seamew пре 1 година
комит
09c6deabda
100 измењених фајлова са 1030 додато и 0 уклоњено
  1. 211 0
      孙浩博/八股/JVM.md
  2. 215 0
      孙浩博/八股/K8S.md
  3. 604 0
      孙浩博/八股/Mysql.md
  4. BIN
      孙浩博/八股/assets/03eacec67cc58ff8d5819d0872ddd41e.png
  5. BIN
      孙浩博/八股/assets/04163db3b7ca4b4c8fbfdf4e7253a98ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  6. BIN
      孙浩博/八股/assets/056c87751b9dd7b56f4264240fe96d00.png
  7. BIN
      孙浩博/八股/assets/061921034534396.png
  8. BIN
      孙浩博/八股/assets/13e4361407ba46979e802eaa654dcf67.png
  9. BIN
      孙浩博/八股/assets/1418b09699fe4614a594a565c55055d5tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  10. BIN
      孙浩博/八股/assets/16c1e0e2878c44dctplv-t2oaga2asx-jj-mark3024000q75.awebp
  11. BIN
      孙浩博/八股/assets/16c1e0e28889eafftplv-t2oaga2asx-jj-mark3024000q75.awebp
  12. BIN
      孙浩博/八股/assets/16c1e0e289a351b2tplv-t2oaga2asx-jj-mark3024000q75.awebp
  13. BIN
      孙浩博/八股/assets/16c1e0e289f9213etplv-t2oaga2asx-jj-mark3024000q75.awebp
  14. BIN
      孙浩博/八股/assets/16c1e0e28aee99a1tplv-t2oaga2asx-jj-mark3024000q75.awebp
  15. BIN
      孙浩博/八股/assets/16c1e0e2ca893b49tplv-t2oaga2asx-jj-mark3024000q75.awebp
  16. BIN
      孙浩博/八股/assets/16c1e0e2d7df4fbftplv-t2oaga2asx-jj-mark3024000q75.awebp
  17. BIN
      孙浩博/八股/assets/16c1e0e2db1c4812tplv-t2oaga2asx-jj-mark3024000q75-16934721993069.awebp
  18. BIN
      孙浩博/八股/assets/16c1e0e2db1c4812tplv-t2oaga2asx-jj-mark3024000q75.awebp
  19. BIN
      孙浩博/八股/assets/16c1e0e2e2a2835etplv-t2oaga2asx-jj-mark3024000q75.awebp
  20. BIN
      孙浩博/八股/assets/16c1e0e2e507aec0tplv-t2oaga2asx-jj-mark3024000q75.awebp
  21. BIN
      孙浩博/八股/assets/16c1e0e3178398fctplv-t2oaga2asx-jj-mark3024000q75.awebp
  22. BIN
      孙浩博/八股/assets/16c1e26a5ecf086etplv-t2oaga2asx-jj-mark3024000q75.awebp
  23. BIN
      孙浩博/八股/assets/1cc7401143e79383ead96582ac11b615.png
  24. BIN
      孙浩博/八股/assets/20201104163915661.png
  25. BIN
      孙浩博/八股/assets/20201104164026393.png
  26. BIN
      孙浩博/八股/assets/20201104164057943.png
  27. BIN
      孙浩博/八股/assets/202308021211012.jpeg
  28. BIN
      孙浩博/八股/assets/202308021212079.jpeg
  29. BIN
      孙浩博/八股/assets/202308021212511.jpeg
  30. BIN
      孙浩博/八股/assets/202308021218967.jpeg
  31. BIN
      孙浩博/八股/assets/2164474-20210716210057908-1704850787.png
  32. BIN
      孙浩博/八股/assets/22c7fe97ce5d3c382b08d83a4d8a5b96.png
  33. BIN
      孙浩博/八股/assets/2306520394.png
  34. BIN
      孙浩博/八股/assets/24-先来先服务.jpg
  35. BIN
      孙浩博/八股/assets/25-最短作业优先算法.jpg
  36. BIN
      孙浩博/八股/assets/2535cfeb9cfb44d4a0a04506f09f7485tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  37. BIN
      孙浩博/八股/assets/26-响应比公式.jpg
  38. BIN
      孙浩博/八股/assets/26f88373d8454682b9e0c1d4fd1611b4-20230309233114856.png
  39. BIN
      孙浩博/八股/assets/27-时间片轮询.jpg
  40. BIN
      孙浩博/八股/assets/28-多级队列.jpg
  41. BIN
      孙浩博/八股/assets/2802786ab4f52c1e248904e5cef33a74.png
  42. BIN
      孙浩博/八股/assets/2ae0ed790c7e7403f215acb2bd82e884.png
  43. BIN
      孙浩博/八股/assets/2b7231b6aabb9a9a2e2390ab3a280b2d-20230309232920063.png
  44. BIN
      孙浩博/八股/assets/2db4831516b9a8b79f833cf0593c1f12.png
  45. BIN
      孙浩博/八股/assets/2e2b95eebf60b6d03f6c1476f4d7c697.png
  46. BIN
      孙浩博/八股/assets/30c2c70721c12f9c140358fbdc5f2282.png
  47. BIN
      孙浩博/八股/assets/316b81a42ea843a192cc2f3578fbdb81tplv-k3u1fbpfcp-zoom-in-crop-mark1512000-16927837871897.awebp
  48. BIN
      孙浩博/八股/assets/316b81a42ea843a192cc2f3578fbdb81tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  49. BIN
      孙浩博/八股/assets/31b9745a2fa94fb693a7ea1257aa5f7ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  50. BIN
      孙浩博/八股/assets/33f858652afc4be6bb1d7b1f1dc33eaatplv-k3u1fbpfcp-zoom-in-crop-mark1512000-169278452952817.awebp
  51. BIN
      孙浩博/八股/assets/33f858652afc4be6bb1d7b1f1dc33eaatplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  52. BIN
      孙浩博/八股/assets/35820959e8cf4376391c427ed7f81495.png
  53. BIN
      孙浩博/八股/assets/3a6cb4e3f27241d3b09b4766bb0b1124.png
  54. BIN
      孙浩博/八股/assets/3层跳表-跨度.drawio.png
  55. BIN
      孙浩博/八股/assets/3层跳表-跨度.png
  56. BIN
      孙浩博/八股/assets/454a8228a6549176ad7e0484fba3c92b.png
  57. BIN
      孙浩博/八股/assets/47e6c8fbc17fd6c89bdfcb5eedaaacff.png
  58. BIN
      孙浩博/八股/assets/4845008abadaa871613873f5ffdcb542.png
  59. BIN
      孙浩博/八股/assets/4d850bfe8d712d3d67ff13e59b919452.png
  60. BIN
      孙浩博/八股/assets/4ef8691d67eb1eb53217099d0a691eb5.png
  61. BIN
      孙浩博/八股/assets/516738c4058cdf9109e40a7812ef4239.png
  62. BIN
      孙浩博/八股/assets/517e2f7939394b3ca35936702a107f07tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  63. BIN
      孙浩博/八股/assets/559260f5ef944cd1a146d07308275b89tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  64. BIN
      孙浩博/八股/assets/5e9e65a4a59b3688fa37cadbd87bb5ac.png
  65. BIN
      孙浩博/八股/assets/60d6b91f49ac4d11bee43f86f33566d6tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  66. BIN
      孙浩博/八股/assets/6a68be69f6b64ad1a8df234d9f0772detplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  67. BIN
      孙浩博/八股/assets/775865f6bd894dfba8d373ee54d79af1.png
  68. BIN
      孙浩博/八股/assets/788acb3c73174c42b603fe67e96c89f5tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  69. BIN
      孙浩博/八股/assets/7d45e677f6c2428d9b9db7022416fe26tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  70. BIN
      孙浩博/八股/assets/80a2bcb823e04e05a10c8f19de2930b9tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  71. BIN
      孙浩博/八股/assets/8febac10b14bed16cb96d1d944cd08da.png
  72. BIN
      孙浩博/八股/assets/955fdfb94c234e32939c76954fd28a56tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  73. BIN
      孙浩博/八股/assets/98987d9417b2bab43087f45fc959d32a-20230309232253633.png
  74. BIN
      孙浩博/八股/assets/9ebde5c11ad69447314c216acf188fc8.png
  75. BIN
      孙浩博/八股/assets/a3e7d217ecb825e94bdc577a467eb29d.png
  76. BIN
      孙浩博/八股/assets/a6e0e622b7384ac78f733e471b280c27tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  77. BIN
      孙浩博/八股/assets/a851f56a384b4a0f9da76644d645ae1ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  78. BIN
      孙浩博/八股/assets/arch-x-reduce-2.png
  79. BIN
      孙浩博/八股/assets/arch-x-reduce-3.png
  80. BIN
      孙浩博/八股/assets/arch-x-reduce-31-169347359783720.png
  81. BIN
      孙浩博/八股/assets/b52e004bd4654cb1b51cdb409182156ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  82. BIN
      孙浩博/八股/assets/b5681d905102439aa1a40412100da566.png
  83. BIN
      孙浩博/八股/assets/c55029a32a6448d9aa35bb3de6efcecatplv-k3u1fbpfcp-zoom-in-crop-mark4536000.awebp
  84. BIN
      孙浩博/八股/assets/c7787bc99996429381a1049580f6c24atplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  85. BIN
      孙浩博/八股/assets/c8054fbec1b14607b2759ea0d1ddc2f4tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  86. BIN
      孙浩博/八股/assets/cc208c2931b4e889d1a58cb655537767.png
  87. BIN
      孙浩博/八股/assets/cdc14698f629c74bf5a239cc8a611aeb.png
  88. BIN
      孙浩博/八股/assets/d4ce0c7fdf3b4039a0e4b0b200af731atplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  89. BIN
      孙浩博/八股/assets/d528bae6fcec2357ba2eb8f324ad9fd5.png
  90. BIN
      孙浩博/八股/assets/d565806a3b7c4735859befbcdad5a105.png
  91. BIN
      孙浩博/八股/assets/d9f2d1f2d3674a50900eda504ecaa326tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  92. BIN
      孙浩博/八股/assets/db568766644a4d10b8a91cdd2f8a4070.png
  93. BIN
      孙浩博/八股/assets/dba2bc3af0938d2c087f85acc191fd3f.png
  94. BIN
      孙浩博/八股/assets/dbb57b8d6071d011d05eeadd93269e13.png
  95. BIN
      孙浩博/八股/assets/e081b470870daeb763062bb873a4477e.png
  96. BIN
      孙浩博/八股/assets/e94e504adc5a75a2d7f562dc44166511.png
  97. BIN
      孙浩博/八股/assets/ea4f7e86baf2435af3999e5cd38b6a26.png
  98. BIN
      孙浩博/八股/assets/ec5c8e28d3ea308c6db2ac991a12ea80.png
  99. BIN
      孙浩博/八股/assets/f0d9d314c75c4bd989dadf044ecd6307tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  100. BIN
      孙浩博/八股/assets/f109a45fe4904726b11fd36422f4abactplv-k3u1fbpfcp-zoom-in-crop-mark4536000.awebp

+ 211 - 0
孙浩博/八股/JVM.md

@@ -0,0 +1,211 @@
+## 什么时候会触发full gc?
+
+1. 当系统主动调用System.gc()函数的时候,只是建议虚拟机执行 Full GC,但是虚拟机不一定真正去执行。不建议使用这种方式,而是让虚拟机管理内存。
+2. 老年代空间不足,当老年代空间不足会触发full gc
+3. JDK1.7之前永久代空间满会触发full gc
+4. 空间分配担保失败在发生**Minor GC**之前,虚拟机会检查**老年代最大可用的连续空间**是否**大于新生代所有对象的总空间**,如果大于,则此次**Minor GC是安全的**。如果小于,则虚拟机会查看**HandlePromotionFailure**设置值是否允许担保失败。如果HandlePromotionFailure=true,那么会继续检查老年代最大可用连续空间是否大于**历次晋升到老年代的对象的平均大小**,如果大于,则尝试进行一次Minor GC,但这次Minor GC依然是有风险的;如果小于或者HandlePromotionFailure=false,则改为进行一次Full GC。
+5. 未指定老年代和新生代大小,堆伸缩时会产生fullgc,所以一定要配置-Xmx、-Xms
+
+## 什么时候会触发Minor Gc?
+
+Minor GC 通常在新生代中的 Eden 区域满时,或者 Survivor 区域中的对象年龄达到一定阈值时触发。下面分别介绍这两种情况:
+
+1. Eden 区域满时:当 Java 应用程序创建新对象时,这些对象会被分配到 Eden 区域中。当 Eden 区域满时,无法再分配出任何连续的内存空间,此时就需要进行 Minor GC 了。Minor GC 会将 Eden 区域中不再使用的对象清理掉,同时将存活的对象移到 Survivor 区域。
+2. Survivor 区域中的对象年龄达到一定阈值:当对象在 Survivor 区域中经历一定次数的垃圾回收后,其年龄就会增加。当对象年龄达到一定阈值时,就会被移到老年代中去。这个阈值的默认值为 15,也可以通过 JVM 参数 -XX:MaxTenuringThreshold 来进行设置。当 Survivor 区域中的对象年龄达到一定阈值时,也会触发 Minor GC。
+
+总的来说,Minor GC 是针对新生代中的垃圾回收,它通常在 Eden 区域满时或者 Survivor 区域中对象年龄达到一定阈值时被触发。Minor GC 的目的是清除新生代中不再使用的对象,同时将存活的对象移到 Survior 区域和老年代中。
+
+## Minor Gc 和 Full GC有什么不同呢?
+
+- **Major GC 是清理老年代。**
+- **Full GC 是清理整个堆空间—包括年轻代和老年代。**
+
+## 频繁发生GC如何优化
+
+`jstat -gcutil 5280 1000` 命令是用于监视 Java 虚拟机的垃圾回收统计信息的命令。这个命令通常在命令行中执行,用于实时监测 Java 应用程序的内存管理和垃圾回收情况。
+
+解释一下命令的各个部分:
+
+- `jstat`: Java 虚拟机统计信息工具,用于监测虚拟机状态和性能数据。
+- `-gcutil`: 表示查询垃圾回收的统计信息,包括各个垃圾回收器的使用情况。
+- `5280`: 进程的进程 ID 或虚拟机标识符(JVM ID),用于指定要监控的 Java 虚拟机实例。这个值需要根据实际情况进行替换。
+- `1000`: 表示每隔 1000 毫秒(1秒)收集一次统计信息并输出。
+
+### 可能原因
+
+* 内存泄漏(代码有问题,对象引用没及时释放,导致对象不能及时回收)。
+* 死循环。在死循环中,对象不断被创建,但无法被正常释放,最终导致堆内存耗尽,触发 Full GC 进行垃圾回收。
+* 大对象。 尤其是大对象,80%以上的情况就是他。 那么大对象从哪里来的呢?
+* 数据库(包括MySQL和MongoDB等NoSQL数据库),结果集太大。
+* 第三方接口传输的大对象。
+* 消息队列,消息太大。
+
+## JVM调优
+
+对应的参数列表
+
+```shell
+-XX:+PrintGC 输出GC日志
+-XX:+PrintGCDetails 输出GC的详细日志
+-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
+-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
+-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
+-Xloggc:../logs/gc.log 日志文件的输出路径
+```
+
+当元空间出现内存碎片化时,我们会着重关注是不是创建了大量的类加载器。
+
+通过进一步分析,发现是由于反射导致创建大量 DelegatingClassLoader。其核心原理如下:
+
+在 JVM 上,最初是通过 JNI 调用来实现方法的反射调用,当 JVM 注意到通过反射经常访问某个方法时,它将生成字节码来执行相同的操作,称为膨胀(inflation)机制。如果使用字节码的方式,则会为该方法生成一个 DelegatingClassLoader,如果存在大量方法经常反射调用,则会导致创建大量 DelegatingClassLoader。
+
+## JVM调优
+
+-Xmx –Xms:指定 java 堆最大值(默认值是物理内存的 1/4(<1GB))和初始 java 堆最小值(默认值是物理内存的 1/64(<1GB))
+
+开发过程中,通常会将 -Xms 与 -Xmx 两个参数配置成相同的值,其目的是为了能够在 java 垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源。
+
+
+
+创建大量MAP导致内存暴涨,优化kafka消息
+
+## CMS垃圾收集器
+
+CMS(标记并发清除垃圾收集器),对比以前的jvm垃圾收集器,最大区别在于并发,当GC线程工作的时候,用户线程不会完全停止,会与GC线程并发执行
+
+CMS主要目的为了避免老年代GC出现长时间的卡顿,主要步骤可以分为以下4点
+
+* **初始标记:** 暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快 ;
+* **并发标记:** 同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新GC ROOT,所以 GC 线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方
+* **重新标记:** 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段用户线程会被暂停,但是停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短
+* **并发清除:** 开启用户线程,同时 GC 线程开始对未标记的区域做清扫。
+
+CMS垃圾收集器的缺点
+
+* 产生大量空间碎片:因为老年代是标记-清除算法,所以会产生大量的空间碎片
+* 对CPU资源敏感:应该它与用户线程并行, 所以会导致系统资源被占用
+* 内存需要预留:CMS垃圾收集器可以一边回收垃圾,一边处理用户线程,那需要在这个过程中保证有充足的内存空间供用户使用。如果CMS运行过程中预留的空间不够用,会报错
+
+## G1垃圾收集器
+
+G1是一款面向服务器的垃圾收集器,主要针对配备多核CPU及大容量内存的机器,可以预测垃圾收集时间,还兼具高吞吐量的性能特征。
+
+G1垃圾收集器将Java堆分为多个大小相等的Region,每个Region都可以是新生代、老年代,或者未标注的区域,G1垃圾收集器还有一个Humongous区域,对于堆中的大对象,会默认分配到此区域,当然G1垃圾收集器也会将H区作为老年代的一部分。
+
+G1垃圾收集器的垃圾回收过程:
+
+* **初始标记**:标记从根节点直接可达的对象。这个阶段是STW的,。所以说用户线程会被暂停
+* **并发标记**:在整个堆中进行并发标记。即和用户进程并行执行。在并发阶段,如果发现区域对象都是垃圾,那么这个区域会被立即回收。同时在这个过程中会计算每个区域的对象活性
+* **再次标记**:由于应用程序持续进行,需要修正上一次的标记结果。这个阶段也是STW的
+* **筛选回收**:首先对各个 Region 中的回收价值和成本进行排序(**G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region**),根据用户所期望的 GC 停顿时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。
+
+## CMS和G1的区别
+
+* STW的时间:CMS是以最小STW时间为目标,而G1主要是建立可预测的停顿时间模型,可以控制STW时间
+* 适用范围区别:CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用,G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用
+* 垃圾碎片:CMS会产生大量的空间碎片,而G1由于是Region管理,降低了内存碎片的可能性
+
+## 垃圾回收算法有哪些?
+
+垃圾回收算法主要有三种:
+
+* 标记清除算法:先标记,后清楚。会产生大量的空间碎片
+* 标记复制算法:复制存活的对象。空间利用率不高
+* 标记整理算法:标记清除算法的改进,清楚之后对碎片进行处理
+
+## 如何判断对象是否为垃圾
+
+主要有两种方法可以判断:
+
+* 引用计数法:无法解决相互引用的问题
+* 可达性分析:作为GC ROOT
+  * 虚拟机栈中引用的对象
+  * 本地方法栈中引用的对象
+  * 方法区中类静态属性引用的对象
+  * 方法区中常量引用的对象
+  * 所有被同步锁持有的对象
+
+## jvm内存区域
+
+jvm内存区域大体上可以分为线程私有和线程共有两大部分
+
+线程私有主要包括
+
+* 程序计数器:记录当前线程所执行的字节码的位置,为了线程切换后可以恢复到正确的位置,程序计数器被设计为私有的
+* Java 虚拟机栈:java方法的调用都是通过java虚拟机栈来实现的。方法调用就压栈,方法结束调用就弹出栈。栈由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法返回地址等。
+* 本地方法栈:**虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。** 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。
+
+线程共有部分主要包括:
+
+* 堆:JDK1.7之前,java堆主要分为一下三部分,新生代,老年代,永久代
+* 方法区:方法区会存储已被虚拟机加载的类信息、字段信息、方法信息、常量、静态变量。其中常量被存储在运行时常量池中,string被存储在字符串常量池中,字符串常量池在jdk1.8之后就被移动到堆上
+* 直接内存:直接内存是一种特殊的内存缓冲区,直接在本地内存上面分配,直接内存的分配不会受到 Java 堆的限制
+
+## 对象创建的过程
+
+1. 类加载检查
+2. 分配内存
+
+指针碰撞 : 
+
+- 适用场合 :堆内存规整(即没有内存碎片)的情况下。
+- 原理 :用过的内存全部整合到一边,没有用过的内存放在另一边,中间有一个分界指针,只需要向着没用过的内存方向将该指针移动对象内存大小位置即可。
+- 使用该分配方式的 GC 收集器:Serial, ParNew
+
+空闲列表 : 
+
+- 适用场合 : 堆内存不规整的情况下。
+- 原理 :虚拟机会维护一个列表,该列表中会记录哪些内存块是可用的,在分配的时候,找一块儿足够大的内存块儿来划分给对象实例,最后更新列表记录。
+- 使用该分配方式的 GC 收集器:CMS
+
+3. 初始化零值
+
+4. 设置对象头
+
+5. 执行init方法
+
+## 类加载过程
+
+1. 加载:通过classloader加载类
+2. 验证:JVM虚拟机验证字节码文件
+3. 准备:为类变量分配内存和初始化
+4. 解析:将符号引用替换为直接引用
+5. 初始化:调用`<clinit> ()`真正初始化类
+
+## 强引用,弱引用,软引用,虚引用的区别
+
+强引用:当内存不足时,JVM 开始进行 GC(垃圾回收),对于强引用对象,就算是出现了OOM 也不会对该对象进行回收,死都不会收。
+软引用:当系统内存充足的时候,不会被回收;当系统内存不足时,它会被回收,软引用通常用在对内存敏感的程序中,比如高速缓存就用到软引用,内存够用时就保留,不够时就回收。
+弱引用:弱引用需要用到 java.lang.ref.WeakReference 类来实现,它比软引用的生存周期更短。对于只有弱引用的对象来说,只要有垃圾回收,不管 JVM 的内存空间够不够用,都会回收该对象占用的内存空间。
+虚引用:虚引用需要 java.lang.ref.Phantomreference 类来实现。顾名思义,虚引用就是形同虚设。与其它几种引用不同,虚引用并不会决定对象的生命周期。
+
+## 强引用对象会被GC清除吗?
+
+不会被清除,因为强引用对象本身就是GC ROOT,除非该方法已经从栈中弹出,或者不在使用才会被清除
+
+## 新生代老年代比例
+
+![1](assets/061921034534396.png)
+
+
+
+## 内存泄漏和内存溢出的区别
+
+在Java中,内存泄漏(Memory Leak)和内存溢出(Memory Overflow)是两个不同的概念,它们有一些区别。
+
+1. 内存泄漏(Memory Leak): 内存泄漏指的是在程序运行过程中,由于错误的内存管理导致无法再被使用的对象仍然占据着内存空间,而这些占用的内存无法被释放。这意味着系统的可用内存逐渐减少,直到最终导致内存耗尽。常见的内存泄漏场景包括:
+   - 未正确释放动态分配的内存:如果程序在分配了内存后没有及时释放,这些内存就会一直占据系统资源。
+   - 对象引用仍存在但不再需要:如果某个对象的引用仍然存在,即使该对象不再需要,垃圾回收器也无法回收该对象所占用的内存。
+2. 内存溢出(Memory Overflow): 内存溢出指的是程序在申请内存时,无法获得足够的内存空间以满足其需求,导致无法继续执行程序或者出现异常。当程序需要分配更多内存而可用内存不足时,就会发生内存溢出。常见的内存溢出场景包括:
+   - 堆内存溢出:当创建过多的对象并且无法被垃圾回收时,堆内存可能会耗尽。这通常是由于程序中存在内存泄漏或者申请了过大的对象导致的。
+   - 栈内存溢出:当递归调用层级过深、方法调用过多或者栈帧过大时,栈内存可能会耗尽。每个方法调用都会在栈上创建一个栈帧,如果栈帧数量超过了栈的容量,就会导致栈内存溢出。
+
+区别:
+
+- 内存泄漏是指无法释放已经分配的内存,导致内存持续占用和耗尽;而内存溢出则是指无法获得足够的内存空间来满足需求,导致程序无法执行或者出现异常。
+- 内存泄漏通常是逐渐发生的,随着时间的推移导致内存占用不断增加;而内存溢出通常是在程序执行过程中突然发生的,因为需要的内存超过了可用内存。
+- 内存泄漏是程序中的错误行为,通常是由于忘记释放资源或者引用未及时清理等原因导致的;而内存溢出可能是因为程序设计问题,如递归调用或者对象太大等。
+
+## 内存泄漏
+
+hbase配置类需要成为static

+ 215 - 0
孙浩博/八股/K8S.md

@@ -0,0 +1,215 @@
+## 什么是K8S
+
+Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、支持和工具广泛可用。
+
+![image-20230905160248241](assets/image-20230905160248241.png)
+
+## pod
+
+容器的本质是进程,Kubernetes就是操作系统。
+
+在一个OS当中,进程并非独自运行的,而是以进程组的方式,有原则的组织在一起。
+
+Kubernetes当中,将“进程组”的概念映射到了容器技术中。
+
+为什么需要这个“组”的概念??
+
+应用之间往往具有密切的协作关系,类似于“进程和进程组”。
+
+关于如何妥善处理成组调度的问题?
+
+* Mesos有一个资源囤积(resource hoarding)机制,当所有设置了Affinity约束的任务都到达之后,才开始对他们进行统一调度
+* Google Omega论文,提出乐观调度处理冲突的方法,即:先不管这些冲突,而是通过回滚机制在出现冲突后解决问题
+
+Kubernetes中得到了妥善解决,调度器**统一按照Pod而非容器的资源需求进行计算**。
+
+但是如果仅仅这样,那么Kubernetes可以在调度器层面解决 容器应用之间的紧密关系,而不一定要把Pod设置为最基本单位?
+
+引出Pod在Kubernetes项目中更加重要的意义,即:**容器设计模式**。
+
+* **Pod只是一个逻辑概念,Kubernetes真正处理的,还是宿主机OS上的Namespace和Cgroups,物理上并没有存在一个所谓的Pod的边界或者隔离环境。**
+
+* Pod,是一组共享了某些资源的容器。
+
+* **Pod当中所有的容器,共享的是同一个Network Namespace,并且可以声明共享同一个Volume。**
+
+**在Pod当中,容器是对等的关系**,而如果是用简单用docker run共享,则必然会有容器先启动,进而产生拓扑关系。
+
+### **Infra容器**(新版本叫Init容器)
+
+为了实现这样的对等关系,Pod的实现需要一个中间容器,叫做`Infra`容器。
+
+**它永远是首先被创建的容器,其他用户定义的容器通过Join Network Namespace方式,与Infra关联起来。**
+
+Infra容器一定要占据非常少的资源,所以它使用一个非常特殊的image,叫**`k8s.gcr.io/pause`**,(称为**pause 镜像**)它是用汇编语言编写、永远处于暂停状态,解压后也只有100~200KB左右。
+
+Pod 的生命周期和 Infra 容器一致,而与其中的用户定义容器无关。
+
+![image-20230905161245730](assets/image-20230905161245730.png)
+
+要为Kubernetes开发一个网络插件时,应该**重点考虑如何配置这个Pod的Network Namespace,而不是每一个用户容器如何使用你的网络配置**。
+
+对于**共享Volume**而言,只需要**把Volume的定义设计在Pod层级**即可:**一个 Volume 对应的宿主机目录对于 Pod 来说就只有一个**,Pod 里的容器只要声明挂载这个 Volume,就一定可以共享这个 Volume 对应的宿主机目录。
+
+## pod配置文件config
+
+**特殊的Projected Volume**
+
+它们存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。这些特殊 Volume 的作用,**是为容器提供预先定义好的数据。**
+
+一共支持四种Volume:
+
+1. Secret: 保密数据
+
+把 Pod 想要访问的加密数据,存放到 Etcd 中。然后,就可以通过在 Pod 的容器里挂载 Volume 的方式,访问到这些 Secret 里保存的信息。
+
+经典场景:存放数据库的Credential信息:
+
+2. ConfigMap: 配置文件
+
+ConfigMap 保存的是不需要加密的、应用所需的配置信息,其他用法与Secret相同。
+
+用ConfigMap来保存一个java应用的配置文件ui.properties:
+
+3. Downward API:  Pod元数据
+
+让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息。
+
+4. ServiceAccountToken: 服务账户,通过验证
+
+> **疑问:现在有了一个 Pod,我能不能在这个 Pod 里安装一个 Kubernetes 的 Client,这样就可以从容器里直接访问并且操作这个 Kubernetes 的 API 了呢?**
+>
+> **答案是:可以,但是需要解决API Server的授权问题。**
+
+`Service Account` 对象的作用,就是 Kubernetes 系统内置的一种“服务账户”,它是 **Kubernetes 进行权限分配的对象。**
+
+ Service Account 的授权信息和文件,实际上**保存在它所绑定的一个特殊的 Secret 对象里的**。这个特殊的 Secret 对象,就叫作**ServiceAccountToken**。
+
+**任何运行在 Kubernetes 集群上的应用,都必须使用这个 ServiceAccountToken 里保存的授权信息,也就是 Token,才可以合法地访问 API Server**。
+
+Kubernetes为了方便使用,为用户提供一个默认的服务账户(default Service Account),任何一个运行在 Kubernetes 里的 Pod,都可以直接使用这个默认的 Service Account,而无需显示地声明挂载它。
+
+## Replicaset
+
+`ReplicaSet`是kubernetes中的一种副本控制器,简称`rs`,主要作用是控制由其管理的pod,使pod副本的数量始终维持在预设的个数。它的主要作用就是保证一定数量的Pod能够在集群中正常运行,它会持续监听这些Pod的运行状态,在Pod发生故障时重启pod,pod数量减少时重新运行新的 Pod副本。**官方推荐不要直接使用ReplicaSet,用Deployments取而代之**,Deployments是比ReplicaSet更高级的概念,它会管理ReplicaSet并提供很多其它有用的特性,最重要的是Deployments支持声明式更新,声明式更新的好处是不会丢失历史变更。所以Deployment控制器不直接管理Pod对象,而是由 Deployment 管理ReplicaSet,再由ReplicaSet负责管理Pod对象。
+
+
+
+Replicaset核心作用在于用户创建指定数量的pod副本,并确保pod副本一直处于满足用户期望的数量, 起到多退少补的作用,并且还具有自动扩容缩容等制。
+Replicaset控制器主要由三个部分组成:
+1、**用户期望的pod副本数**:用来定义由这个控制器管控的pod副本有几个
+2、**标签选择器**:选定哪些pod是自己管理的,如果通过标签选择器选到的pod副本数量少于我们指定的数量,需要用到下面的组件
+3、**pod资源模板**:如果集群中现存的pod数量不够我们定义的副本中期望的数量怎么办,需要新建pod,这就需要pod模板,新建的pod是基于模板来创建的。
+
+## Deployment
+
+为了更好地解决服务编排的问题,k8s在V1.2版本开始,引入了deployment控制器,值得一提的是,这种控制器并不直接管理pod,
+
+而是通过管理replicaset来间接管理pod,即:deployment管理replicaset,replicaset管理pod。所以deployment比replicaset的功能更强大。
+
+![image-20230905164914619](assets/image-20230905164914619.png)
+
+deployment的主要功能有下面几个:
+
+- 支持replicaset的所有功能
+- 支持发布的停止、继续
+- 支持版本的滚动更新和版本回退
+
+## StatefulSet
+
+作为一个后端工程师,因为负责的大部分项目都是`Web`服务这类的“无状态应用”,在平时工作中接触到的最常用的`Kubernetes`控制器是`Deployment`,但是`Deployment`只适合于编排“无状态应用”,它会假设一个应用的所有 `Pod`是完全一样的,互相之间也没有顺序依赖,也无所谓运行在哪台宿主机上。正因为每个`Pod`都一样,在需要的时候可以水平扩/缩,增加和删除`Pod`。
+
+但是并不是所有应用都是无状态的,尤其是每个实例之间有主从关系的应用和数据存储类应用,针对这类应用使用`Deployment`控制器无法实现正确调度,所以`Kubernetes`里采用了另外一个控制器`StatefulSet`负责调度有状态应用的`Pod`,保持应用的当前状态始终等于应用定义的所需状态。
+
+## node affinity
+
+pod绑定节点最简单的方法是使用 nodeSelector,但它比较简单粗暴,使用起来不能灵活调度,这个在后续版本中也会慢慢过时,所以我们一般用 nodeAffinity来实现这些需求。
+
+Node Affinity
+ Affinity 翻译成中文是“亲和性”,它对应的是 Anti-Affinity,我们翻译成“互斥”。这两个词比较形象,可以把 pod 选择 node 的过程类比成磁铁的吸引和互斥,不同的是除了简单的正负极之外,pod 和 node 的吸引和互斥是可以灵活配置的。
+
+Affinity的优点:
+
+匹配有更多的逻辑组合,不只是字符串的完全相等
+ 调度分成软策略(soft)和硬策略(hard),在软策略下,如果没有满足调度条件的节点,pod会忽略这条规则,继续完成调度。
+ 目前主要的node affinity:
+
+requiredDuringSchedulingIgnoredDuringExecution
+ 表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中IgnoreDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,pod也会继续运行。
+
+requiredDuringSchedulingRequiredDuringExecution
+ 表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中RequiredDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,则重新选择符合要求的节点。
+
+preferredDuringSchedulingIgnoredDuringExecution
+ 表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。
+
+preferredDuringSchedulingRequiredDuringExecution
+ 表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。其中RequiredDuringExecution表示如果后面节点标签发生了变化,满足了条件,则重新调度到满足条件的节点。
+
+## Toleration
+
+节点亲和性 是 Pod的一种属性,它使 Pod 被吸引到一类特定的节点(这可能出于一种偏好,也可能是硬性要求)。 **污点(Taint)** 则相反——它使节点能够排斥一类特定的 Pod。
+
+**容忍度(Toleration)** 是应用于 Pod 上的。容忍度允许调度器调度带有对应污点的 Pod。 容忍度允许调度但并不保证调度:作为其功能的一部分, 调度器也会评估其他参数。
+
+污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod, 是不会被该节点接受的。
+
+## service
+
+Service是一种抽象的对象,它定义了一组Pod的逻辑集合和一个用于访问它们的策略,一个Serivce下面包含的Pod集合一般是由**Label Selector**来决定的。假如我们后端运行了3个副本,这些副本都是可以替代的,因为前端并不关心它们使用的是哪一个后端服务。尽管由于各种原因后端的Pod集合会发生变化,但是前端却不需要知道这些变化,也不需要自己用一个列表来记录这些后端的服务,Service的这种抽象就可以帮我们达到这种解耦的目的。
+
+
+
+> Node IP:Node节点的IP地址
+>  Pod IP:Pod的IP地址
+>  Cluster IP:Service的IP地址
+
+首先,Node IP是Kubernetes集群中节点的物理网卡IP地址(一般为内网),所有属于这个网络的服务器之间都可以直接通信,所以Kubernetes集群外要想访问Kubernetes集群内部的某个节点或者服务,肯定得通过Node IP进行通信(这个时候一般是通过外网IP了)
+
+然后Pod IP是每个Pod的IP地址,它是Docker Engine根据docker0网桥的IP地址段进行分配的(我们这里使用的是flannel这种网络插件保证所有节点的Pod IP不会冲突)
+
+最后Cluster IP是一个虚拟的IP,仅仅作用于Kubernetes Service这个对象,由Kubernetes自己来进行管理和分配地址,当然我们也**无法ping这个地址**,他没有一个真正的实体对象来响应,他只能结合Service Port来组成一个可以通信的服务。
+
+![在这里插入图片描述](assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxMTg3NTE1,size_16,color_FFFFFF,t_70.png)
+
+## Ingress
+
+ingress翻译过来是入口的意思,k8s希望ingress是整个集群流量的入口,引入ingress后整个请求如下图所示
+
+![image.png](assets/c8054fbec1b14607b2759ea0d1ddc2f4tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp)
+
+### 为什么需要Ingress资源
+
+由于K8S集群拥有强大的副本控制能力,Pod随时可能从一个节点上被驱逐到另一个节点上,或者直接销毁再来一个新的。
+
+然而伴随着Pod的销毁和重生,Pod的IP等信息不断地在改变,此时使用K8S提供的Service机制可以解决这一问题,Service通过标签选定指定的Pod作为后端服务,并监听这些Pod的变化。
+
+在对外暴露服务时,使用Service的NodePort是一个方法,但还会有以下几个问题
+
+### 问题1 - 如何管理端口
+
+当需要对外暴露的服务量比较多的时候,端口管理的问题便会暴露出来。并且service只支持4层代理,也就是只能根据ip+端口
+
+此时的一个处理方案是使用一个代理服务(例如Nginx)根据请求信息将请求转发到不同的服务上去。
+
+### 问题2 - 如何管理转发配置
+
+每当有新服务加入,都需要对该服务的配置进行修改、升级,在服务数量逐渐变多后,该配置项目会变得越来越大,手工修改的风险也会逐渐增高。
+
+那么需要一个工具来简化这一过程,希望可以通过简单的配置动态生成代理中复杂的配置,最好还可以顺手重新加载配置文件。
+
+K8S刚好也提供了此类型资源。
+
+## 健康检查
+
+健康检查(health check)是用于检测应用实例是否正常工作,对应用状态的监控,保障业务高可用的一种机制。
+
+k8s健康检测主要分为以下三种:
+
+- 存活性探测(Liveness probes) :主要是探测应用是否还活着。如果检测到应用没有存活就杀掉当前pod并重启。
+- 就绪性探测(Readiness probes):只要是探测应用是否准备好接受请求访问,如果检测应用准备好了,就把请求流量放进来;反之,则把应用节点从注册中心拿掉。
+- 启动探测(Startup Probes):对于旧应用需要更长的启动时间,这时候既不想重启应用也不想让请求访问进来,可以设置启动探测给足够的启动时间保证应用启动成功。
+
+![image-20230905203232434](assets/image-20230905203232434.png)
+
+> **二者不能相互替代,根据实际情况,配合使用。只配置了readiness是无法触发容器重启的;只配置了liveness,可能应用还没准备好,导致请求失败,status是running,Ready是0/1。**

+ 604 - 0
孙浩博/八股/Mysql.md

@@ -0,0 +1,604 @@
+## mysql内连接,外连接,左连接,右连接
+
+- left join(左连接):返回包括左表中的所有记录和右表中连接字段相等的记录。
+- right join(右连接):返回包括右表中的所有记录和左表中连接字段相等的记录。
+- inner join(内连接):只返回两个表中连接字段相等的行。
+- full join (全外连接):返回左右表中所有的记录和左右表中连接字段相等的记录。在mysql中不存在全连接,但是他可以等同于左连接合并右连接
+
+## mysql如何提升查询性能
+
+1. 合理使用索引:索引是提升查询性能的重要手段,可以通过在常用查询字段上创建索引来加速查询速度。需要注意的是,索引的创建和使用需要谨慎,过多或不合理的索引可能会降低性能。在使用索引时,可以通过 EXPLAIN 分析查询计划,避免全表扫描和不必要的索引使用。
+2. 优化 SQL 语句:优化 SQL 语句可以通过多种方式实现,例如避免使用通配符查询,优化复杂查询语句,避免不必要的连接查询和子查询,合理使用聚合函数和 GROUP BY 子句等。可以通过使用数据库性能分析工具(如 MySQL 自带的慢查询日志)来定位慢查询,并对其进行优化。
+3. 缓存和缓冲技术:通过使用缓存和缓冲技术可以减轻数据库的负载,提高查询性能。可以使用数据库自带的查询缓存功能,或者使用外部缓存技术如 Redis、Memcached 等进行数据缓存,减少对数据库的频繁查询。
+4. 合理配置数据库参数:MySQL 有丰富的配置参数可以进行调优,例如调整缓冲池大小、设置合理的连接数、开启合适的日志等,可以根据实际需求和硬件资源来配置数据库参数,以达到最佳性能。
+6. 可以考虑使用分库分表技术
+
+## mysql底层数据结构
+
+1. B+ 树索引:MySQL 使用 B+ 树作为默认的索引结构。索引数据最好能按顺序排列,这样可以使用「二分查找法」高效定位数据,而且还要支持排序操作。这就天然要求我们使用平衡二叉树作为默认的数据结构,而平衡二叉树本身是一个B树,每个节点只能有两个子节点那么当节点个数越多的时候,树的高度也会相应变高,这样就会增加磁盘的 I/O 次数,从而影响数据查询的效率。B 树的每一个节点最多可以包括 M 个子节点,M 称为 B 树的阶,所以 B 树就是一个多叉树。B+ 树就是对 B 树做了一个升级,他和B树相比有如下几个优点
+   1. B+ 树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的 B 树查询效率更高,因为IO次数更少
+   2. B+ 树在删除根节点的时候,由于存在冗余的节点,所以不会发生复杂的树的变形,B 树则不同,B 树没有冗余节点,删除节点的时候非常复杂
+   3. B+ 树所有叶子节点间还有一个链表进行连接,这种设计对范围查找非常有帮助
+2. 数据文件:MySQL 数据库将数据存储在磁盘上的数据文件中,底层由表空间构成,表空间由段(segment)、区(extent)、页(page)、行(row)组成
+
+![image-20230524111644588](assets/image-20230524111644588.png)
+
+为什么分区?
+
+页要连续,顺序IO读写快,每个区都维护一个链表,代表空闲区的指针
+
+- `FREE`链表:同一个段中,所有页都是空闲的区对应的`XDES Entry`结构会被加入到这个链表。注意和直属于表空间的`FREE`链表区别开了,此处的`FREE`链表是附属于某个段的。
+- `NOT_FULL`链表:同一个段中,仍有空闲空间的区对应的`XDES Entry`结构会被加入到这个链表。
+- `FULL`链表:同一个段中,已经没有空闲空间的区对应的`XDES Entry`结构会被加入到这个链表。
+
+为什么分段?
+
+区分叶子节点和非叶子节点
+
+页?
+
+稀疏索引,分组
+
+3. InnoDB 存储引擎:InnoDB 是 MySQL 的一种常用存储引擎,它使用了多版本并发控制(MVCC)和行级锁来实现高并发性和事务支持。InnoDB 存储引擎的核心数据结构包括页(page)、记录(record)、索引(index)和事务日志(transaction log)等。
+
+## nysql低层文件结构
+
+- db.opt,用来存储当前数据库的默认字符集和字符校验规则。
+- t_order.frm ,t_order 的**表结构**会保存在这个文件。在 MySQL 中建立一张表都会生成一个.frm 文件,该文件是用来保存每个表的元数据信息的,主要包含表结构定义。
+- t_order.ibd,t_order 的**表数据**会保存在这个文件。表数据既可以存在共享表空间文件(文件名:ibdata1)里,也可以存放在独占表空间文件(文件名:表名字.ibd)。这个行为是由参数 innodb_file_per_table 控制的,若设置了参数 innodb_file_per_table 为 1,则会将存储的数据、索引等信息单独存储在一个独占表空间,从 MySQL 5.6.6 版本开始,它的默认值就是 1 了,因此从这个版本之后, MySQL 中每一张表的数据都存放在一个独立的 .ibd 文件。
+
+## 联合索引定义要注意哪些点
+
+在 MySQL 中定义联合索引时,需要注意以下几点:
+
+1. 列顺序:联合索引中的列顺序非常重要,它会影响索引的效果。通常情况下,应该将被频繁用于查询的列放在联合索引的前面,这样可以使索引在查询时更加有效。例如,如果查询中经常同时使用列 A 和列 B 进行查询,那么联合索引应该按照 (A, B) 的顺序定义,而不是 (B, A)。
+
+2. 列选择:不要将过多的列包含在联合索引中,因为索引的大小对数据库性能有影响。过大的索引可能会导致磁盘 I/O 操作增加,并且会占用额外的存储空间,导致性能下降
+
+   * 索引选择:不是所有的列都适合联合索引。联合索引在使用时会按照索引列的顺序进行匹配,因此只有查询中包含了索引的前缀列时,索引才能被充分利用。因此,应该选择那些在查询中经常一起使用的列进行联合索引定义。
+
+   * 更新性能:联合索引在更新操作时可能会导致性能下降。因为联合索引涉及多个列,更新其中的一个列可能需要更新整个索引。因此,在定义联合索引时应该考虑更新性能的影响,避免频繁的更新操作导致性能下降。
+
+## 数据库ACID
+
+- **原子性(Atomicity)**:一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,而且事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样,就好比买一件商品,购买成功时,则给商家付了钱,商品到手;购买失败时,则商品在商家手中,消费者的钱也没花出去。
+- **一致性(Consistency)**:是指事务操作前和操作后,数据满足完整性约束,数据库保持一致性状态。比如,用户 A 和用户 B 在银行分别有 800 元和 600 元,总共 1400 元,用户 A 给用户 B 转账 200 元,分为两个步骤,从 A 的账户扣除 200 元和对 B 的账户增加 200 元。一致性就是要求上述步骤操作后,最后的结果是用户 A 还有 600 元,用户 B 有 800 元,总共 1400 元,而不会出现用户 A 扣除了 200 元,但用户 B 未增加的情况(该情况,用户 A 和 B 均为 600 元,总共 1200 元)。
+- **隔离性(Isolation)**:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致,因为多个事务同时使用相同的数据时,不会相互干扰,每个事务都有一个完整的数据空间,对其他并发事务是隔离的。也就是说,消费者购买商品这个事务,是不影响其他消费者购买的。
+- **持久性(Durability)**:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
+
+InnoDB 引擎通过什么技术来保证事务的这四个特性的呢?
+
+- 持久性是通过 redo log (重做日志)来保证的;
+- 原子性是通过 undo log(回滚日志) 来保证的;
+- 隔离性是通过 MVCC(多版本并发控制) 或锁机制来保证的;
+- 一致性则是通过持久性+原子性+隔离性来保证;
+
+## 数据库隔离级别
+
+数据库隔离级别是指在多用户并发访问数据库时,数据库管理系统 (DBMS) 为了保护数据的一致性、隔离性和并发性,采取的一系列措施和规定。MySQL 支持以下四种隔离级别:
+
+1. 读未提交 (Read Uncommitted):最低的隔离级别,事务可以读取到其他事务未提交的数据。这种隔离级别可能导致脏读(Dirty Read),即读取到其他事务未提交的数据,可能会引起数据的不一致性。
+2. 读提交 (Read Committed):事务只能读取到其他事务已经提交的数据,保证了数据的一致性。但在该隔离级别下,可能会出现不可重复读(Non-repeatable Read)问题,即在同一事务内多次读取同一行数据时,可能会得到不同的结果。
+3. 可重复读 (Repeatable Read):事务在执行期间对同一行数据进行读取时,会保持一致的结果。其他事务对该行数据的修改只有在当前事务提交后才能生效。这种隔离级别可以避免不可重复读问题,但仍然可能出现幻读(Phantom Read)问题,即在同一事务内多次执行相同的查询时,可能会得到不同的结果。(事务B插入一个数据,事务A进行更新,然后A事务就会读取到这个新插入的数据)
+4. 串行化 (Serializable):最高的隔离级别,事务会对数据库中的数据加锁,防止其他事务对数据的并发访问。这种隔离级别可以避免幻读问题,但可能会导致性能下降,因为事务需要等待其他事务释放锁。
+
+## 数据库隔离级别如何实现
+
+* 读未提交:因为可以读到未提交事务修改的数据,所以直接读取最新的数据就好了;
+* 读提交:通过 **Read View 来实现的**,**「读提交」隔离级别是在「每个语句执行前」都会重新生成一个 Read View**
+* 可重复读:通过 **Read View 来实现的**,**「可重复读」隔离级别是「启动事务时」生成一个 Read View,然后整个事务期间都在用这个 Read View**。
+* 串行化:通过加读写锁的方式来避免并行访问;
+
+## 数据库MVCC
+
+MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数据库管理系统(DBMS)中的并发控制机制,用于在多用户并发访问数据库时保障事务的隔离性和一致性。MVCC通过在数据库中为每个事务创建多个版本的数据副本,使多个事务可以同时读取和修改数据库中的数据,而不会相互干扰。
+
+在MVCC模型中,每个事务在读取和修改数据时,都会看到数据库中的一个一致性的快照(snapshot),而不是实际的物理数据。每个事务都有自己的事务ID(Transaction ID),数据库中的每条记录也会保存多个版本,每个版本都包含了一个事务ID和一个时间戳(Timestamp)。当事务执行读取操作时,只会看到在其事务开始之前提交的数据版本,而不会看到在其事务开始之后提交的数据版本。这样可以避免脏读、不可重复读和幻读等并发访问问题。
+
+## 加入索引有什么讲究
+
+1. 精选索引列:选择适合索引的列是关键。频繁在查询条件中出现,或者是查询条件的所有列。这样可以防止回表
+2. 注意索引的顺序:索引的顺序对查询性能有影响。对于联合索引,索引列的顺序应该根据查询的实际情况来选择。通常,将基数(Distinct count)较高的列放在前面,可以减少索引的选择性,提高查询性能。
+3. 考虑索引的类型:MySQL支持多种类型的索引,如普通索引、唯一索引、主键索引、全文索引等。根据查询的需求和数据的特点选择合适的索引类型。例如,对于需要唯一性约束的列,可以使用唯一索引或主键索引;对于文本字段的模糊查询,可以考虑使用全文索引。
+4. 避免过度索引:过度索引可能导致性能下降和维护成本增加。因此,避免在相同的列上创建多个重复的索引,避免对低基数列(Distinct count较低的列)添加索引,避免创建不必要的索引。
+
+## B树的特点
+
+1. 平衡二叉树节点最多有两个子树,而 B 树每个节点可以有多个子树,**M 阶 B 树表示该树每个节点最多有 M 个子树**
+2. 平衡二叉树每个节点只有一个数据和两个指向孩子的指针,而 B 树每个中间节点有 k-1 个关键字(可以理解为数据)和 k 个子树( k介于阶数 M 和 M/2 之间,M/2 ⬆️向上取整)
+3. B 树的所有叶子节点都在同一层,并且叶子节点只有关键字,指向孩子的指针为 null
+
+## 索引的分类
+
+- 按「物理存储」分类:**聚簇索引(主键索引)、二级索引(辅助索引)(非聚簇索引)**。
+- 按「字段特性」分类:**主键索引、唯一索引、普通索引、前缀索引**。
+- 按「字段个数」分类:**单列索引、联合索引**。
+
+## MySQL为什么使用B+树而不是使用B树
+
+- B+ 树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的 B 树,B+树的非叶子节点可以存放更多的索引,因此 B+ 树可以比 B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。
+- B+ 树有大量的冗余节点(所有非叶子节点都是冗余索引),这些冗余索引让 B+ 树在插入、删除的效率都更高,比如删除根节点的时候,不会像 B 树那样会发生复杂的树的变化;
+- B+ 树叶子节点之间用链表连接了起来,有利于范围查询,而 B 树要实现范围查询,因此只能通过树的遍历来完成范围查询,这会涉及多个节点的磁盘 I/O 操作,范围查询效率不如 B+ 树。
+
+## MySQL 有哪些锁?
+
+###  表级锁
+
+* 表锁
+* 元数据锁
+* 意向锁
+
+当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。
+
+*  AUTO-INC 锁
+
+### 行级锁
+
+*  Record Lock
+
+**记录锁,锁住单行数据**
+
+*  Gap Lock
+
+**间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的**
+
+*  Next-Key Lock
+
+**next-key lock 是包含间隙锁+记录锁的,如果一个事务获取了 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的**
+
+* 插入意向锁
+
+一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(next-key lock 也包含间隙锁)。
+
+如果有的话,插入操作就会发生**阻塞**,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个**插入意向锁**,表明有事务想在某个区间插入新记录,但是现在处于等待状态。
+
+## 加锁规则
+
+唯一索引等值查询:
+
+- 当查询的记录是「存在」的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock 会**退化成「记录锁」**。
+- 当查询的记录是「不存在」的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的 next-key lock 会**退化成「间隙锁」**。
+
+非唯一索引等值查询:
+
+- 当查询的记录「存在」时,由于不是唯一索引,所以肯定存在索引值相同的记录,于是非唯一索引等值查询的过程是一个扫描的过程,直到扫描到第一个不符合条件的二级索引记录就停止扫描,然后**在扫描的过程中,对扫描到的二级索引记录加的是 next-key 锁,而对于第一个不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。同时,在符合查询条件的记录的主键索引上加记录锁**。
+- 当查询的记录「不存在」时,**扫描到第一条不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。因为不存在满足查询条件的记录,所以不会对主键索引加锁**。
+
+非唯一索引和主键索引的范围查询的加锁规则不同之处在于:
+
+- 唯一索引在满足一些条件的时候,索引的 next-key lock 退化为间隙锁或者记录锁。
+- 非唯一索引范围查询,索引的 next-key lock 不会退化为间隙锁和记录锁。
+
+其实理解 MySQL 为什么要这样加锁,主要要以避免幻读角度去分析,这样就很容易理解这些加锁的规则了。
+
+## InnoDB 和 MyISAM 引擎的区别
+
+InnoDB和MyISAM是MySQL数据库中常见的两种存储引擎,它们有一些重要的区别。
+
+1. 事务支持:InnoDB引擎支持事务,可以使用ACID(原子性、一致性、隔离性和持久性)特性来确保数据的完整性和一致性。而MyISAM引擎不支持事务,它的操作是自动提交的,无法回滚。
+2. 锁的等级:InnoDB引擎在高并发读写操作下表现更好。它支持行级锁定,可以同时处理多个并发操作,从而提高了数据库的并发性能。相比之下,MyISAM引擎只支持表级锁定,当某个操作在修改表时,其他操作必须等待,可能导致并发性能下降。
+3. 外键约束:InnoDB引擎通过外键约束来保持数据完整性,可以定义外键关系。而MyISAM引擎不支持外键约束,需要在应用层面来维护数据的完整性。
+4. 崩溃恢复:InnoDB引擎具有崩溃恢复能力,可以保证数据库在崩溃后更好地恢复。MyISAM引擎在崩溃后恢复较差,可能会导致数据丢失或损坏。(因为使用了表级锁,非聚簇索引。而InnoDB使用redo log恢复)
+5. 全文搜索功能:MyISAM引擎支持全文索引和全文搜索功能,可以对文本进行高效的全文搜索。而InnoDB引擎在MySQL 5.6版本之前不支持全文索引,需要借助其他插件或引擎来实现全文搜索。
+5. 索引结构:InnoDB引擎使用聚簇索引(Clustered Index),将数据存储在主键的索引树中,可以提高查询效率。而MyISAM引擎使用非聚簇索引(Non-clustered Index),索引文件和数据文件分开存储。
+
+## 什么是全文索引
+
+使用`like%xxx%`进行模糊查询时,字段的索引就会失效。因此,在数据量大的情况下,通过此种方式查询的效率极低。这个时候,就可通过全文索引(Full-Text Search)来进行优化。
+
+全文索引(Full-Text Search)是将存储于数据库中的整本书或整篇文章中的任意信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。
+
+全文索引一般是通过倒排索引实现的,倒排索引如同 B+Tree 一样,也是一种索引结构。它在辅助表中存储了单词与单词自身在一个或多个文档中所在位置之间的映射,这通常利用关联数组实现,拥有两种表现形式:
+
+```sql
+    inverted file index:{单词,单词所在文档的id}
+
+    full inverted index:{单词,(单词所在文档的id,再具体文档中的位置)}
+```
+
+创建索引之后可以在索引中查找与关键词匹配的文档列表。可以使用布尔检索、向量空间模型或其他检索算法来计算文档与关键词的相关性,并返回匹配度高的文档结果。
+
+## binlog与主从复制
+
+binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作,比如 SELECT 和 SHOW 操作。
+
+binlog日志可以用于在主从数据库之间复制数据,从而实现数据的高可用和负载均衡等功能。
+MySQL的binlog日志有三种格式,分别是Statement格式、Row格式和Mixed格式。它们之间的区别如下:
+
+* STATEMENT:每一条修改数据的 SQL 都会被记录到 binlog 中(相当于记录了逻辑操作,所以针对这种格式, binlog 可以称为逻辑日志),主从复制中 slave 端再根据 SQL 语句重现。但 STATEMENT 有动态函数的问题,比如你用了 uuid 或者 now 这些函数,你在主库上执行的结果并不是你在从库执行的结果,这种随时在变的函数会导致复制的数据不一致;
+* ROW:记录行数据最终被修改成什么样了(这种格式的日志,就不能称为逻辑日志了),不会出现 STATEMENT 下动态函数的问题。但 ROW 的缺点是每行数据的变化结果都会被记录,比如执行批量 update 语句,更新多少行数据就会产生多少条记录,使 binlog 文件过大,而在 STATEMENT 格式下只会记录一个 update 语句而已;
+* MIXED:包含了 STATEMENT 和 ROW 模式,它会根据不同的情况自动使用 ROW 模式和 STATEMENT 模式;
+
+MySQL 的主从复制依赖于 binlog ,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上。复制的过程就是将 binlog 中的数据从主库传输到从库上。
+
+这个过程一般是**异步**的,也就是主库上执行事务操作的线程不会等待复制 binlog 的线程同步完成。
+
+![MySQL 主从复制过程](assets/主从复制过程.drawio.png)
+
+MySQL 集群的主从复制过程梳理成 3 个阶段:
+
+- **写入 Binlog**:主库写 binlog 日志,提交事务,并更新本地存储数据。
+- **同步 Binlog**:把 binlog 复制到所有从库上,每个从库把 binlog 写到暂存日志中。
+- **回放 Binlog**:回放 binlog,并更新存储引擎中的数据。
+
+具体详细过程如下:
+
+- MySQL 主库在收到客户端提交事务的请求之后,会先写入 binlog,再提交事务,更新存储引擎中的数据,事务提交完成后,返回给客户端“操作成功”的响应。
+- 从库会创建一个专门的 I/O 线程,连接主库的 log dump 线程,来接收主库的 binlog 日志,再把 binlog 信息写入 relay log 的中继日志里,再返回给主库“复制成功”的响应。
+- 从库会创建一个用于回放 binlog 的线程,去读 relay log 中继日志,然后回放 binlog 更新存储引擎中的数据,最终实现主从的数据一致性。
+- 当一个事务在 MySQL 主库上被回滚时,相应的回滚操作会被写入 binlog,以确保主从复制和数据一致性。
+
+在完成主从复制之后,你就可以在写数据时只写主库,在读数据时只读从库,这样即使写请求会锁表或者锁记录,也不会影响读请求的执行。
+
+> 从库是不是越多越好?
+
+不是的。
+
+因为从库数量增加,从库连接上来的 I/O 线程也比较多,**主库也要创建同样多的 log dump 线程来处理复制的请求,对主库资源消耗比较高,同时还受限于主库的网络带宽**。
+
+所以在实际使用中,一个主库一般跟 2~3 个从库(1 套数据库,1 主 2 从 1 备主),这就是一主多从的 MySQL 集群结构。
+
+> MySQL 主从复制还有哪些模型?
+
+主要有三种:
+
+- **同步复制**:MySQL 主库提交事务的线程要等待所有从库的复制成功响应,才返回客户端结果。这种方式在实际项目中,基本上没法用,原因有两个:一是性能很差,因为要复制到所有节点才返回响应;二是可用性也很差,主库和所有从库任何一个数据库出问题,都会影响业务。
+- **异步复制**(默认模型):MySQL 主库提交事务的线程并不会等待 binlog 同步到各从库,就返回客户端结果。这种模式一旦主库宕机,数据就会发生丢失。
+- **半同步复制**:MySQL 5.7 版本之后增加的一种复制方式,介于两者之间,事务线程不用等待所有的从库复制成功响应,只要一部分复制成功响应回来就行,比如一主二从的集群,只要数据成功复制到任意一个从库上,主库的事务线程就可以返回给客户端。这种**半同步复制的方式,兼顾了异步复制和同步复制的优点,即使出现主库宕机,至少还有一个从库有最新的数据,不存在数据丢失的风险**。
+
+## undo log
+
+ **undo log(回滚日志),它保证了事务的 ACID 特性中的原子性(Atomicity)**。
+
+![回滚事务](assets/回滚事务.png)
+
+每当 InnoDB 引擎对一条记录进行操作(修改、删除、新增)时,要把回滚时需要的信息都记录到 undo log 里,比如:
+
+- 在**插入**一条记录时,要把这条记录的主键值记下来,这样之后回滚时只需要把这个主键值对应的记录**删掉**就好了;
+- 在**删除**一条记录时,要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录**插入**到表中就好了;
+- 在**更新**一条记录时,要把被更新的列的旧值记下来,这样之后回滚时再把这些列**更新为旧值**就好了。
+
+一条记录的每一次更新操作产生的 undo log 格式都有一个 roll_pointer 指针和一个 trx_id 事务id:
+
+- 通过 trx_id 可以知道该记录是被哪个事务修改的;
+- 通过 roll_pointer 指针可以将这些 undo log 串成一个链表,这个链表就被称为版本链;
+
+版本链如下图:
+
+![版本链](assets/版本链.png)
+
+因此,undo log 两大作用:
+
+- **实现事务回滚,保障事务的原子性**。事务处理过程中,如果出现了错误或者用户执 行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态。
+- **实现 MVCC(多版本并发控制)关键因素之一**。MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。
+
+## Buffer Pool?
+
+Innodb 存储引擎缓冲池**(Buffer Pool)**
+
+![Buffer Poo](assets/缓冲池.drawio.png)
+
+有了 Buffer Poo 后:
+
+- 当读取数据时,如果数据存在于 Buffer Pool 中,客户端就会直接读取 Buffer Pool 中的数据,否则再去磁盘中读取。
+- 当修改数据时,如果数据存在于 Buffer Pool 中,那直接修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页(该页的内存数据和磁盘上的数据已经不一致),为了减少磁盘I/O,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入到磁盘。
+
+### Buffer Pool 缓存什么?
+
+InnoDB 会把存储的数据划分为若干个「页」,以页作为磁盘和内存交互的基本单位,一个页的默认大小为 16KB。因此,Buffer Pool 同样需要按「页」来划分。
+
+在 MySQL 启动的时候,**InnoDB 会为 Buffer Pool 申请一片连续的内存空间,然后按照默认的`16KB`的大小划分出一个个的页, Buffer Pool 中的页就叫做缓存页**。此时这些缓存页都是空闲的,之后随着程序的运行,才会有磁盘上的页被缓存到 Buffer Pool 中。
+
+所以,MySQL 刚启动的时候,你会观察到使用的虚拟内存空间很大,而使用到的物理内存空间却很小,这是因为只有这些虚拟内存被访问后,操作系统才会触发缺页中断,申请物理内存,接着将虚拟地址和物理地址建立映射关系。
+
+Buffer Pool 除了缓存「索引页」和「数据页」,还包括了 Undo 页,插入缓存、自适应哈希索引、锁信息等等。
+
+
+
+> **Undo 页是记录什么?**
+
+开启事务后,InnoDB 层更新记录前,首先要记录相应的 undo log,如果是更新操作,需要把被更新的列的旧值记下来,也就是要生成一条 undo log,undo log 会写入 Buffer Pool 中的 Undo 页面。
+
+> **查询一条记录,就只需要缓冲一条记录吗?**
+
+不是的。
+
+当我们查询一条记录时,InnoDB 是会把整个页的数据加载到 Buffer Pool 中,将页加载到 Buffer Pool 后,再通过页里的「页目录」去定位到某条具体的记录。
+
+
+
+## redo log
+
+为了防止断电导致数据丢失的问题,当有一条记录需要更新的时候,InnoDB 引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来,**这个时候更新就算完成了**。
+
+后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 **WAL (Write-Ahead Logging)技术**。
+
+**WAL 技术指的是, MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上**。
+
+过程如下图:
+
+![img](assets/wal.png)
+
+> **什么是 redo log?**
+
+redo log 是物理日志,记录了某个数据页做了什么修改,比如**对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新**,每当执行一个事务就会产生这样的一条或者多条物理日志。
+
+在事务提交时,只要先将 redo log 持久化到磁盘即可,可以不需要等到将缓存在 Buffer Pool 里的脏页数据持久化到磁盘。
+
+当系统崩溃时,虽然脏页数据没有持久化,但是 redo log 已经持久化,接着 MySQL 重启后,可以根据 redo log 的内容,将所有数据恢复到最新的状态。
+
+> **被修改 Undo 页面,需要记录对应 redo log 吗?**
+
+需要的。
+
+开启事务后,InnoDB 层更新记录前,首先要记录相应的 undo log,如果是更新操作,需要把被更新的列的旧值记下来,也就是要生成一条 undo log,undo log 会写入 Buffer Pool 中的 Undo 页面。
+
+不过,**在内存修改该 Undo 页面后,需要记录对应的 redo log**。
+
+> **redo log 和 undo log 区别在哪?**
+
+这两种日志是属于 InnoDB 存储引擎的日志,它们的区别在于:
+
+- redo log 记录了此次事务「**完成后**」的数据状态,记录的是更新**之后**的值;
+- undo log 记录了此次事务「**开始前**」的数据状态,记录的是更新**之前**的值;
+
+事务提交之前发生了崩溃,重启后会通过 undo log 回滚事务,事务提交之后发生了崩溃,重启后会通过 redo log 恢复事务,如下图:
+
+![事务恢复](assets/事务恢复.png)
+
+所以有了 redo log,再通过 WAL 技术,InnoDB 就可以保证即使数据库发生异常重启,之前已提交的记录都不会丢失,这个能力称为 **crash-safe**(崩溃恢复)。可以看出来, **redo log 保证了事务四大特性中的持久性**。
+
+> **redo log 要写到磁盘,数据也要写磁盘,为什么要多此一举?**
+
+写入 redo log 的方式使用了追加操作, 所以磁盘操作是**顺序写**,而写入数据需要先找到写入位置,然后才写到磁盘,所以磁盘操作是**随机写**。
+
+磁盘的「顺序写 」比「随机写」 高效的多,因此 redo log 写入磁盘的开销更小。
+
+针对「顺序写」为什么比「随机写」更快这个问题,可以比喻为你有一个本子,按照顺序一页一页写肯定比写一个字都要找到对应页写快得多。
+
+可以说这是 WAL 技术的另外一个优点:**MySQL 的写操作从磁盘的「随机写」变成了「顺序写」**,提升语句的执行性能。这是因为 MySQL 的写操作并不是立刻更新到磁盘上,而是先记录在日志上,然后在合适的时间再更新到磁盘上 。
+
+至此, 针对为什么需要 redo log 这个问题我们有两个答案:
+
+- **实现事务的持久性,让 MySQL 有 crash-safe 的能力**,能够保证 MySQL 在任何时间段突然崩溃,重启后之前已提交的记录都不会丢失;
+- **将写操作从「随机写」变成了「顺序写」**,提升 MySQL 写入磁盘的性能。
+
+> **产生的 redo log 是直接写入磁盘的吗?**
+
+不是的。
+
+实际上, 执行一个事务的过程中,产生的 redo log 也不是直接写入磁盘的,因为这样会产生大量的 I/O 操作,而且磁盘的运行速度远慢于内存。
+
+所以,redo log 也有自己的缓存—— **redo log buffer**,每当产生一条 redo log 时,会先写入到 redo log buffer,后续在持久化到磁盘如下图:
+
+![事务恢复](assets/redologbuf.webp)
+
+redo log buffer 默认大小 16 MB,可以通过 `innodb_log_Buffer_size` 参数动态的调整大小,增大它的大小可以让 MySQL 处理「大事务」是不必写入磁盘,进而提升写 IO 性能。
+
+### redo log 什么时候刷盘?
+
+缓存在 redo log buffer 里的 redo log 还是在内存中,它什么时候刷新到磁盘?
+
+主要有下面几个时机:
+
+- MySQL 正常关闭时;
+- 当 redo log buffer 中记录的写入量大于 redo log buffer 内存空间的一半时,会触发落盘;
+- InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
+- 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘(这个策略可由 innodb_flush_log_at_trx_commit 参数控制,下面会说)。
+
+## redo log和binlog区别
+
+binlog和redolog都是用于MySQL数据库的日志。它们都可以用于数据恢复,但是它们的使用场景和恢复方法有所不同。
+
+binlog是MySQL的二进制日志,它记录了所有对MySQL数据库的修改操作,包括插入、更新和删除等。binlog可以用于恢复MySQL数据库到指定的时间点或者指定的事务。具体来说,可以使用mysqlbinlog命令将binlog文件解析成SQL语句,然后再执行这些SQL语句,从而恢复MySQL数据库的状态。
+
+redolog是MySQL的重做日志,它记录了所有对MySQL数据库的修改操作,但是只记录了物理操作,比如页的修改。redolog可以用于恢复MySQL数据库的崩溃恢复,即在MySQL崩溃后,通过重做日志,将数据库恢复到最近一次提交的状态。具体来说,可以使用innodb_recovery命令来进行崩溃恢复,该命令会根据重做日志来恢复数据库。
+
+因此,binlog和redolog都可以用于数据恢复,但是它们的使用场景和恢复方法有所不同。binlog主要用于数据恢复到指定时间点或者指定事务,而redolog主要用于MySQL的崩溃恢复。
+
+## mysql优化慢SQL
+
+### 开启慢查询日志
+
+首先开启慢查询日志,由参数`slow_query_log`决定是否开启,在MySQL命令行下输入下面的命令:
+
+```mysql
+set global slow_query_log=on;
+```
+
+或者可以使用druid连接池去监控
+
+其次设置一个慢查询阈值
+
+```mysql
+set global long_query_time=1;
+```
+
+只要你的SQL实际执行时间超过了这个阈值,就会被记录到慢查询日志里面。这个阈值默认是10s,线上业务一般建议把`long_query_time`设置为1s,如果某个业务的MySQL要求比较高的QPS,可设置慢查询为0.1s。
+
+最后通过
+
+```mysql
+show global variables like 'slow_query_log_file'
+```
+
+语句可以找到慢查询的日志
+
+### 使用**explain**分析sql执行计划
+
+* select_type
+
+![img](assets/v2-98b72fd8e29df55aecdafb8deff0312f_720w.webp)
+
+* type
+
+![img](assets/v2-4c45bde8970caa0205d64b50095169c4_720w.webp)
+
+* Extra:
+
+![img](assets/v2-3ab6401c24be71551d1138762ed1a307_720w.webp)
+
+### 关键字优化
+
+* 因为只有在内连接的时候,and就一并筛选,而Where是将两张表先合并一起,再做筛选
+* 优化value的插入方式,即insert (a, b) (1, ,2,3,4)
+* 避免索引失效
+* 避免使用not null not in 之类的关键字,均会导致索引失效
+
+## CHAR和VARCHAR的区别
+
+在MySQL中,`CHAR`和`VARCHAR`都是用于存储文本数据的数据类型,它们之间有以下区别:
+
+1. 存储方式:`CHAR`类型是固定长度的,当存储数据时,会使用固定的空间。例如,如果定义一个`CHAR(10)`类型的字段,无论实际存储的数据长度是多少,都会占用10个字符的空间。而`VARCHAR`类型是可变长度的,只会占用实际存储的数据长度加上额外的存储空间(1或2个字节用于记录数据长度),对于较短的数据,它占用的空间会更小。
+2. 存储效率:由于`CHAR`类型是固定长度的,所以在存储和检索时效率相对较高。而`VARCHAR`类型由于长度可变,可能会造成额外的存储空间和内存开销,所以在存储和检索大量数据时,效率可能稍低。
+3. 数据填充:对于`CHAR`类型,如果实际存储的数据长度小于定义的长度,会使用空格进行填充以达到指定长度。而`VARCHAR`类型不会进行填充。
+4. 索引和排序:在MySQL中,对于`CHAR`类型的列,可以更好地利用索引和排序的性能,因为它的长度固定,查询时可以更快地定位数据。而`VARCHAR`类型由于长度可变,可能会影响索引和排序的效率。
+
+## 索引失效场景
+
+* 最左前缀原则:要求建立索引的一个列都不能缺失,否则会出现索引失效
+
+* 索引列上的计算,函数、类型转换(列类型是字符串在条件中需要使用引号,否则不走索引)、均会导致索引失效:,索引的数据结构只能对原值做索引
+
+* 索引列中使用 is not null 会导致索引列失效:在where 语句种筛选 idx is null 时,由于索引字段不为空,所以该条件失效,无法查询;在where 语句种筛选 idx is not null 时,由于索引字段本身不为空,所以该条件也失效,会造成全表扫描;
+
+* 索引列中使用 like 查询的前以 % 开头会导致索引列失效。
+
+* 索引列用 or 连接时会导致索引失效:如果条件中有or,只要其中一个条件没有索引,其他字段有索引也不会使用。
+
+## mysql分库分表历史数据如何查询
+
+* 直接进行迁移:记录时间戳,使用定时任务去扫描
+* 平滑迁移:只插入,旧表数据不动,插入时候直接加上扩容倍数。查询直接分批查询。
+
+## mysql分库分表物理层面优化
+
+* IO瓶颈
+
+磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的IO,降低查询速度 ->  分库和垂直分表。
+
+网络IO瓶颈,请求的数据太多,网络带宽不够 ->  分库。
+
+* CPU瓶颈
+
+SQL问题,如SQL中包含join,group by,order by,非索引字段条件查询等,增加CPU运算的操作 -> SQL优化,建立合适的索引,在业务Service层进行业务计算。
+
+单表数据量太大,查询时扫描的行太多,SQL效率低,CPU率先出现瓶颈 ->  水平分表。
+
+* 存储瓶颈
+
+关系型数据库多以B+树类型的索引,在数据量超过阈值的情况,索引深度的增加使得磁盘访问的IO次数增加,导致性能下降,同时,高并发访问使得集中数据库成为系统瓶颈。
+
+## 既然Hash比B+树更快,为什么MySQL用B+树来存储索引呢?
+
+MySQL中存储索引用到的数据结构是B+树,B+树的查询时间跟树的高度有关,是log(n),如果用hash存储,那么查询时间是O(1)。
+
+采用Hash来存储确实要更快,但是采用B+树来存储索引的原因主要有以下两点:
+
+一、**从内存角度上说**,数据库中的索引一般是在磁盘上,数据量大的情况可能无法一次性装入内存,B+树的设计可以允许数据分批加载。
+
+二、**从业务场景上说**,如果只选择一个数据那确实是hash更快,但是数据库中经常会选中多条,这时候由于B+树索引有序,并且又有链表相连,它的查询效率比hash就快很多了。
+
+## B+树插入流程
+
+B+树是B树的一种变形形式,一颗B+树包含根节点、内部节点和叶子节点,B+树上的叶子节点存储关键字以及相应记录的地址,叶子节点以上各层作为索引使用。
+
+一棵m阶的B+树定义如下:
+
+* 1)根结点最少包含1个关键字个数,最多包含m-1个关键字;
+* 2)B+树内部结点不保存数据,只用于索引,所有数据(或者说记录)都保存在叶子结点中;
+* 3)内部结点最少有ceil(m / 2) (向上取整)- 1个关键字,最多有m-1个关键字(或者说内部结点最多有m个子树);
+* 4)内部结点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它,叶子结点中的记录也按照key的大小排列;
+* 5)每个叶子结点都存有相邻叶子结点的指针,叶子结点本身依关键字的大小自小而大顺序连接;
+  如下图是一颗标准的5阶B+树:
+
+![image-20230824174350063](assets/image-20230824174350063.png)
+
+![image-20230824174809579](assets/image-20230824174809579.png)
+
+![img](assets/20201104163915661.png)
+
+​	
+
+下面我们通过一个简单的示例说明B+树的详细构建过程:
+
+我们以构建一个5阶B+树为例,根据B+树特性,最少包含2个关键字,最多可以包含4个关键字,当不满足上面条件的时候,可能就需要进行分裂操作了。
+
+![img](assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1dlaXhpYW9odWFp,size_16,color_FFFFFF,t_70-169287061300535.png)
+
+## 数据库三大范式
+
+* 第一范式:列不可再分
+* 第二范式:属性完全依赖主键
+* 第三范式:属性不依赖于其他非主键,属性直接依赖于主键
+
+## limit与深度翻页
+
+最常见的分页写法就是使用limit,在分页查询时,会在 LIMIT 后面传两个参数,一个是偏移量(offset),一个是获取的条数(limit)。
+
+实现方式是先查询offset+limit条数据,再将offset条数据丢弃给用户返回剩下的limit条数据。比如limit 10000,10实际上是mysql查找到前10010条数据,之后丢弃前面的10000行后再返回
+
+这样子当偏移量很小时,查询速度很快,但是随着 offset 变大时,查询速度会越来越慢,因为查找的数据越来越多
+
+### 优化
+
+- 方式一:
+
+```mysql
+select * from t1 where id >= 300000 order by id limit 10
+```
+
+避免了扫描前offset条记录
+
+但是每次查询都需要拿到上一页的最大/小id。比如当前在第3页,需要查询第5页的数据就没办法了
+
+* 方式二:
+
+结合普通limit与方式一,解决方式二的问题,但是offset要尽量小
+
+```mysql
+select * from t1 where id > 300000 order by id limit 10, 10
+```
+
+* 方式三:
+
+```mysql
+select * from t1 where id > (select id from t1 order by id limit 300000, 1) limit 10
+```
+
+## MySQL中 IS NULL、IS NOT NULL、不等于, 能用上索引吗?
+
+**MySQL中决定使不使用某个索引执行查询的依据就是成本够不够小,如果null值很多,还是会用到索引的。**
+
+## MySQL允许在唯一索引字段中添加多个NULL值
+
+ 在sql server中,唯一索引字段不能出现多个null值 在mysql 的innodb引擎中,是允许在唯一索引的字段中出现多个null值的。 根据NULL的定义,**NULL表示的是未知,因此两个NULL比较的结果既不相等,也不不等,结果仍然是未知。**根据这个定义,多个NULL值的存在应该不违反唯一约束,所以是合理的,在oracel也是如此。
+
+## mysql索引为什么不能为null
+
+会引起歧义,就不允许
+
+## 为什么是2千万?
+
+假设
+
+- 非叶子节点内指向其他页的数量为 x
+- 叶子节点内能容纳的数据行数为 y
+- B+ 数的层数为 z
+
+一页是16K,**页又一些File Header (38 byte)、Page Header (56 Byte)、Infimum + Supermum(26 byte)、File Trailer(8byte), 再加上页目录,大概 1k 左右。** 剩下 15k 用于存数据,主键我们假设是 Bigint (8 byte), 而页号也是固定的(4Byte)那么索引页中的一条数据也就是 12byte。
+
+所以非叶子节点内指向其他页的数量为 x , x=15*1024/12≈1280 行。
+
+叶子节点和非叶子节点的结构是一样的,同理,能放数据的空间也是 15k。
+
+但是叶子节点中存放的是真正的行数据,这个影响的因素就会多很多,比如,字段的类型,字段的数量。每行数据占用空间越大,页中所放的行数量就会越少。
+
+这边我们暂时按一条行数据 1k 来算,那一页就能存下 15 条,Y = 15*1024/1000 ≈15。
+
+算到这边了,是不是心里已经有谱了啊。
+
+根据上述的公式,Total =x^(z-1) *y,已知 x=1280,y=15:
+
+- 假设 B+ 树是两层,那就是 z = 2, Total = (1280 ^1 )*15 = 19200
+- 假设 B+ 树是三层,那就是 z = 3, Total = (1280 ^2) *15 = 24576000 (约 2.45kw)

BIN
孙浩博/八股/assets/03eacec67cc58ff8d5819d0872ddd41e.png


BIN
孙浩博/八股/assets/04163db3b7ca4b4c8fbfdf4e7253a98ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/056c87751b9dd7b56f4264240fe96d00.png


BIN
孙浩博/八股/assets/061921034534396.png


BIN
孙浩博/八股/assets/13e4361407ba46979e802eaa654dcf67.png


BIN
孙浩博/八股/assets/1418b09699fe4614a594a565c55055d5tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/16c1e0e2878c44dctplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e28889eafftplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e289a351b2tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e289f9213etplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e28aee99a1tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e2ca893b49tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e2d7df4fbftplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e2db1c4812tplv-t2oaga2asx-jj-mark3024000q75-16934721993069.awebp


BIN
孙浩博/八股/assets/16c1e0e2db1c4812tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e2e2a2835etplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e2e507aec0tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e0e3178398fctplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/16c1e26a5ecf086etplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
孙浩博/八股/assets/1cc7401143e79383ead96582ac11b615.png


BIN
孙浩博/八股/assets/20201104163915661.png


BIN
孙浩博/八股/assets/20201104164026393.png


BIN
孙浩博/八股/assets/20201104164057943.png


BIN
孙浩博/八股/assets/202308021211012.jpeg


BIN
孙浩博/八股/assets/202308021212079.jpeg


BIN
孙浩博/八股/assets/202308021212511.jpeg


BIN
孙浩博/八股/assets/202308021218967.jpeg


BIN
孙浩博/八股/assets/2164474-20210716210057908-1704850787.png


BIN
孙浩博/八股/assets/22c7fe97ce5d3c382b08d83a4d8a5b96.png


BIN
孙浩博/八股/assets/2306520394.png


BIN
孙浩博/八股/assets/24-先来先服务.jpg


BIN
孙浩博/八股/assets/25-最短作业优先算法.jpg


BIN
孙浩博/八股/assets/2535cfeb9cfb44d4a0a04506f09f7485tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/26-响应比公式.jpg


BIN
孙浩博/八股/assets/26f88373d8454682b9e0c1d4fd1611b4-20230309233114856.png


BIN
孙浩博/八股/assets/27-时间片轮询.jpg


BIN
孙浩博/八股/assets/28-多级队列.jpg


BIN
孙浩博/八股/assets/2802786ab4f52c1e248904e5cef33a74.png


BIN
孙浩博/八股/assets/2ae0ed790c7e7403f215acb2bd82e884.png


BIN
孙浩博/八股/assets/2b7231b6aabb9a9a2e2390ab3a280b2d-20230309232920063.png


BIN
孙浩博/八股/assets/2db4831516b9a8b79f833cf0593c1f12.png


BIN
孙浩博/八股/assets/2e2b95eebf60b6d03f6c1476f4d7c697.png


BIN
孙浩博/八股/assets/30c2c70721c12f9c140358fbdc5f2282.png


BIN
孙浩博/八股/assets/316b81a42ea843a192cc2f3578fbdb81tplv-k3u1fbpfcp-zoom-in-crop-mark1512000-16927837871897.awebp


BIN
孙浩博/八股/assets/316b81a42ea843a192cc2f3578fbdb81tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/31b9745a2fa94fb693a7ea1257aa5f7ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/33f858652afc4be6bb1d7b1f1dc33eaatplv-k3u1fbpfcp-zoom-in-crop-mark1512000-169278452952817.awebp


BIN
孙浩博/八股/assets/33f858652afc4be6bb1d7b1f1dc33eaatplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/35820959e8cf4376391c427ed7f81495.png


BIN
孙浩博/八股/assets/3a6cb4e3f27241d3b09b4766bb0b1124.png


BIN
孙浩博/八股/assets/3层跳表-跨度.drawio.png


BIN
孙浩博/八股/assets/3层跳表-跨度.png


BIN
孙浩博/八股/assets/454a8228a6549176ad7e0484fba3c92b.png


BIN
孙浩博/八股/assets/47e6c8fbc17fd6c89bdfcb5eedaaacff.png


BIN
孙浩博/八股/assets/4845008abadaa871613873f5ffdcb542.png


BIN
孙浩博/八股/assets/4d850bfe8d712d3d67ff13e59b919452.png


BIN
孙浩博/八股/assets/4ef8691d67eb1eb53217099d0a691eb5.png


BIN
孙浩博/八股/assets/516738c4058cdf9109e40a7812ef4239.png


BIN
孙浩博/八股/assets/517e2f7939394b3ca35936702a107f07tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/559260f5ef944cd1a146d07308275b89tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/5e9e65a4a59b3688fa37cadbd87bb5ac.png


BIN
孙浩博/八股/assets/60d6b91f49ac4d11bee43f86f33566d6tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/6a68be69f6b64ad1a8df234d9f0772detplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/775865f6bd894dfba8d373ee54d79af1.png


BIN
孙浩博/八股/assets/788acb3c73174c42b603fe67e96c89f5tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/7d45e677f6c2428d9b9db7022416fe26tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/80a2bcb823e04e05a10c8f19de2930b9tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/8febac10b14bed16cb96d1d944cd08da.png


BIN
孙浩博/八股/assets/955fdfb94c234e32939c76954fd28a56tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/98987d9417b2bab43087f45fc959d32a-20230309232253633.png


BIN
孙浩博/八股/assets/9ebde5c11ad69447314c216acf188fc8.png


BIN
孙浩博/八股/assets/a3e7d217ecb825e94bdc577a467eb29d.png


BIN
孙浩博/八股/assets/a6e0e622b7384ac78f733e471b280c27tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/a851f56a384b4a0f9da76644d645ae1ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/arch-x-reduce-2.png


BIN
孙浩博/八股/assets/arch-x-reduce-3.png


BIN
孙浩博/八股/assets/arch-x-reduce-31-169347359783720.png


BIN
孙浩博/八股/assets/b52e004bd4654cb1b51cdb409182156ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/b5681d905102439aa1a40412100da566.png


BIN
孙浩博/八股/assets/c55029a32a6448d9aa35bb3de6efcecatplv-k3u1fbpfcp-zoom-in-crop-mark4536000.awebp


BIN
孙浩博/八股/assets/c7787bc99996429381a1049580f6c24atplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/c8054fbec1b14607b2759ea0d1ddc2f4tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/cc208c2931b4e889d1a58cb655537767.png


BIN
孙浩博/八股/assets/cdc14698f629c74bf5a239cc8a611aeb.png


BIN
孙浩博/八股/assets/d4ce0c7fdf3b4039a0e4b0b200af731atplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/d528bae6fcec2357ba2eb8f324ad9fd5.png


BIN
孙浩博/八股/assets/d565806a3b7c4735859befbcdad5a105.png


BIN
孙浩博/八股/assets/d9f2d1f2d3674a50900eda504ecaa326tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/db568766644a4d10b8a91cdd2f8a4070.png


BIN
孙浩博/八股/assets/dba2bc3af0938d2c087f85acc191fd3f.png


BIN
孙浩博/八股/assets/dbb57b8d6071d011d05eeadd93269e13.png


BIN
孙浩博/八股/assets/e081b470870daeb763062bb873a4477e.png


BIN
孙浩博/八股/assets/e94e504adc5a75a2d7f562dc44166511.png


BIN
孙浩博/八股/assets/ea4f7e86baf2435af3999e5cd38b6a26.png


BIN
孙浩博/八股/assets/ec5c8e28d3ea308c6db2ac991a12ea80.png


BIN
孙浩博/八股/assets/f0d9d314c75c4bd989dadf044ecd6307tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
孙浩博/八股/assets/f109a45fe4904726b11fd36422f4abactplv-k3u1fbpfcp-zoom-in-crop-mark4536000.awebp


Неке датотеке нису приказане због велике количине промена