文章列表

慢SQL治理分享

作者:微信小助手

<p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.625" data-s="300,640" src="/upload/7d53c8948cfce39a6045b4ef09bdab72.jpg" data-type="jpeg" data-w="1024" style=""></p> <p style="text-align: center;"><br></p> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">一&nbsp; 为什么要做这个事情</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">1 &nbsp;什么是慢SQL?</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这里指的是MySQL慢查询,具体指运行时间超过long_query_time值的SQL。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">我们常听常见的MySQL中有二进制日志binlog、中继日志relaylog、重做回滚日志redolog、undolog等。针对慢查询,还有一种慢查询日志slowlog,用来记录在MySQL中响应时间超过阀值的语句。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">大家不要被慢查询这个名字误导,以为慢查询日志只会记录select语句,其实也会记录执行时间超过了long_query_time设定的阈值的insert、update等DML语句。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__comment"># 查看慢SQL是否开启</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">show</span>&nbsp;<span class="code-snippet__keyword">variables</span>&nbsp;<span class="code-snippet__keyword">like</span>&nbsp;<span class="code-snippet__string">"slow_query_log%"</span>;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"># 查看慢查询设定的阈值 单位:秒</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">show</span> <span class="code-snippet__keyword">variables</span> <span class="code-snippet__keyword">like</span> <span class="code-snippet__string">"long_query_time"</span>;</span></code></pre> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">对于我们使用的AliSQL-X-Cluster即XDB来说,默认慢查询是开启的,long_query_time设置为1秒。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">2 &nbsp;慢查询为何会导致故障?</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">真实的慢SQL往往会伴随着大量的行扫描、临时文件排序或者频繁的磁盘flush,直接影响就是磁盘IO升高,正常SQL也变为了慢SQL,大面积执行超时。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">去年双11后,针对技术侧暴露的问题,菜鸟CTO线推出多个专项治理,CTO-D各领一项作为sponsor,我所在的大团队负责慢SQL治理这个专项。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">二&nbsp; 要做到什么程度</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">1 &nbsp;怎么来衡量一个应用的慢SQL严重程度?</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">微平均</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="diff"><code><span class="code-snippet_outer">sum(aone应用慢SQL执行次数)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">-----------------------</span></span></code><code><span class="code-snippet_outer">sum(aone应用SQL执行次数)</span></code></pre> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;">我们认为,该值越大,影响越大;</span> <span style="color: rgb(62, 62, 62);font-size: 15px;">该值越小,影响可能小。</span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">极端情况就是应用里每次执行的SQL全是慢SQL,该值为1;应用里每次执行的SQL全不是慢SQL,该值为0。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">但是这个指标带来的问题是区分度不佳,尤其是对SQL QPS很高且大多数情况下SQL都不是慢查询的情况,偶发的慢SQL会被淹没。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">另外一个问题,偶发的慢SQL是真的慢SQL吗?我们遇到很多被慢查询日志记录的SQL,实际上可能受到其他慢SQL影响、MySQL磁盘抖动、优化器选择等原因使得常规查询下表现显然不是慢SQL的变成了慢SQL。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">宏平均</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="diff"><code><span class="code-snippet_outer">sum(慢SQL 1执行次数) sum(慢SQL n执行次数)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">----------------- + ------------------</span></span></code><code><span class="code-snippet_outer">sum(SQL 1执行次数) sum(SQL n执行次数)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">---------------------------------------</span></span></code><code><span class="code-snippet_outer"> n</span></code></pre> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这个算法建立在被抓到的慢SQL有一定执行次数的基础上,可以减少假性慢SQL的影响。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">当某些应用QPS很低,即一天执行SQL的次数很少,如果碰到假性SQL就会引起统计误差。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">执行次数</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="diff"><code><span class="code-snippet_outer">sum(aone应用慢SQL执行次数)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">-----------------------</span></span></code><code><span class="code-snippet_outer"> 7</span></code></pre> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;">统计最近一周平均每天的慢SQL执行次数,可以消除掉宏平均带来的假性SQL问题。</span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">慢SQL模板数量</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">以上维度均有个时间限定范围,为了追溯慢SQL历史处理情况,我们还引入了全局慢SQL模板数量维度。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="swift"><code><span class="code-snippet_outer"><span class="code-snippet__built_in">count</span>(distinct(aone应用慢<span class="code-snippet__type">SQL</span>模板) )</span></code></pre> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);font-size: 15px;">2&nbsp; 目标</span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">核心应用:解决掉所有的慢SQL</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">普通应用:微平均指标下降50%</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">3&nbsp; CTO报表</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">以CTO-D为单位根据以上多维度指标统计汇总应用的加权平均,由低到高得出排名,突出头尾top3,每周播报。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">三&nbsp; 为什么由我来做</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">猜测可能与我的背景有关,有C/C++背景,曾在上家公司负责过公司层面异地多活架构的设计和落地,对于MySQL比较了解一些。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">另外可能是利益无关,我所在小团队业务刚起步,不存在慢SQL,这样可以插入到各个业务线去。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">四&nbsp; 行动支撑</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">1&nbsp; 集团MySQL规约</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">索引规约摘录部分:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">【强制】超过三个表禁止join。需要join的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">说明:即使双表join也要注意表索引、SQL性能。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">【强制】在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为20的索引,区分度会高达90%以上,可以使用count(distinct left(列名, 索引长度))/count(*)的区分度来确定。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">说明:索引文件具有B-Tree的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">【推荐】防止因字段类型不同造成的隐式转换,导致索引失效。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">【参考】创建索引时避免有如下极端误解:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">1) 索引宁滥勿缺</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">认为一个查询就需要建一个索引。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">2) 吝啬索引的创建</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">认为索引会消耗空间、严重拖慢更新和新增速度。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;">3) 抵制唯一索引</span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">认为唯一索引一律需要在应用层通过“先查后插”方式解决。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">2&nbsp; DB变更标准</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">DDL需要控制变更速度,注意灰度和并发控制,变更发布需要在规定的变更发布窗口内。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">五&nbsp; 分享一些我参与优化的例子</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">1&nbsp; 数据分布不均匀</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.35390625" data-s="300,640" src="/upload/fa48c553596f8190787e5b9c15c72037.png" data-type="png" data-w="1280" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.54609375" data-s="300,640" src="/upload/36935f25a08dc25f7f8ecfeeb9622983.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">1)分库分表不合理</span> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">该业务数据分了8个库,每个库分了16张表,通过查看表空间可以看到数据几乎都分布在各个库的某2张表中。分库分表的策略有问题,另外过高预估了业务增量,这个持保留意见。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">2)索引不合理</span> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">单表创建了idx_logistics_corp_id_special_id的联合索引,但即便这样区分度依然太低,根据实验及业务反馈(logistics_corp_id,transport_type_id)字段组合区分度非常高,且业务存在transport_type_id的单查场景。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.45546875" data-s="300,640" src="/upload/bd55b8ca9d9779fa7663b90d4f2ca905.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">2&nbsp; 索引问题</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 14px;text-align: start;"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">SELECT</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">COUNT</span>(<span class="code-snippet__number">0</span>) <span class="code-snippet__keyword">AS</span> <span class="code-snippet__string">`tmp_count`</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">FROM</span>(</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">SELECT</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`user_id`</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`sc_item_id`</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">SUM</span>(</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">CASE</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`inventory_type`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">WHEN</span> <span class="code-snippet__number">1</span> <span class="code-snippet__keyword">THEN</span> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`quantity`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">ELSE</span> <span class="code-snippet__number">0</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">END</span></span></code><code><span class="code-snippet_outer"> ) <span class="code-snippet__keyword">AS</span> <span class="code-snippet__string">`saleable_quantity`</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">SUM</span>(</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">CASE</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`inventory_type`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">WHEN</span> <span class="code-snippet__number">1</span> <span class="code-snippet__keyword">THEN</span> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`lock_quantity`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">ELSE</span> <span class="code-snippet__number">0</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">END</span></span></code><code><span class="code-snippet_outer"> ) <span class="code-snippet__keyword">AS</span> <span class="code-snippet__string">`saleable_lock_quantity`</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">SUM</span>(</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">CASE</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`inventory_type`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">WHEN</span> <span class="code-snippet__number">401</span> <span class="code-snippet__keyword">THEN</span> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`quantity`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">ELSE</span> <span class="code-snippet__number">0</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">END</span></span></code><code><span class="code-snippet_outer"> ) <span class="code-snippet__keyword">AS</span> <span class="code-snippet__string">`transfer_on_way_quantity`</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`store_code`</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">MAX</span>(<span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`gmt_modified`</span>) <span class="code-snippet__keyword">AS</span> <span class="code-snippet__string">`gmt_modified`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">FROM</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">WHERE</span>(<span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`is_deleted`</span> = <span class="code-snippet__number">0</span>)</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">AND</span>(<span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`quantity`</span> &gt; <span class="code-snippet__number">0</span>)</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">AND</span> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`user_id`</span> <span class="code-snippet__keyword">IN</span>(<span class="code-snippet__number">3405569954</span>)</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">AND</span> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`store_code`</span> <span class="code-snippet__keyword">IN</span>(<span class="code-snippet__string">'ZJJHBHYTJJ0001'</span>, <span class="code-snippet__string">'...1000多个'</span>)</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">GROUP</span> <span class="code-snippet__keyword">BY</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`user_id`</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`sc_item_id`</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">ORDER</span> <span class="code-snippet__keyword">BY</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`user_id`</span> <span class="code-snippet__keyword">ASC</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`table_holder`</span>.<span class="code-snippet__string">`sc_item_id`</span> <span class="code-snippet__keyword">ASC</span></span></code><code><span class="code-snippet_outer"> ) <span class="code-snippet__string">`a`</span>;</span></code><code><span class="code-snippet_outer"><br></span></code></pre> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这个case对应的表有store_code索引,因此认为没问题,没办法优化了。实则通过执行计划,我们发现MySQL选择了全表扫描。针对该case实践发现,当范围查询的个数超过200个时,索引优化器将不再使用该字段索引。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">最终经过拉取最近一段时间的相关查询SQL,结合业务的数据分布,我们发现采用(is_deleted,quantity)即可解决。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">判断执行计划采用的索引长度:</span> <span style="color: rgb(62, 62, 62);font-size: 15px;">key_len的长度</span> <span style="color: rgb(62, 62, 62);font-size: 15px;">计算公</span> <span style="color: rgb(62, 62, 62);font-size: 15px;">式(&gt;=5.6.4)</span> </section> <pre style="text-align: justify;line-height: 1.75em;"><br></pre> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cpp"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">char</span>(<span class="code-snippet__number">10</span>)允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;&nbsp;<span class="code-snippet__number">10</span>&nbsp;*&nbsp;(&nbsp;character&nbsp;<span class="code-snippet__built_in">set</span>:utf8mb4=<span class="code-snippet__number">4</span>,utf8=<span class="code-snippet__number">3</span>,gbk=<span class="code-snippet__number">2</span>,latin1=<span class="code-snippet__number">1</span>)&nbsp;+&nbsp;<span class="code-snippet__number">1</span>(<span class="code-snippet__literal">NULL</span>)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">char</span>(<span class="code-snippet__number">10</span>)不允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;<span class="code-snippet__number">10</span>&nbsp;*&nbsp;(&nbsp;character&nbsp;<span class="code-snippet__built_in">set</span>:utf8mb4=<span class="code-snippet__number">4</span>,utf8=<span class="code-snippet__number">3</span>,gbk=<span class="code-snippet__number">2</span>,latin1=<span class="code-snippet__number">1</span>)</span></code><code><span class="code-snippet_outer">varchr(<span class="code-snippet__number">10</span>)允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;<span class="code-snippet__number">10</span>&nbsp;*&nbsp;(&nbsp;character&nbsp;<span class="code-snippet__built_in">set</span>:utf8mb4=<span class="code-snippet__number">4</span>,utf8=<span class="code-snippet__number">3</span>,gbk=<span class="code-snippet__number">2</span>,latin1=<span class="code-snippet__number">1</span>)&nbsp;+&nbsp;<span class="code-snippet__number">1</span>(<span class="code-snippet__literal">NULL</span>)&nbsp;+&nbsp;<span class="code-snippet__number">2</span>(变长字段)</span></code><code><span class="code-snippet_outer">varchr(<span class="code-snippet__number">10</span>)不允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;=&nbsp;&nbsp;<span class="code-snippet__number">10</span>&nbsp;*&nbsp;(&nbsp;character&nbsp;<span class="code-snippet__built_in">set</span>:utf8mb4=<span class="code-snippet__number">4</span>,utf8=<span class="code-snippet__number">3</span>,gbk=<span class="code-snippet__number">2</span>,latin1=<span class="code-snippet__number">1</span>)&nbsp;+&nbsp;<span class="code-snippet__number">2</span>(变长字段)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">int</span>允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;<span class="code-snippet__number">4</span>&nbsp;+&nbsp;<span class="code-snippet__number">1</span>(<span class="code-snippet__literal">NULL</span>)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">int</span>不允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;<span class="code-snippet__number">4</span></span></code><code><span class="code-snippet_outer">timestamp允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;<span class="code-snippet__number">4</span>&nbsp;+&nbsp;<span class="code-snippet__number">1</span>(<span class="code-snippet__literal">NULL</span>)</span></code><code><span class="code-snippet_outer">timestamp不允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;<span class="code-snippet__number">4</span></span></code><code><span class="code-snippet_outer">datatime允许<span class="code-snippet__literal">NULL</span> =&nbsp;&nbsp;<span class="code-snippet__number">5</span>&nbsp;+&nbsp;<span class="code-snippet__number">1</span>(<span class="code-snippet__literal">NULL</span>)</span></code><code><span class="code-snippet_outer">datatime不允许<span class="code-snippet__literal">NULL</span>&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;<span class="code-snippet__number">5</span></span></code></pre> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);font-size: 15px;">3&nbsp; 被人影响</span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">用到了索引却依然被爆出扫描2千万行:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.37890625" data-s="300,640" src="/upload/4d1db3735a5d87397c289d927eca6f2.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">索引字段区分度很高:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.34453125" data-s="300,640" src="/upload/84a303af4de8a4b96dec6edc3658f5c3.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">同时期常规SQL变为了慢查询:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.678125" data-s="300,640" src="/upload/c6fe79864e0b316451a0d42ce7753c50.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">DB数据盘访问情况:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.51171875" data-s="300,640" src="/upload/e036cf072944eaf5825be1525c459cb1.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">排查共用物理机其他实例的情况,发现有个库在问题时间附近有很多慢sql需要排序,写临时文件刚好写入了2GB:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.090625" data-s="300,640" src="/upload/53c7584e153a9c8986cf24dba138c6a1.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">多个MySQL实例leader节点混合部署在同一台物理机,虽然通过docker隔离了CPU、MEM等资源,但目前还没有做到buffer io的隔离。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.421875" data-s="300,640" src="/upload/1897ba8a7995cfdad7c42c88dd70e86c.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">4&nbsp; 无法解决</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">通过汇总分析高频的查询并结合业务得出合适的索引往往能够解决日常遇到的慢查询,但这并不是万能的。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">比如有可能索引越加越多,乃至成了这样:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.30546875" data-s="300,640" src="/upload/8fe24239c824fbed4bd4c4074c51f2d0.png" data-type="png" data-w="1280" style=""></p> <section style="text-align: justify;line-height: 1.75em;"> <br> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">有些场景,比如支持多个字段组合查询,又没有必填项,如果都要通过索引来支持显然是不合理的。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.15417558886509636" data-s="300,640" src="/upload/9e1de618007b27450ecf0892dd1c51d6.jpg" data-type="jpeg" data-w="467" style="width: 361px;height: 56px;"></p> <section style="text-align: justify;line-height: 1.75em;"> <br> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">查询场景下,将区分度较高的字段设定为必填项是个好习惯;查询组合很多的情况下考虑走搜索支持性更好的存储或者搜索引擎。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">六&nbsp; 日常化处理</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">随着各个CTO-D线的深入治理,各项指标较之前均有非常大的改观,比如核心应用完成慢查询清零,影响最大的一些慢SQL被得以解决,而我所在的团队排名也由最初的尾部top3进入到头部top3。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">慢SQL治理进入日常化,通过每周固定推送慢SQL工单、owner接手处理、结单,基本形成了定期清零的习惯和氛围,慢SQL治理专项也被多次点名表扬。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">七&nbsp; 小结</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这是一篇迟到的总结,现在回头看觉得这里面的策略制定、问题分析和解决的过程还是蛮值得拿出来和大家分享下。</span> </section>

什么是布隆过滤器?如何解决高并发缓存穿透问题?

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="letter-spacing: 0px;">日常开发中,大家经常使用缓存,但是你知道大型的互联网公司面对高并发流量,要注意缓存穿透问题吗!!!&nbsp; &nbsp;&nbsp;</span><span style="letter-spacing: 0px;">本</span><span style="letter-spacing: 0px;">文会介绍布隆过滤器,空间换时间,以较低的内存空间、高效解决这个问题。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="letter-spacing: 0px;"></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本篇文章的目录:</p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <br> </section> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="638" data-backw="578" data-ratio="1.1039861351819757" data-s="300,640" src="/upload/485bd2decf8b44c24f2a30e027c04a2b.jpg" data-type="jpeg" data-w="1154" style="width: 100%;height: auto;"></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong><br></strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>1、性能不够,缓存来凑</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">现在的年轻人都喜欢网购,没事就逛逛淘宝,剁剁手,买些自己喜欢的东西,释放下工作压力。</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <br> </section> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6514195583596214" data-s="300,640" src="/upload/34d77318888f5cab814a6e0974c84e59.jpg" data-type="jpeg" data-w="1268" style=""></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <br> <blockquote data-tool="mdnice编辑器"> <p>地址:</p> <p>https://detail.tmall.com/item.htm?id=628993216729</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">上图是一个天猫 iphone12 的</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">商品详情页</span></code><span style="font-size: 16px;">,id表示商品的编号</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">我们都知道淘宝的访问量是非常高的,为了提升系统的吞吐量,做了很多性能优化,其中非常重要一点是将信息异构到缓存中。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">有句话说的好:<strong>性能不够,缓存来凑。</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">但是,使用缓存时,我们要关注一个重要问题,如果缓存没有命中怎么办?</span></p> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.4590909090909091" data-s="300,640" src="/upload/d85c6d31600e3b122b553c4920bc1f13.jpg" data-type="jpeg" data-w="440" style=""></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <br> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);font-size: 17px;"><strong>2、缓存没有命中,怎么办?</strong></span></p> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.952" data-s="300,640" src="/upload/ee7becb51ba32a3a67560c7067560c61.jpg" data-type="jpeg" data-w="750" style=""></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">①我们先查询缓存,判断缓存中是否有数据</span> </section></li> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">②如果有数据,直接返回</span> </section></li> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">③如果缓存为空,我们需要再查一次数据库,并将数据格式异构化,然后预热到缓冲中,然后将结果返回</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">注意:</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">步骤 ③ 存在风险漏洞,如果缓存中数据不存在,压力会转嫁给数据库。假如被竞争对手利用,搞无效请求流量攻击,瞬间大量请求打到数据库中,对系统性能产生很大影响,很容易把数据库打挂,这种现象称为缓存穿透。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>3、那么如何处理缓存穿透?</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">我们的思路是,缓存中能不能判断这个数据库值的存在性,如果真的不存在,直接返回,也避免一次数据库查询。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">由于不存在是个</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">无限边界</span></code><span style="font-size: 16px;">,所以,我们采用反向策略,将存在的值建立一个高效的检索。每次缓存取值时,先走一次判空检索。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">简单归纳下,这个框架的要求:</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">快速检索</span> </section></li> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">内存空间要非常小</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">经调研,我们发现</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">布隆过滤器</span></code><span style="font-size: 16px;">具备以上两个条件。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>4、什么是布隆过滤器?</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">优点:空间效率和查询时间都远远超过一般的算法。</span> </section></li> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">缺点:有一定的误识别率,删除困难。</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>5、布隆过滤器如何构建?</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">布隆过滤器本质上是一个 n 位的二进制数组,用0和1表示。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">假如我们以商品为例,有三件商品,商品编码分别为,</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">id1</span></code><span style="font-size: 16px;">、</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">id2</span></code><span style="font-size: 16px;">、</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">id3</span></code></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">a)首先,对</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">id1</span></code><span style="font-size: 16px;">,进行三次哈希,并确定其在二进制数组中的位置。</span></p> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.37421875" data-s="300,640" src="/upload/3213ae2994d3a253d6442c7465fb6e4c.jpg" data-type="jpeg" data-w="1280" style=""></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <br> <blockquote data-tool="mdnice编辑器"> <p>三次哈希,对应的二进制数组下标分别是 2、5、8,将原始数据从 0 变为 1。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">b)对</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">id2</span></code><span style="font-size: 16px;">,进行三次哈希,并确定其在二进制数组中的位置。</span></p> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.39609375" data-s="300,640" src="/upload/2b65177ab4540d87b56a81351e824575.jpg" data-type="jpeg" data-w="1280" style=""></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <blockquote data-tool="mdnice编辑器"> <p>三次哈希,对应的二进制数组下标分别是 2、7、98,将原始数据从 0 变为 1。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">下标 2,之前已经被操作设置成 1,则本次认为是哈希冲突,不需要改动。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">Hash 规则:如果在 Hash 后,原始位它是 0 的话,将其从 0 变为 1;如果本身这一位就是 1 的话,则保持不变。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>6、布隆过滤器如何使用?</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong><br></strong></span></p> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="1.3746958637469586" data-s="300,640" src="/upload/ff628cdcec4b0fcef81bb8aca4e9b1de.jpg" data-type="jpeg" data-w="822" style="width: 481px;height: 661px;"></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <br> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">跟初始化的过程有点类似,当查询一件商品的缓存信息时,我们首先要判断这件商品是否存在。</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">通过三个哈希函数对商品id计算哈希值</span> </section></li> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">然后,在布隆数组中查找访问对应的位值,0或1</span> </section></li> <li style="font-size: 16px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 16px;">判断,三个值中,只要有一个不是1,那么我们认为数据是不存在的。</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">注意:布隆过滤器只能精确判断数据不存在情况,对于存在我们只能说是可能,因为存在Hash冲突情况,当然这个概率非常低。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>7、如何减少布隆过滤器的误判?</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">a)</span><span style="font-size: 16px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">增加二进制位数组的长度。这样经过hash后数据会更加的离散化,出现冲突的概率会大大降低</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">b)增加Hash的次数,变相的增加数据特征,特征越多,冲突的概率越小</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>8、布隆过滤器会不会很费内存?</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">带着疑问,我们来做个实验</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">假设有1千万个数据,我们需要记录其是否存在。存在的话标记1,不存在标记为0。技术选型,框架采用Redis的</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">BitMap</span></code><span style="font-size: 16px;">存储。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">数据初始化预热代码:</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">redisTemplate.executePipelined(new&nbsp;RedisCallback&lt;Long&gt;()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;@Nullable<br>&nbsp;&nbsp;&nbsp;&nbsp;@Override<br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Long&nbsp;doInRedis(RedisConnection&nbsp;connection)&nbsp;throws&nbsp;DataAccessException&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.openPipeline();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">for</span>&nbsp;(int&nbsp;offset&nbsp;=&nbsp;10000000;&nbsp;offset&nbsp;&gt;=&nbsp;0;&nbsp;offset--)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boolean&nbsp;value&nbsp;=&nbsp;offset&nbsp;%&nbsp;2&nbsp;==&nbsp;0&nbsp;?&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">true</span>&nbsp;:&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">false</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.setBit(<span style="color: #a6e22e;line-height: 26px;">"bloom-filter-data-1"</span>.getBytes(),&nbsp;offset,&nbsp;value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.closePipeline();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a6e22e;line-height: 26px;">return</span>&nbsp;null;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>});<br>System.out.println(<span style="color: #a6e22e;line-height: 26px;">"数据预热完成"</span>);<br></code></pre> <blockquote data-tool="mdnice编辑器"> <p>性能有点慢,我们也可以采用分组形式,10000个数一组,多批次提交。</p> </blockquote> </section> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.353125" data-s="300,640" src="/upload/f7484f4f043937b969cfb60a037a52e8.jpg" data-type="jpeg" data-w="1280" style=""></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">数据上传完了后,大小 1.19M,跟我们设想的一样。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">计算公式:</span><span style="font-size: 16px;color: rgb(61, 170, 214);"> 10000000/8/1024/1024=1.19M</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>9、Java应用中,如何使用布隆过滤器?代码实例</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">J</span><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;">ava语言的生态非常繁荣,提供了很多开箱即用的开源框架供我们使用。布隆过滤器也不例外,Java 中提供了一个 </span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">Redisson</span></code><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;"> 的组件,它内置了布隆过滤器。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">首先引入依赖包</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">&lt;dependency&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;org.redisson&lt;/groupId&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;redisson&lt;/artifactId&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;3.11.1&lt;/version&gt;<br>&lt;/dependency&gt;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">代码示例:</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">/**<br>&nbsp;*&nbsp;@author 微信公众号:微观技术<br>&nbsp;*/<br>@Test<br>public&nbsp;void&nbsp;<span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">test5</span>()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;Config&nbsp;config&nbsp;=&nbsp;new&nbsp;Config();<br>&nbsp;&nbsp;&nbsp;&nbsp;config.useSingleServer().setAddress(<span style="color: #a6e22e;line-height: 26px;">"redis://172.16.67.37:6379"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;RedissonClient&nbsp;cient&nbsp;=&nbsp;Redisson.create(config);<br>&nbsp;&nbsp;&nbsp;&nbsp;RBloomFilter&lt;String&gt;&nbsp;bloomFilter&nbsp;=&nbsp;cient.getBloomFilter(<span style="color: #a6e22e;line-height: 26px;">"test5-bloom-filter"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;初始化布隆过滤器,数组长度100W,误判率&nbsp;1%<br>&nbsp;&nbsp;&nbsp;&nbsp;bloomFilter.tryInit(1000000L,&nbsp;0.01);<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;添加数据<br>&nbsp;&nbsp;&nbsp;&nbsp;bloomFilter.add(<span style="color: #a6e22e;line-height: 26px;">"Tom哥"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;判断是否存在<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(bloomFilter.contains(<span style="color: #a6e22e;line-height: 26px;">"微观技术"</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(bloomFilter.contains(<span style="color: #a6e22e;line-height: 26px;">"Tom哥"</span>));<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">运行结果:</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">false</span>&nbsp;&nbsp;&nbsp;//&nbsp;肯定不存在<br><span style="color: #f92672;font-weight: bold;line-height: 26px;">true</span>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;可能存在,有1%的误判率<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">注意:误判率设置过小,会产生更多次的 Hash 操作,降低系统的性能。通常我们的建议值是 1%</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>10、布隆过滤器二进制数组,如何处理删除?</strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">初始化后的布隆过滤器,可以直接拿来使用了。但是如果原始数据删除了怎么办?布隆过滤器二进制数组如何维护?</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">直接删除不行吗?</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">还真不行!因为这里面有Hash冲突的可能,会导致误删。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">怎么办?</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;">方案1:开发定时任务,每隔几个小时,自动创建一个新的布隆过滤器数组,替换老的,有点</span><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span style="font-size: 16px;">CopyOnWriteArrayList</span></code><span style="font-size: 16px;">的味道</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="font-size: 16px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">方案2:布隆过滤器增加一个等长的数组,存储计数器,主要解决冲突问题,每次删除时对应的计数器减一,如果结果为0,更新主数组的二进制值为0</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong><br></strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(255, 104, 39);"><strong>11、布隆过滤器的应用场景</strong></span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 本文重点介绍的,解决缓存穿透 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 网页爬虫对URL的去重,避免爬取相同的URL地址 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱 </section></li> </ul> </section> <p><br></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="Mzg2NzYyNjQzNg==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/2KTof9YshwdmOC0H6kaQlnh3rvWF2hPpzBoAoibbfQkhLdXfEpQgd8frHoDJDH503rv3FaMK6las2rCNQY7icr6w/0?wx_fmt=png" data-nickname="微观技术" data-alias="weiguanjishu" data-signature="前阿里架构师,研究生,CSDN博客专家。负责过电商交易、社区团购、流量营销等业务。分享后端架构技能、一线大厂面试经验、团队管理等话题。欢迎关注" data-from="0"></mpprofile> </section>

聊聊前后端分离接口规范

作者:微信小助手

<section style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"> <br> </section> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA3ODIxNjYxNQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/Baq5lYpIw7WIvzVfHZ61VvJoaTzb7HDxtsJoicXicBJJ5uc9FrPG3eVztG6eBfUfdwIYmoqu8ibM5APCTDBUBPLrg/0?wx_fmt=png" data-nickname="架构文摘" data-alias="ArchDigest" data-signature="每天一篇架构领域重磅好文,涉及一线互联网公司应用架构(高可用、高性能、高稳定)、大数据、机器学习、Java架构等各个热门领域。" data-from="0"></mpprofile> </section> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(136, 136, 136);font-family: Optima-Regular, PingFangTC-light;font-size: 10px;letter-spacing: 0.544px;text-align: left;">原文:</span><span style="color: rgb(136, 136, 136);font-family: Optima-Regular, PingFangTC-light;font-size: 10px;letter-spacing: 0.544px;text-align: left;">www.jianshu.com/p/c81008b68350</span><br></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;">1、前言</span></strong></span> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 随着互联网的高速发展,前端页面的展示、交互体验越来越灵活、炫丽,响应体验也要求越来越高,后端服务的高并发、高可用、高性能、高扩展等特性的要求也愈加苛刻,从而导致前后端研发各自专注于自己擅长的领域深耕细作。 </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 然而带来的另一个问题:前后端的对接界面双方却关注甚少,没有任何接口约定规范情况下各自干各自的,导致我们在产品项目开发过程中,前后端的接口联调对接工作量占比在30%-50%左右,甚至会更高。往往前后端接口联调对接及系统间的联调对接都是整个产品项目研发的软肋。 </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 本文的主要初衷就是规范约定先行,尽量避免沟通联调产生的不必要的问题,让大家身心愉快地专注于各自擅长的领域。 </section> <h2 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2、为何要分离</strong></span></h2> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 参考两篇文章: </section> <blockquote style="padding: 10px 15px 10px 1rem;border-left-width: 6px;border-left-color: rgb(220, 230, 240);color: rgb(62, 62, 62);font-size: 0.8em;max-width: 100%;overflow-wrap: normal;letter-spacing: 0.544px;white-space: normal;line-height: inherit;background: rgb(242, 247, 251);overflow: auto;word-break: normal;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: start;box-sizing: border-box !important;"> <section style="max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> http://blog.jobbole.com/65509/ <br style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">http://blog.jobbole.com/56161/ </section> </blockquote> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 目前现有前后端开发模式:“后端为主的MVC时代”,如下图所示: </section> <section style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.6518518518518519" src="/upload/d4bcf00b121ecab94dbf8ca8aa4fdc2d.jpg" data-type="jpeg" data-w="540" style="border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 352.696px !important;width: 540px !important;"> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(150, 150, 150);font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">后端为主的MVC时代</span> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 代码可维护性得到明显好转,MVC 是个非常好的协作模式,从架构层面让开发者懂得什么代码应该写在什么地方。为了让 View 层更简单干脆,还可以选择 Velocity、Freemaker 等模板,使得模板里写不了 Java 代码。 </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 看起来是功能变弱了,但正是这种限制使得前后端分工更清晰。然而依旧并不是那么清晰,这个阶段的典型问题是: </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">前端开发重度依赖开发环境,开发效率低。</strong> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 这种架构下,前后端协作有两种模式:一种是前端写demo,写好后,让后端去套模板 。淘宝早期包括现在依旧有大量业务线是这种模式。好处很明显,demo 可以本地开发,很高效。不足是还需要后端套模板,有可能套错,套完后还需要前端确定,来回沟通调整的成本比较大。 </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 另一种协作模式是前端负责浏览器端的所有开发和服务器端的 View 层模板开发,支付宝是这种模式。好处是 UI 相关的代码都是前端去写就好,后端不用太关注,不足就是前端开发重度绑定后端环境,环境成为影响前端开发效率的重要因素。 </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">前后端职责依旧纠缠不清。</strong> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> Velocity 模板还是蛮强大的,变量、逻辑、宏等特性,依旧可以通过拿到的上下文变量来实现各种业务逻辑。这样,只要前端弱势一点,往往就会被后端要求在模板层写出不少业务代码。还有一个很大的灰色地带是 Controller,页面路由等功能本应该是前端最关注的,但却是由后端来实现。Controller 本身与 Model 往往也会纠缠不清,看了让人咬牙的业务代码经常会出现在 Controller 层。这些问题不能全归结于程序员的素养,否则 JSP 就够了。 </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">对前端发挥的局限。</strong> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 性能优化如果只在前端做空间非常有限,于是我们经常需要后端合作才能碰撞出火花,但由于后端框架限制,我们很难使用Comet、Bigpipe等技术方案来优化性能。 </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 总上所述,就跟为什麽要代码重构一样: </section> <ul class="list-paddingleft-2" style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">关注点分离</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">职责分离</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">对的人做对的事</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">更好的共建模式</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">快速的反应变化</span> <span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section></li> </ul> <h2 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></h2> <h2 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;">3、什么是分离</span></strong></span></h2> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 我们现在要做的前后分离第一阶段:“基于 Ajax 带来的 SPA 时代”,如图: </section> <section style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.7044609665427509" src="/upload/f53254c1b57a3b5982f3dc894070f364.jpg" data-type="jpeg" data-w="538" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 538px !important;visibility: visible !important;"> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(150, 150, 150);font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">基于 Ajax 带来的 SPA 时代</span> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 这种模式下,前后端的分工非常清晰,前后端的关键协作点是 Ajax 接口。看起来是如此美妙,但回过头来看看的话,这与 JSP 时代区别不大。复杂度从服务端的 JSP 里移到了浏览器的 JavaScript,浏览器端变得很复杂。类似 Spring MVC,这个时代开始出现浏览器端的分层架构: </section> <section style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.6962962962962963" src="/upload/29daa5bbf55657765b4265843517fa2c.jpg" data-type="jpeg" data-w="540" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 540px !important;visibility: visible !important;"> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(150, 150, 150);font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">浏览器端的分层架构</span> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 对于这一SPA阶段,前后端分离有几个重要挑战: </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">前后端接口的约定。</strong> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 如果后端的接口一塌糊涂,如果后端的业务模型不够稳定,那么前端开发会很痛苦。这一块在业界有 API Blueprint 等方案来约定和沉淀接口,==在阿里,不少团队也有类似尝试,通过接口规则、接口平台等方式来做。有了和后端一起沉淀的接口规则,还可以用来模拟数据,使得前后端可以在约定接口后实现高效并行开发。== 相信这一块会越做越好。 </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">前端开发的复杂度控制。</strong> </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> SPA 应用大多以功能交互型为主,JavaScript 代码过十万行很正常。大量 JS 代码的组织,与 View 层的绑定等,都不是容易的事情。典型的解决方案是业界的 Backbone,但 Backbone 做的事还很有限,依旧存在大量空白区域需要挑战。 </section> <h2 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4、如何做分离</span></strong></span></h2> <h3 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></h3> <h3 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">4.1 职责分离</strong></span></h3> <section style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.5712121212121212" src="/upload/407cae3bd0b5442a216509edbf3d9090.jpg" data-type="jpeg" data-w="660" style="border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 377.858px !important;visibility: visible !important;width: 660px !important;"></span> </section> <section style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(150, 150, 150);font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">职责分离</span></span> </section> <section style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <ul class="list-paddingleft-2" style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">前后端仅仅通过异步接口(AJAX/JSONP)来编程</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">前后端都各自有自己的开发流程,构建工具,测试集合</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">关注点分离,前后端变得相对独立并松耦合</span> </section></li> </ul> <section style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.2807807807807808" data-s="300,640" src="/upload/3bfe33545265a0db15d7c4ca4eea68f5.png" data-type="png" data-w="666" style="border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 188.438px !important;width: 666px !important;"></p> <h3 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">4.2 开发流程</strong></span></h3> <ul class="list-paddingleft-2" style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);list-style-type: square;overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">后端编写和维护接口文档,在 API 变化时更新接口文档</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">后端根据接口文档进行接口开发</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">前端根据接口文档进行开发 + Mock平台</span> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;min-height: 1em;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: inherit;line-height: inherit;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">开发完成后联调和提交测试</span> <span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section></li> </ul> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> Mock 服务器根据接口文档自动生成 Mock 数据,实现了接口文档即API: </section> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;min-height: 1em;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.269" src="/upload/f28703f7d9b1fdceb4b96da0d789820a.jpg" data-type="jpeg" data-w="1000" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 677px !important;"> </section> <section style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);min-height: 1em;text-align: center;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(150, 150, 150);font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">开发流程</span> </section> <h3 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">4.3 具体实施</strong></span></h3> <section style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;letter-spacing: 0.544

Java 性能优化的 50 个细节(珍藏版)

作者:微信小助手

<p style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2em;"><span style="font-size: 15px;">在JAVA程序中,性能问题的大部分原因并不在于JAVA语言,而是程序本身。养成良好的编码习惯非常重要,能够显著地提升程序性能。</span><br></p> <p line="QNTA" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="eHsx" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>1. 尽量在合适的场合使用单例</strong></span></p> <p line="Wu8C" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例</span></p> <p line="Wu8C" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="Wu8C" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">简单来说,单例主要适用于以下三个方面:</span></p> <p line="Wu8C" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <ol class="list-paddingleft-2" style="padding-left: 30px;width: 552.891px;font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;"> <li><p line="QIgM" linespacing="115" style="letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">控制资源的使用,通过线程同步来控制资源的并发访问;</span></p></li> <li><p line="VJps" linespacing="115" style="letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">控制实例的产生,以达到节约资源的目的;</span></p></li> <li><p line="Xadb" linespacing="115" style="letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。</span></p></li> </ol> <p line="Xadb" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="V9Vj" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>2. 尽量避免随意使用静态变量</strong></span></p> <p line="Bb4g" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">当某个对象被定义为static变量所引用,那么GC通常是不会回收这个对象所占有的内存,如:</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <pre style="margin-top: 0.5em;margin-bottom: 0.5em;padding: 0.4em 0.6em;border-radius: 8px;background: none;"><code style="margin-right: 0.15em;margin-left: 0.15em;padding: 6px;border-radius: 4px;font-size: 0.85em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;overflow-x: auto;white-space: nowrap;"><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;">public</span>&nbsp;<span style="background: rgba(0, 0, 0, 0);display: inline;width: 46px;"><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);background: rgba(0, 0, 0, 0);display: inline;width: 6px;">A</span></span>{<br><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;">&nbsp; private</span>&nbsp;<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;">static</span>&nbsp;B b =&nbsp;<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 20px;">new</span>&nbsp;B();<br>}</code></pre> </section> <p line="Bb4g" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">此时静态变量 b 的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。</span></p> <p line="Bb4g" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="DrkO" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>3. 尽量避免过多过常地创建Java对象</strong></span></p> <p line="6mrg" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理</span></p> <p line="6mrg" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="6mrg" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">在我们可以控制的范围内,最大限度地重用对象,最好能用基本的数据类型或数组来替代对象。</span></p> <p line="6mrg" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="KbEd" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>4. 尽量使用final修饰符</strong></span></p> <p line="mGfx" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">带有final修饰符的类是不可派生的。在JAVA核心API中,有许多应用final的例子,例如java、lang、String,为String类指定final防止了使用者覆盖length()方法。</span></p> <p line="mGfx" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="mGfx" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">另外,如果一个类是final的,则该类所有方法都是final的。java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关),此举能够使性能平均提高50%。</span></p> <p line="mGfx" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="irHB" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">如:让访问实例内变量的getter/setter方法变成”final:</span><span style="font-size: 15px;letter-spacing: 0.544px;">简单的getter/setter方法应该被置成final,这会告诉编译器,这个方法不会被重载,所以,可以变成”inlined”,例子:</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <pre style="margin-top: 0.5em;margin-bottom: 0.5em;padding: 0.4em 0.6em;border-radius: 8px;background: none;"><code style="margin-right: 0.15em;margin-left: 0.15em;padding: 6px;border-radius: 4px;font-size: 0.85em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;overflow-x: auto;white-space: nowrap;"><span style="background: rgba(0, 0, 0, 0);display: inline;width: 66px;"><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);background: rgba(0, 0, 0, 0);display: inline;width: 20px;">MAF</span>&nbsp;</span>{<br><span style="background: rgba(0, 0, 0, 0);display: inline;width: 204px;"><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 39px;">&nbsp; public</span>&nbsp;<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 46px;">setSize</span>&nbsp;<span style="background: rgba(0, 0, 0, 0);display: inline;width: 66px;">(<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 20px;">int</span>&nbsp;size)</span>&nbsp;</span>{<br>&nbsp; &nbsp; _size = size;<br>&nbsp; }<br><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;">&nbsp; private</span>&nbsp;<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 19px;">int</span>&nbsp;_size;<br>}<br><br>更正<br><span style="background: rgba(0, 0, 0, 0);display: inline;width: 105px;"><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);background: rgba(0, 0, 0, 0);display: inline;width: 60px;">DAF_fixed</span>&nbsp;</span>{<br><span style="background: rgba(0, 0, 0, 0);display: inline;width: 244px;"><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 33px;">&nbsp; final</span>&nbsp;<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 40px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 46px;">setSize</span>&nbsp;<span style="background: rgba(0, 0, 0, 0);display: inline;width: 66px;">(<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 20px;">int</span>&nbsp;size)</span>&nbsp;</span>{<br>&nbsp; &nbsp; _size = size;<br>&nbsp; }<br><span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 46px;">&nbsp; private</span>&nbsp;<span style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 19px;">int</span>&nbsp;_size;<br>}</code></pre> </section> <p style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;"><br></p> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="KUFn" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>5. 尽量使用局部变量</strong></span></p> <p line="Iqg9" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快;其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。</span></p> <p line="Iqg9" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="rlG8" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>6. 尽量处理好包装类型和基本类型两者的使用场所</strong></span></p> <p line="Wxp7" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">虽然包装类型和基本类型在使用过程中是可以相互转换,但它们两者所产生的内存区域是完全不同的</span></p> <p line="Wxp7" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="Wxp7" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">基本类型数据产生和处理都在栈中处理,包装类型是对象,是在堆中产生实例。在集合类对象,有对象方面需要的处理适用包装类型,其他的处理提倡使用基本类型。</span></p> <p line="Wxp7" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="Brwd" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>7. 慎用synchronized,尽量减小synchronize的方法</strong></span></p> <p line="p9oA" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">都知道,实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。</span></p> <p line="p9oA" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="p9oA" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">synchronize方法被调用时,直接会把当前对象锁了,在方法执行完之前其他线程无法调用当前对象的其他方法。</span></p> <p line="p9oA" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="p9oA" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">所以,synchronize的方法尽量减小,并且应尽量使用方法同步代替代码块同步。</span></p> <p line="p9oA" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="K76B" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>9. 尽量不要使用finalize方法</strong></span></p> <p line="OjSF" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">实际上,将资源清理放在finalize方法中完成是非常不好的选择</span></p> <p line="OjSF" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="OjSF" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">由于GC的工作量很大,尤其是回收Young代内存时,大都会引起应用程序暂停,所以再选择使用finalize方法进行资源清理,会导致GC负担更大,程序运行效率更差。</span></p> <p line="OjSF" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"><span style="font-size: 15px;"><strong>10. 尽量使用基本数据类型代替对象</strong></span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <pre style="margin-top: 0.5em;margin-bottom: 0.5em;padding: 0.4em 0.6em;border-radius: 8px;background: none;"><br><span style="font-size: 14px;">String&nbsp;str&nbsp;=&nbsp;"hello";<br></span></pre> </section> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">上面这种方式会创建一个“hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <pre style="margin-top: 0.5em;margin-bottom: 0.5em;padding: 0.4em 0.6em;border-radius: 8px;background: none;"><br><span style="font-size: 14px;">String&nbsp;str&nbsp;=&nbsp;new&nbsp;String("hello");<br></span></pre> </section> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;letter-spacing: 0.544px;">此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o</span><br></p> <p line="XHUC" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="et5N" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>11. 多线程在未发生线程安全前提下应尽量使用HashMap、ArrayList</strong></span></p> <p line="OUga" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">HashTable、Vector等使用了同步机制,降低了性能。</span></p> <p line="OUga" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="4y1F" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>12. 尽量合理的创建HashMap</strong></span></p> <p line="w1wF" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">当你要创建一个比较大的hashMap时,充分利用这个构造函数</span></p> <p line="w1wF" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="w1wF" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="background-color: initial;letter-spacing: 0.544px;font-size: 12px;">public&nbsp;HashMap(int&nbsp;initialCapacity,&nbsp;float&nbsp;loadFactor);</span></p> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;letter-spacing: 0.544px;">避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事</span></p> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;letter-spacing: 0.544px;">在默认中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大小,同样的Hashtable,Vectors也是一样的道理。</span><br></p> <p line="RsIh" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="v6hn" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;"><strong>13. 尽量减少对变量的重复计算</strong></span></p> <p line="p6p3" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="p6p3" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">如:</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <pre style="margin-top: 0.5em;margin-bottom: 0.5em;padding: 0.4em 0.6em;border-radius: 8px;background: none;"><span style="font-size: 14px;">for(int&nbsp;i=0;i&lt;list.size();i++)</span><br></pre> </section> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;">应该改为:</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <pre style="margin-top: 0.5em;margin-bottom: 0.5em;padding: 0.4em 0.6em;border-radius: 8px;background: none;"><span style="font-size: 14px;">for(int&nbsp;i=0,len=list.size();i&lt;len;i++)<br></span></pre> </section> <p line="69Nz" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><span style="font-size: 15px;letter-spacing: 0.544px;">并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。</span><br></p> <p line="mSaS" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 2;"><br></p> <p line="8TGA" linespacing="115" style="font-family: 默认, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;letter-

漫画:Object类很大,你忍一下(完结篇)

作者:微信小助手

<p data-mpa-powered-by="yiban.io"><span style="font-size: 18px;">在上一篇当中,我们提及了Java语言Object类的九大方法,并重点讲解了其中的getClass(),finalize(),toString(),equals(),hashcode()。</span><br></p> <p><span style="font-size: 18px;"><br></span></p> <p style=""><span style="font-size: 18px;">没看过的小伙伴,可以点击阅读上一篇:</span><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&amp;mid=2653230744&amp;idx=1&amp;sn=f713c92f58d200b1f830cb34381a55de&amp;chksm=8c986442bbefed542d77cef64d660cdb88c068e7ef6e77960d998aad7bb4933fce48d82d1c7c&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 18px;" data-linktype="2"><span style="font-size: 18px;">漫画:Object类很大,你忍一下</span></a></p> <p style=""><br></p> <p style=""><span style="font-size: 18px;">这一次,我们来重点讲解 wait(),notify(),notifyAll() 这三大方法。</span></p> <p><span style="font-size: 18px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/315574ec09d5efbefc27d065c4935137.png" data-type="png" data-w="678" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/833360098ad03f8ea19704f48d53f9f1.png" data-type="png" data-w="670" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/924b7eb41c57faeab23987031e2b1ef.png" data-type="png" data-w="678" style=""></p> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/baffc9d37221541f1e2fdd4bf8dfd3ec.png" data-type="png" data-w="670" style=""></p> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5895522388059702" data-s="300,640" src="/upload/f157ab999332d421f514cb3d9afd75d8.png" data-type="png" data-w="670" style=""></p> <p><span style="font-size:16px;font-family:微软雅黑,sans-serif;"><br></span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(240, 240, 240);color: rgb(68, 68, 68);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;执行这个方法后,持有此对象监视器的线程会进入等待队列,同时释放锁</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;如果不在synchronized修饰的方法或代码块里调用,则会抛出IllegalMonitorStateException&nbsp;异常</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;如果当前线程在等待时被中断,则抛出InterruptedException异常</span><br><span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">final</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">wait</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">()</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">throws</span>&nbsp;InterruptedException&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;wait(<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>);<br>}<br><br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;timeout是线程等待时间,时间结束则自动唤醒,单位ms</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;Java默认的实现方式,native实现</span><br><span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">final</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">native</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">wait</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">(<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">long</span>&nbsp;timeout)</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">throws</span>&nbsp;InterruptedException</span>;<br><br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;nanos是更精确的线程等待时间,单位ns(<strong>1&nbsp;ms&nbsp;=&nbsp;1,000,000&nbsp;ns</strong>)</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;Java默认的实现方式</span><br><span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">final</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">wait</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">(<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">long</span>&nbsp;timeout,&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;nanos)</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">throws</span>&nbsp;InterruptedException&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(timeout&nbsp;&lt;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">throw</span>&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;IllegalArgumentException(<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">"timeout&nbsp;value&nbsp;is&nbsp;negative"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(nanos&nbsp;&lt;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>&nbsp;||&nbsp;nanos&nbsp;&gt;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">999999</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">throw</span>&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;IllegalArgumentException(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">"nanosecond&nbsp;timeout&nbsp;value&nbsp;out&nbsp;of&nbsp;range"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(nanos&nbsp;&gt;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout++;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;wait(timeout);<br>}<br></code></pre> </section> <p><br></p> <p><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/e684bbff4cb92354e314b7a71cba2b97.png" data-type="png" data-w="670" style="text-align: center;"></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/70f403c3d5bfd8fb5284fdd1ca50e6ac.png" data-type="png" data-w="670" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/2e75243a554dfcff0ff22a022c58d591.png" data-type="png" data-w="670" style=""></p> <p><br></p> <p style=""><span style="font-size: 18px;">含参数的wait()方法调用以后,线程可以在等待时间结束后被唤醒;无参的wait()方法调用后,则必须等待持有该对象监视器的线程主动调用notify()或notifyAll()方法后才能被唤醒。</span></p> <p style=""><span style="font-size: 18px;"><br></span></p> <p style=""><span style="font-size: 18px;">两者之间的区别,在于notify()方法唤醒在此对象监视器上等待的<strong>单个线程</strong>,而notifyAll()方法则唤醒在此对象监视器上等待的<strong>所有线程</strong>。</span><br></p> <p style=""><span style="font-size: 18px;">&nbsp;</span></p> <p style=""><span style="font-size: 18px;">与wait方法一样,执行notify方法的线程也必须提前获取锁。需要注意的是,被notify方法唤醒的线程并不会立即执行,因为要等调用notify方法的线程释放锁之后才会获取到锁。</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/5f6fb5e11ff07ee13e1706256eca0be7.png" data-type="png" data-w="670" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/e92f3caa52b64f2b76ef03e25052c2be.png" data-type="png" data-w="670" style=""></p> <p><br></p> <p style=""><span style="font-size: 18px;">有的Java虚拟机(VM)会选择最先调用wait方法的线程,也有的则会随机选择一个线程。尽管notify方法的处理速度比notifyAll方法更快,但使用notifyAll方法更为稳妥。</span></p> <p style=""><span style="font-size: 18px;"><br></span></p> <p style=""><span style="font-size: 18px;">notify与notifyAll的方法声明如下:</span></p> <p><br></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(240, 240, 240);color: rgb(68, 68, 68);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">final</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">native</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">notify</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">()</span></span>;<br><span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">final</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">native</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">notifyAll</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">()</span></span>;</code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/dae6aaca8a65581298c29f59425fe047.png" data-type="png" data-w="678" style=""></p> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/f87093cf0d92c0134d179d38b6aa7ecd.png" data-type="png" data-w="678" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/5fbd6211321f949a12df2b10c2c7543d.png" data-type="png" data-w="678" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/98044039ea4a54d2c4035cb21757ff72.png" data-type="png" data-w="670" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/ab2d0890ee16acf5ec96aa7df04a7ccb.png" data-type="png" data-w="670" style=""></p> <p><br></p> <p><br></p> <p style=""><span style="font-size: 18px;">有一家公司开始想要招聘程序员,于是面试了几名候选人:</span><br></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5082236842105263" data-s="300,640" src="/upload/4734c05d799877ecb88117d644795f98.png" data-type="png" data-w="608" style="width: 476px;height: 242px;"></p> <p><br></p> <p><br></p> <p style=""><span style="font-size: 18px;">但公司录用程序员的时间是不确定的,需要综合考虑,无法给出及时反馈。于是告诉他们回去等通知。</span></p> <p style=""><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5024390243902439" data-s="300,640" src="/upload/cf2b0dc181b50285d5975973edcc8023.png" data-type="png" data-w="615" style="width: 457px;height: 230px;"></p> <p style=""><br></p> <p style=""><span style="font-size: 18px;">经过事后的比较和研究,面试官觉得大黄是招聘的最佳人选,于是让HR小姐姐通知大黄,也就是“唤醒”了大黄:</span></p> <p style=""><span style="font-size: 18px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5016666666666667" data-s="300,640" src="/upload/ff4447015c18a63e0dfe2ee4bfbefff0.png" data-type="png" data-w="600" style="width: 470px;height: 236px;"></p> <p style=""><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/24590bdb3629513091cf2e121ed65dd0.png" data-type="png" data-w="678" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/408c97c57db8e973ac86271855e6f5c2.png" data-type="png" data-w="678" style=""></p> <p><br></p> <p><br></p> <p><span style="font-family: 微软雅黑, sans-serif;font-size: 16px;color: rgb(122, 79, 214);">(1)wait()、notify()和notifyAll()必须在synchronized修饰的方法或代码块中使用。</span></p> <p><span style="font-family: 微软雅黑, sans-serif;font-size: 16px;color: rgb(122, 79, 214);">(2)在while循环里而不是if语句下使用wait(),确保在线程睡眠前后都检查wait()触发的条件(防止虚假唤醒)。</span></p> <p><span style="font-family: 微软雅黑, sans-serif;font-size: 16px;color: rgb(122, 79, 214);">(3)wait()方法必须在多线程共享的对象上调用。</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/60826c55c2304857bc57c27c16d08578.png" data-type="png" data-w="670" style=""></p> <p><span style="font-size:16px;font-family:微软雅黑,sans-serif;">&nbsp;</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/97d68df7ed1c2b2bf060adde9040b772.png" data-type="png" data-w="670" style=""></p> <p><br></p> <p style=""><span style="font-size: 18px;">生产者/消费者模型能解决绝大多数并发问题,通过平衡生产线程和消费线程的工作能力,来提高程序的整体处理数据的速度。<br></span></p> <p style=""><br></p> <p style=""><span style="font-size: 18px;">生产者线程和消费者线程的处理速度差异,会引起消费者想要获取数据时,数据还没生成或者生产者想要交付数据,却没有消费者接收的问题。对于这样的问题,生产者/消费者模型可以消除这</span><span style="font-size: 18px;">个差异。</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5870206489675516" data-s="300,640" src="/upload/256d550e14017c5d08583606c6b8a390.png" data-type="png" data-w="678" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5870206489675516" data-s="300,640" src="/upload/eccf9fc1b3552193ad8eed6fab0f7b3c.png" data-type="png" data-w="678" style=""></p> <p><br></p> <p style=""><span style="font-size: 18px;">首先,按照注意事项(1)和(2)的要求,定义一个生产者,往队列里添加元素:</span></p> <p><span style="font-size:16px;font-family:微软雅黑,sans-serif;"><br></span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(240, 240, 240);color: rgb(68, 68, 68);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;生产者,有详细的注释</span><br><span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">class</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">Producer</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">implements</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">Runnable</span></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">private</span>&nbsp;Queue&lt;Integer&gt;&nbsp;queue;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">private</span>&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;maxSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">Producer</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">(Queue&lt;Integer&gt;&nbsp;queue,&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;maxSize)</span></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.queue&nbsp;=&nbsp;queue;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.maxSize&nbsp;=&nbsp;maxSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(31, 113, 153);overflow-wrap: inherit !important;word-break: inherit !important;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">run</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;这里为了方便演示做了一个死循环,现实开发中不要这样搞</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">true</span>){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//(1)wait()、notify()和notifyAll()必须在synchronized修饰的方法或代码块中使用</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">synchronized</span>&nbsp;(queue){<br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;"> //(2)在while循环里而不是if语句下使用wait(),确保在线程睡眠前后都检查wait()触发的条件(防止虚假唤醒)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(queue.size()&nbsp;==&nbsp;maxSize){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">try</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">"Queue&nbsp;is&nbsp;Full"</span>);<br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;"> //&nbsp;生产者线程进入等待状态,在此对象监视器上等待的所有线程(其实只有那个消费者线程)开始争夺锁</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.wait();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">catch</span>&nbsp;(InterruptedException&nbsp;ie){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ie.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Random&nbsp;random&nbsp;=&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Random();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;i&nbsp;=&nbsp;random.nextInt();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">"Produce&nbsp;"</span>&nbsp;+&nbsp;i);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.add(i);<br><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;"> //&nbsp;唤醒这个Queue对象的等待池中的所有线程(其实只有那个消费者线程),等待获取对象监视器</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.notifyAll();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> </section> <p><br></p> <p><span style="font-size:16px;font-family:微软雅黑,sans-serif;"><span style="font-size: 18px;">接下来,</span></span><span style="font-family: 微软雅黑, sans-serif;font-size: 18px;">再定义一个与之类似的消费者类</span><span style="font-family: 微软雅黑, sans-serif;font-size: 18px;">,除了从队列里移除元素的逻辑之外,整体代码大同小异:</span></p> <p><span style="font-family: 微软雅黑, sans-serif;font-size: 18px;"><br></span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(240, 240, 240);color: rgb(68, 68, 68);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;消费者类</span><br><span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">class</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">Consumer</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">implements</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">Runnable</span></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">private</span>&nbsp;Queue&lt;Integer&gt;&nbsp;queue;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">private</span>&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;maxSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">Consumer</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">(Queue&lt;Integer&gt;&nbsp;queue,&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;maxSize)</span></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.queue&nbsp;=&nbsp;queue;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.maxSize&nbsp;=&nbsp;maxSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(31, 113, 153);overflow-wrap: inherit !important;word-break: inherit !important;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">run</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">true</span>){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">synchronized</span>&nbsp;(queue){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">while</span>&nbsp;(queue.isEmpty()){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">"Queue&nbsp;is&nbsp;Empty"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">try</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.wait();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">catch</span>&nbsp;(InterruptedException&nbsp;ie){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ie.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;v&nbsp;=&nbsp;queue.remove();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">"Consume&nbsp;"</span>&nbsp;+&nbsp;v);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.notifyAll();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> </section> <p><br></p> <p style=""><span style="font-family: 微软雅黑, sans-serif;font-size: 18px;">最后编写符合<span style="font-size: 18px;">注意事项</span>(3)的测试代码:</span></p> <p><br></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(240, 240, 240);color: rgb(68, 68, 68);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="line-height: inherit;color: rgb(136, 0, 0);font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">test</span><span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">()</span></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//(3)wait()方法必须在多线程共享的对象上调用</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;这个队列就是给消费者、生产者两个线程共享的对象</span><br>&nbsp;&nbsp;&nbsp;&nbsp;Queue&lt;Integer&gt;&nbsp;queue&nbsp;=&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;LinkedList&lt;&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;maxSize&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">5</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;Producer&nbsp;p&nbsp;=&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Producer(queue,&nbsp;maxSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;Consumer&nbsp;c&nbsp;=&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Consumer(queue,&nbsp;maxSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;pT&nbsp;=&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Thread(p);<br>&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;pC&nbsp;=&nbsp;<span style="font-size: inherit;color: inherit;line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Thread(c);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;生产者线程启动,获取锁</span><br>&nbsp;&nbsp;&nbsp;&nbsp;pT.start();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;消费者线程启动</span><br>&nbsp;&nbsp;&nbsp;&nbsp;pC.start();<br>}<br></code></pre> </section> <p><br></p> <p style=""><span style="font-family: 微软雅黑, sans-serif;font-size: 18px;">最终的查看运行结果如下:&nbsp;</span></p> <p><br></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(240, 240, 240);color: rgb(68, 68, 68);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">Produce&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1604006010</span><br>Produce&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1312202442</span><br>Produce&nbsp;-<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1478853208</span><br>Produce&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1460408111</span><br>Produce&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1802825495</span><br>Queue&nbsp;is&nbsp;Full<br>Consume&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1604006010</span><br>Consume&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1312202442</span><br>Consume&nbsp;-<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1478853208</span><br>Consume&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1460408111</span><br>Consume&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(136, 0, 0);overflow-wrap: inherit !important;word-break: inherit !important;">1802825495</span><br>Queue&nbsp;is&nbsp;Empty</code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/a9a1704845b4316184ffb7e3745a8b6f.png" data-type="png" data-w="670" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/18bbf80a9564a6acb14b004c12f64673.png" data-type="png" data-w="678" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5722713864306784" data-s="300,640" src="/upload/18bbf80a9564a6acb14b004c12f64673.png" data-type="png" data-w="678" style=""></p> <p><span style="font-size:16px;font-family:微软雅黑,sans-serif;"></span></p> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5615050651230101" data-s="300,640" src="/upload/92d11c933320cfc4b43d6b7ce11899e8.png" data-type="png" data-w="691" style=""></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5880597014925373" data-s="300,640" src="/upload/dee1041be6c021a9ae94630c885ae66f.png" data-type="png" data-w="670" style=""></p> <p><span style="font-size:16px;font-family:微软雅黑,sans-serif;"></span></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzIxMjE5MTE1Nw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/NtO5sialJZGrOaned81pMkwib5Voibzes9ibatWlia3ZiceXRbsEWCZbyeOdoQTP1b4licNGR2qbzfaicvstXFztqQJ0wg/0?wx_fmt=png" data-nickname="程序员小灰" data-alias="chengxuyuanxiaohui" data-signature="一群喜爱编程技术和算法的小仓鼠。" data-from="0"></mpprofile> </section>

10000 字讲清楚 Spring Boot 注解原理

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);" data-mpa-powered-by="yiban.io"> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA5MTU0OTY0Ng==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/zc3KLDBfJlmPt0J5PXYOoiaG8wsQPZrLevbxMZSfgQ0YypNYaicnbS0P9UicluuOySLSP4CjTcRUVHCZzYeXQ9WlA/0?wx_fmt=png" data-nickname="Java派" data-alias="javapai" data-signature="专注Java相关技术栈:Spring全家筒、Docker、k8s、Mysql、集群、微服务、中间件等知识。" data-from="0"></mpprofile> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 5px 4px 1em;"> 首先,先看SpringBoot的主配置类: </section> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@SpringBootApplication</span><br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">StartEurekaApplication</span><br></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">main</span><span style="line-height: 26px;">(String[]&nbsp;args)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SpringApplication.run(StartEurekaApplication<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>,&nbsp;<span style="color: #e6c07b;line-height: 26px;">args</span>)</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">点进@SpringBootApplication来看,发现@SpringBootApplication是一个组合注解。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Target</span>(ElementType.TYPE)<br><span style="color: #61aeee;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #61aeee;line-height: 26px;">@Documented</span><br><span style="color: #61aeee;line-height: 26px;">@Inherited</span><br><span style="color: #61aeee;line-height: 26px;">@SpringBootConfiguration</span><br><span style="color: #61aeee;line-height: 26px;">@EnableAutoConfiguration</span><br><span style="color: #61aeee;line-height: 26px;">@ComponentScan</span>(excludeFilters&nbsp;=&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #61aeee;line-height: 26px;">@Filter</span>(type&nbsp;=&nbsp;FilterType.CUSTOM,&nbsp;classes&nbsp;=&nbsp;TypeExcludeFilter<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@<span style="color: #e6c07b;line-height: 26px;">Filter</span>(<span style="color: #e6c07b;line-height: 26px;">type</span>&nbsp;</span>=&nbsp;FilterType.CUSTOM,&nbsp;classes&nbsp;=&nbsp;AutoConfigurationExcludeFilter<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)&nbsp;})<br><span style="color: #e6c07b;line-height: 26px;">public</span>&nbsp;@<span style="color: #e6c07b;line-height: 26px;">interface</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">SpringBootApplication</span>&nbsp;</span>{<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">首先我们先来看 @SpringBootConfiguration:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Target</span>({ElementType.TYPE})<br><span style="color: #61aeee;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #61aeee;line-height: 26px;">@Documented</span><br><span style="color: #61aeee;line-height: 26px;">@Configuration</span><br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">@interface</span>&nbsp;SpringBootConfiguration&nbsp;{<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可以看到这个注解除了元注解以外,就只有一个@Configuration,那也就是说这个注解相当于@Configuration,所以这两个注解作用是一样的,它让我们能够去注册一些额外的Bean,并且导入一些额外的配置。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">那@Configuration还有一个作用就是把该类变成一个配置类,不需要额外的XML进行配置。所以@SpringBootConfiguration就相当于@Configuration。进入@Configuration,发现@Configuration核心是@Component,说明Spring的配置类也是Spring的一个组件。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Target</span>({ElementType.TYPE})<br><span style="color: #61aeee;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #61aeee;line-height: 26px;">@Documented</span><br><span style="color: #61aeee;line-height: 26px;">@Component</span><br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">@interface</span>&nbsp;Configuration&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #61aeee;line-height: 26px;">@AliasFor</span>(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;annotation&nbsp;=&nbsp;Component<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span><br>&nbsp;&nbsp;&nbsp;&nbsp;)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #e6c07b;line-height: 26px;">String</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">value</span>()&nbsp;<span style="color: #e6c07b;line-height: 26px;">default</span>&nbsp;""</span>;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">继续来看下一个@EnableAutoConfiguration,这个注解是开启自动配置的功能。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Target</span>({ElementType.TYPE})<br><span style="color: #61aeee;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #61aeee;line-height: 26px;">@Documented</span><br><span style="color: #61aeee;line-height: 26px;">@Inherited</span><br><span style="color: #61aeee;line-height: 26px;">@AutoConfigurationPackage</span><br><span style="color: #61aeee;line-height: 26px;">@Import</span>({AutoConfigurationImportSelector<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>})<br><span style="color: #e6c07b;line-height: 26px;">public</span>&nbsp;@<span style="color: #e6c07b;line-height: 26px;">interface</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">EnableAutoConfiguration</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;ENABLED_OVERRIDE_PROPERTY&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"spring.boot.enableautoconfiguration"</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Class&lt;?&gt;[]&nbsp;exclude()&nbsp;<span style="color: #c678dd;line-height: 26px;">default</span>&nbsp;{};<br><br>&nbsp;&nbsp;&nbsp;&nbsp;String[]&nbsp;excludeName()&nbsp;<span style="color: #c678dd;line-height: 26px;">default</span>&nbsp;{};<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可以看到它是由 @AutoConfigurationPackage,@Import(EnableAutoConfigurationImportSelector.class)这两个而组成的,我们先说@AutoConfigurationPackage,他是说:让包中的类以及子包中的类能够被自动扫描到spring容器中。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Target</span>({ElementType.TYPE})<br><span style="color: #61aeee;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #61aeee;line-height: 26px;">@Documented</span><br><span style="color: #61aeee;line-height: 26px;">@Inherited</span><br><span style="color: #61aeee;line-height: 26px;">@Import</span>({Registrar<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>})<br><span style="color: #e6c07b;line-height: 26px;">public</span>&nbsp;@<span style="color: #e6c07b;line-height: 26px;">interface</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">AutoConfigurationPackage</span>&nbsp;</span>{<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">使用@Import来给Spring容器中导入一个组件 ,这里导入的是Registrar.class。来看下这个Registrar:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">Registrar</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">implements</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">ImportBeanDefinitionRegistrar</span>,&nbsp;<span style="color: #e6c07b;line-height: 26px;">DeterminableImports</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Registrar()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">registerBeanDefinitions</span><span style="line-height: 26px;">(AnnotationMetadata&nbsp;metadata,&nbsp;BeanDefinitionRegistry&nbsp;registry)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AutoConfigurationPackages.register(registry,&nbsp;(<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;AutoConfigurationPackages.PackageImport(metadata)).getPackageName());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;Set&lt;Object&gt;&nbsp;<span style="color: #61aeee;line-height: 26px;">determineImports</span><span style="line-height: 26px;">(AnnotationMetadata&nbsp;metadata)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;Collections.singleton(<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;AutoConfigurationPackages.PackageImport(metadata));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;

面试必备!TCP协议经典十五连问!

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: PingFangSC-Light;" data-mpa-powered-by="yiban.io"> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>前言<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">TCP协议是大厂面试必问的知识点。整理了15道非常经典的TCP面试题,希望大家都找到理想的offer呀</p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.43359375" data-s="300,640" src="/upload/1e1dee1e467a6ab21128d1f69443a0b6.png" data-type="png" data-w="1280" style=""></p> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <br> <strong style="font-weight: border;color: #0e88eb;"></strong> </section> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>1. &nbsp;讲下TCP三次握手流程<span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.3748326639892905" src="/upload/9ffdaaee5f5c98aaf307825bfbd20113.png" data-type="png" data-w="747" style="border-radius: 0px 0px 5px 5px;display: block;margin: 20px auto;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">开始客户端和服务器都处于CLOSED状态,然后服务端开始监听某个端口,进入LISTEN状态</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 第一次握手(SYN=1, seq=x),发送完毕后,客户端进入 SYN_SEND 状态 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服务器端进入 SYN_RCVD 状态。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 第三次握手(ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手,即可以开始数据传输。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>2.TCP握手为什么是三次,不能是两次?不能是四次?<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">TCP握手为什么是三次呢?为了方便理解,我们以谈恋爱为例子:两个人能走到一起,最重要的事情就是相爱,就是<strong style="font-weight: border;color: #0e88eb;">我爱你,并且我知道,你也爱我</strong>,接下来我们以此来模拟三次握手的过程:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="2.2149122807017543" src="/upload/73a37ab999f7e767843e625bea69a443.png" data-type="png" data-w="456" style="border-radius: 0px 0px 5px 5px;display: block;margin: 20px auto;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">为什么握手不能是两次呢?</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">如果只有两次握手,女孩子可能就不知道,她的那句<strong style="font-weight: border;color: #0e88eb;">我也爱你</strong>,男孩子是否<strong style="font-weight: border;color: #0e88eb;">收到</strong>,恋爱关系就不能愉快展开。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">为什么握手不能是四次呢?</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">因为握手不能是四次呢?因为三次已经够了,三次已经能让双方都知道:你爱我,我也爱你。而四次就多余了。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>3. 讲下TCP四次挥手过程<span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.0821643286573146" src="/upload/c834468d7a0264979e7db2419242999.png" data-type="png" data-w="998" style="border-radius: 0px 0px 5px 5px;display: block;margin: 20px auto;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </figure> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 第一次挥手(FIN=1,seq=u),发送完毕后,客户端进入FIN_WAIT_1 状态 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 第二次挥手(ACK=1,ack=u+1,seq =v),发送完毕后,服务器端进入CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 第三次挥手(FIN=1,ACK1,seq=w,ack=u+1),发送完毕后,服务器端进入LAST_ACK 状态,等待来自客户端的最后一个ACK。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 第四次挥手(ACK=1,seq=u+1,ack=w+1),客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态, <strong style="font-weight: border;color: #0e88eb;">等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后</strong>,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 </section></li> </ol> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>4. TCP挥手为什么需要四次呢?<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">举个例子吧!</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <span style="font-size: 4em;font-family: Arial, serif;line-height: 1em;font-weight: 700;">★</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;display: inline;">小明和小红打电话聊天,通话差不多要结束时,小红说“我没啥要说的了”,小明回答“我知道了”。但是小明可能还会有要说的话,小红不能要求小明跟着自己的节奏结束通话,于是小明可能又叽叽歪歪说了一通,最后小明说“我说完了”,小红回答“知道了”,这样通话才算结束。</p> <span style="float: right;font-size: 3em;line-height: 1em;">”</span> </blockquote> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.7050243111831442" src="/upload/13fa768b9fe3755ac8e0c50137b45932.png" data-type="png" data-w="617" style="border-radius: 0px 0px 5px 5px;display: block;margin: 20px auto;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>5. TIME-WAIT 状态为什么需要等待 2MSL<span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.1179540709812108" src="/upload/3a2156feedcdfd75f0079daa6a212cb7.png" data-type="png" data-w="958" style="border-radius: 0px 0px 5px 5px;display: block;margin: 20px auto;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">2MSL,2 Maximum Segment Lifetime,即两个最大段生命周期</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> <span style="font-size: 4em;font-family: Arial, serif;line-height: 1em;font-weight: 700;">★</span> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 1个 MSL 保证四次挥手中主动关闭方最后的 ACK 报文能最终到达对端 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 1个 MSL 保证对端没有收到 ACK 那么进行重传的 FIN 报文能够到达 </section></li> </ul> <span style="float: right;font-size: 3em;line-height: 1em;">”</span> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>6.TCP 和 UDP 的区别<span style="display: none;"></span></h3> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> TCP面向连接((如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> TCP要求安全性,提供可靠的服务,通过TCP连接传送的数据,不丢失、不重复、安全可靠。而UDP尽最大努力交付,即不保证可靠交付。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> TCP是点对点连接的,UDP一对一,一对多,多对多都可以 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> TCP传输效率相对较低,而UDP传输效率高,它适用于对高速传输和实时性有较高的通信或广播通信。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> TCP适合用于网页,邮件等;UDP适合用于视频,语音广播等 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> TCP面向字节流,UDP面向报文 </section></li> </ol> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>7. TCP报文首部有哪些字段,说说其作用<span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.43208191126279866" src="/upload/78e35124b8c0ee1eb1c692ea9d4adbba.png" data-type="png" data-w="1465" style="border-radius: 0px 0px 5px 5px;display: block;margin: 20px auto;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">16位端口号</strong>:源端口号,主机该报文段是来自哪里;目标端口号,要传给哪个上层协议或应用程序 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">32位序号</strong>:一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">32位确认号</strong>:用作对另一方发送的tcp报文段的响应。其值是收到的TCP报文段的序号值加1。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">4位头部长度</strong>:表示tcp头部有多少个32bit字(4字节)。因为4位最大能标识15,所以TCP头部最长是60字节。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">6位标志位</strong>:URG(紧急指针是否有效),ACk(表示确认号是否有效),PSH(缓冲区尚未填满),RST(表示要求对方重新建立连接),SYN(建立连接消息标志接),FIN(表示告知对方本端要关闭连接了) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">16位窗口大小</strong>:是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">16位校验和</strong>:由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> <strong style="font-weight: border;color: #0e88eb;">16位紧急指针</strong>:一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>8. TCP 是如何保证可靠性的<span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.0267175572519085" src="/upload/3abf064c1e124f5bb863e0cdba229f6.png" data-type="png" data-w="262" style="border-radius: 0px 0px 5px 5px;display: block;margin: 20px auto;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 首先,TCP的连接是基于 <strong style="font-weight: border;color: #0e88eb;">三次握手</strong>,而断开则是 <strong style="font-weight: border;color: #0e88eb;">四次挥手</strong>。确保连接和断开的可靠性。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 其次,TCP的可靠性,还体现在 <strong style="font-weight: border;color: #0e88eb;">有状态</strong>;TCP会记录哪些数据发送了,哪些数据被接受了,哪些没有被接受,并且保证数据包按序到达,保证数据传输不出差错。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 再次,TCP的可靠性,还体现在 <strong style="font-weight: border;color: #0e88eb;">可控制</strong>。它有报文校验、ACK应答、 <strong style="font-weight: border;color: #0e88eb;">超时重传(发送方)</strong>、失序数据重传(接收方)、丢弃重复数据、流量控制(滑动窗口)和拥塞控制等机制。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>9. TCP 重传机制<span style="display: none;"></span></h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>超时重传<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">TCP 为了实现可靠传输,实现了重传机制。最基本的重传机制,就是<strong style="font-weight: border;color: #0e88eb;">超时重传</strong>,即在发送数据报文时,设定一个定时器,每间隔一段时间,没有收到对方的ACK确认应答报文,就会重发该报文。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">这个间隔时间,一般设置为多少呢?我们先来看下什么叫<strong style="font-weight: border;color: #0e88eb;">RTT(Round-Trip Time,往返时间)</strong>。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7700680272108843" src="/upload/58127f13b0237e2bd059a6dc3411e404.png" data-type="png" data-w="735" style="border-radius: 0px 0px 5px 5px;display: block;margin: 20px auto;width: 85%;height: 100%;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">RTT就是,一个数据包从发出去到回来的时间,即<strong style="font-weight: border;color: #0e88eb;">数据包的一次往返时间</strong>。超时重传时间,就是Retransmission Timeout ,简称<strong style="font-weight: border;color: #0e88eb;">RTO</strong>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">RTO设置多久呢?</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 如果RTO比较小,那很可能数据都没有丢失,就重发了,这会导致网络阻塞,会导致更多的超时出现。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 如果RTO比较大,等到花儿都谢了还是没有重发,那效果就不好了。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">一般情况下,RTO略大于RTT,效果是最好的。一些小伙伴会问,超时时间有没有计算公式呢?有的!有个标准方法算RTO的公式,也叫<strong style="font-weight: border;color: #0e88eb;">Jacobson / Karels 算法</strong>。我们一起来看下计算RTO的公式</p> <p data-tool="mdnice编辑�

消息幂等(去重)通用解决方案

作者:微信小助手

<section style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"> <br> </section> <p style="white-space: normal;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;text-align: left;"></span></strong>

分布式系统咋做同步?虐死人!

作者:微信小助手

<p style="white-space: normal;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;text-align: left;"></span></strong></span></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">分布式系统,通过数据冗余,来保证数据的安全。要写一个分布式系统,一道绕不过去的坎,那就是数据同步。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">同步,这两个字,折磨死了很多人。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">是同步,还是异步?是push,还是pull?谁是master,谁是slave?下线会怎样,上线了又会怎样?中心化,or对等节点?</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">这些问题,无一不拷打者分布式系统的设计者。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">下面,我们将看一下主流的几个存储服务,是如何解决数据同步问题的。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 23px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(123, 12, 0);">MySQL如何做主从同步?</span></h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">mysql的主服务器叫做master,从服务器叫做slave。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">主服务器将变更记录在binlog中,slave将通过独立的线程拷贝这些记录,然后重放。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">binlog的格式分为statement、row、mixed三种。</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> statement 将变更的sql语句写入到binlog中,在准确性方面会有一定影响 </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> row 将每一条记录的变化,写入到binlog中 </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> mixed 上面两种的结合。MySQL会判断什么时候有用statement,什么时候用row </section></li> </ul> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">由于是异步线程去拷贝,slave很容易会出现延迟。当master不幸宕机,将会造成延迟的数据丢失。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(89, 89, 89);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-ratio="0.42460796139927626" data-s="300,640" src="/upload/a117308e302da13a4eb3595a4a2b72f0.png" data-type="png" data-w="829" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> </figure> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了解决异步复制的问题,5.5版本之后,MySQL引入了半同步复制(semi &nbsp;sync)的概念。半同步处于异步和全量同步之间,master执行完事务之后,并不直接返回,而是要等待至少一个slave写入成功才返回。由于需要与至少一个slave进行交互,性能相比较异步复制肯定是有不少折损的。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">全复制模式当然是要等待所有的slave节点复制完成,这种安全性最高,但是效率也最低。从概念上来讲,只有一个slave的半复制就是全复制。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">5.7之后,mysql实现了组复制(group replication)协议。它支持单主模式和多主模式,但在同一个group内,不允许同时存在。听起还好像很神奇,其实它还是通过paxos协议去实现的。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 23px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(123, 12, 0);">Kafka如何做的副本同步?</span></h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">kafka由于是一个消息队列,所以不需要考虑随机删除和随机更新的问题,它只关注写入问题即可。从结构上来说,kafka的同步单元是非常分散的:kafka有多个topic,每个topic又分为多个partition,副本就是基于partiton去做的。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">主分区叫做leader,1-n个副本叫做follower。生产者在发送消息的时候,需要先找到该分区的leader,然后将数据发送给它。follower只是作为一个备份存在,以便在主分区发生问题时能够顶上去。</p> <p style="max-width: 100%;min-height: 1em;color: rgb(89, 89, 89);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-ratio="0.5287896592244419" data-s="300,640" src="/upload/db9cfe1cb2541d3beca869473841e427.jpg" data-type="jpeg" data-w="851" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">kafka的主从同步,叫做ISR(In Sync Replica)机制。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">那什么时候消息算是发送成功呢?这还要看ack的发送级别。</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">0</code>&nbsp;表示异步发送,消息发送完毕就算是成功了 </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">1</code>&nbsp;leader主副本写入完成,就算是发送成功了 </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">-1</code>&nbsp;leader发送完成,并且ISR中的副本都需要回复ack </section></li> </ul> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">0和1的情况下,kafka都有丢失消息的可能。在-1的情况下,也需要保证至少有一个follower commit成功才能保证消息安全。如果follower都不能追赶上leader,则会被移除出 ISR列表。没错,是直接移除。当ISR为空,则kafka的分区和单机是没有区别的,所以kafka提供了<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">min.insync.replicas</code>参数规定了最小ISR。</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 当ISR不满足的时候怎么办?kafka当然是不会丢失消息了,因为此时生产者的提交是失败的,消息根本进不了系统里来 </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 当所有副本都不可用怎么办?此时,该partition将永不可用 </section></li> </ul> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">副本之间的数据复制,是通过follower&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">pull</code>的方式,也就是拉取的方式去获取的。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 23px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(123, 12, 0);">Redis的主从复制</span></h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">redis是内存kv数据库,速度上远超其他数据库,理论上主从同步更容易。但在高流量和高QPS下,主从复制依然会发生问题。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">redis的slave连接上之后,首先会进行一次全量同步。它会发送psync命令到master,然后master执行bgsave生成一个rdb文件。全量同步就是复制这个rdb快照文件到slave。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">那在全量复制中间出现的数据怎么办呢?肯定是要缓存起来的。master会开启一个buffer,然后记录全量复制过程中产生的新数据,在全量同步完成之后再补齐增量数据。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">slave断线之后也不需要每次都执行全量同步,为了配合增量,还引入了复制偏移量<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">(offset)</code>、复制积压缓冲区<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">(replication backlog buffer)</code>和运行 ID&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">(run_id)</code>三个概念。可以看出它都是为了标识slave,以及它的复制位置和缓冲区用的。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(89, 89, 89);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-ratio="0.5209471766848816" data-s="300,640" src="/upload/684c95efe9bc14904eeaa356ee306324.png" data-type="png" data-w="549" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 549px !important;visibility: visible !important;"></p> </figure> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">之后的同步,就可以一直使用psync去复制。依然是异步复制。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">可以看出redis的主从复制一致性大量依赖内存,级别是非常弱的。但是它快。快能解决很多问题,所以应用场景是不同的。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 23px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(123, 12, 0);">ElasticSearch主从复制</span></h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">es是基于lucene的搜索引擎,数据节点会包含多个索引(index)。每个索引包含多个分片(shard),每个分片又包含多个replica(副本)。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">从上面的描述来看,这些概念是与kafka高度雷同的,es的复制单元是分片。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">es的数据依然是先写master,它同样维护了一个同步中的slave列表(InSyncAllocationIds),处于yellow和red状态的副本当然是不在这个列表中的。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">master需要等待所有这些正常的副本写入完成后,才返回给客户端,所以一致性级别是比较高的,因为它的slave节点是要参与读操作的,它是一个近实时系统。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">由于它是一个数据库,所以依然会有删除和更新操作。Translog相当于wal日志,保证了断电的数据安全,这和其他rdbms的套路是一致的。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 23px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(123, 12, 0);">Cassandra集群模式</span></h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">cassandra是一个非常有名的CAP理论实践数据库,更多的像一个AP数据库,目前在db-engines.com依然有较高的排名。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">数据存储是表的概念,一个表可以存储在多台机器上。它的分区,是通过partition key来设计的,数据分布非常依赖于hash函数。如果某个节点出现问题怎么办?那就需要一致性hash的支持。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">cassandra非常有意思,它的复制(replicas)并不像其他的主备数据一样,它更像是多份master数据,这些数据都是同时向外提供服务的。当掉一个检点,并不需要主备切换。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(89, 89, 89);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages wxw-img" data-ratio="0.6496551724137931" data-s="300,640" src="/upload/d6e87cd1e6b8e08ebeea2ec2651314e1.png" data-type="png" data-w="725" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> </figure> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">为什么可以做到这种程度呢?因为cassandra追求的是最终一致性。分布式系统由于副本的存在,不可避免的要异步或者同步复制。那到底复制到什么程度才算是合适的呢?<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">Quorum</code>的<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;overflow-wrap: break-word;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);box-sizing: border-box !important;">R+W</code>就是一个权衡策略。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 16px;max-width: 100%;overflow-x: auto;background: rgb(30, 30, 30);color: rgb(220, 220, 220);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;">quorum&nbsp;=&nbsp;(sum_of_replication_factors&nbsp;/&nbsp;2)&nbsp;+&nbsp;1<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">什么意思呢?考虑到你有5个抽屉,然后随机放入W个球,求需要多少次R,才能拿出一个球。假如你向里面放了1个球,你需要打开5次,才能每次都有正确的判断,此时R=5、W=1;当你放了2个球,则你只需要打开4次就可以了;假如你放入了5个球,那就只需要读一次。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">当R+W&gt;N的时候,属于强一致性;当R+W&lt;=N的时候,属于最终一致性。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">有意思的是,cassandra中的集群信息,即meta信息,使用gossip(push-pull-gossip)进行传递。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 23px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(123, 12, 0);">MongoDB主从复制</span></h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">mongodb有三种数据冗余方式。一种是master-slave(不推荐使用),一种是replica set,一种是 sharding模式。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">mongodb的副本集主从,就是标准的故障自动转移实现方式,不需要人工介入。master节点当掉之后,会通过选举从副本集中找出新的master节点,然后引导其他节点连接到这个master。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">mongodb的选举算法,采用的是bully。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">主节点的变更,会存放在特定的系统表中。slave会定时拉取这些变更,并应用。从这种描述中也可以看出,mongodb在同步延迟或者单节点出问题的时候,会有丢失数据的可能。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 23px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(123, 12, 0);">总结</span></h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">分布式是为了解决单机的容量问题,但它引入了一个新的问题,那就是数据同步。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">数据同步要关注一致性,故障恢复以及时效性。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">主要有两种数据需要同步。</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 元数据信息 </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 真正的数据 </section></li> </ul> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">对于元数据信息,目前比较主流的做法,可以参考使用raft协议进行数据分发。到了真正的数据同步方面,raft协议的效率还是有些低的,所以会普遍采用异步复制的方式。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">在这种情况下,异步复制列表,就成了关键的元数据信息,集群需要维护这些节点的状态。最坏的情况下,异步复制节点全部不可用,master会自己运行在非常不可信的环境下。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了增加数据分配的灵活性,这些复制单元多会针对于sharding分片进行操作,由此带来的,就是meta信息的爆炸。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">分布式系统这么多,但并没有一个能够统一的模式。有意思的是,即使是最低效的分布式系统,也有大批的追随者。不信?看看BTC的走势就知道了。</p>

IntelliJ idea 高效使用的姿势,一劳永逸!

作者:微信小助手

<section style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"> <br> </section> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA3ODIxNjYxNQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/Baq5lYpIw7WIvzVfHZ61VvJoaTzb7HDxtsJoicXicBJJ5uc9FrPG3eVztG6eBfUfdwIYmoqu8ibM5APCTDBUBPLrg/0?wx_fmt=png" data-nickname="架构文摘" data-alias="ArchDigest" data-signature="每天一篇架构领域重磅好文,涉及一线互联网公司应用架构(高可用、高性能、高稳定)、大数据、机器学习、Java架构等各个热门领域。" data-from="0"></mpprofile> </section> <p style="margin-top: 20px;max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">安装好 Intellij idea 之后,进行如下的初始化操作,工作效率提升十倍。</span></p> <h1 style="max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;font-family: Arial;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">插件</span></strong></span></p><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 18px;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1、Codota 代码智能提示插件</span></strong></span></p><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p></h1> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.6121212121212121" src="/upload/279ef426843f57d175feedaa49513985.png" data-type="png" data-w="1320" style="margin-right: auto;margin-bottom: 8px;margin-left: auto;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;display: block;border-radius: 4px;overflow-wrap: break-word !important;visibility: visible !important;width: 677px !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">只要打出首字母就能联想出一整条语句,这也太智能了,还显示了每条语句使用频率。</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">原因是它学习了我的项目代码,总结出了我的代码偏好。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="1.1846473029045643" src="/upload/4aefedaee941623bec004a276911dff0.png" data-type="png" data-w="964" style="margin-right: auto;margin-bottom: 8px;margin-left: auto;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;display: block;border-radius: 4px;overflow-wrap: break-word !important;visibility: visible !important;width: 677px !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果让它再加上机器学习,人工智能写代码的时代还会远吗?</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">2、Key Promoter X 快捷键提示插件</span></strong></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.4230769230769231" src="/upload/9a0673cf40ac094b5ae2320cb6c7242.png" data-type="png" data-w="1820" style="margin-right: auto;margin-bottom: 8px;margin-left: auto;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;display: block;border-radius: 4px;overflow-wrap: break-word !important;visibility: visible !important;width: 677px !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">每次都会在右下角弹窗提示,帮助我们快速熟悉快捷键。</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">3、CodeGlance 显示代码缩略图插件</span></strong></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.8241444866920152" src="/upload/5a1035d591aa1de91c649304b6edf6a4.jpg" data-type="jpeg" data-w="2104" style="margin-right: auto;margin-bottom: 8px;margin-left: auto;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;display: block;border-radius: 4px;overflow-wrap: break-word !important;visibility: visible !important;width: 677px !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">当代码很多的时候,方便查看,很有用。</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4、Lombok 简化臃肿代码插件</span></strong></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.948509485094851" src="/upload/97800a477a768239f7b8c8d4261736ca.png" data-type="png" data-w="1476" style="margin-right: auto;margin-bottom: 8px;margin-left: auto;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;display: block;border-radius: 4px;overflow-wrap: break-word !important;visibility: visible !important;width: 677px !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">实体类中的get/set/构造/toString/hashCode等方法,都不需要我们再手动写了</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">5、Alibaba Java Coding Guidelines 阿里巴巴代码规范检查插件</span></strong></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 10