文章列表

Spring Boot 使用 Disruptor 做内部高性能消息队列

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;overflow-wrap: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">工作中遇到项目使用Disruptor做消息队列,对你没看错,不是Kafka,也不是rabbitmq。Disruptor有个最大的优点就是快,还有一点它是开源的哦,下面做个简单的记录.</p> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247512889&amp;idx=1&amp;sn=3f4600c571d97f1311def99c103365c2&amp;chksm=fcf76cf4cb80e5e2034beb924b8ba5dc0c76af6526d24313c978ede2e193ef13b18189edad1d&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="inset: auto;margin: 20px 0px;"><img class="rich_pages wxw-img" data-ratio="0.8298653610771114" src="/upload/ead6d7cb5f1f53a15748231a0a9285ef.png" data-type="png" data-w="817" style="border-radius: 6px;display: block;margin: 0px;max-width: 95%;object-fit: contain;"></span></a> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Disruptor介绍</strong></span></h2> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Disruptor 是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级)。基于 Disruptor 开发的系统单线程能支撑每秒 600 万订单,2010 年在 QCon 演讲后,获得了业界关注。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Disruptor是一个开源的Java框架,它被设计用于在生产者—消费者(producer-consumer problem,简称PCP)问题上获得尽量高的吞吐量(TPS)和尽量低的延迟。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 从功能上来看,Disruptor 是实现了“队列”的功能,而且是一个有界队列。那么它的应用场景自然就是“生产者-消费者”模型的应用场合了。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Disruptor是LMAX在线交易平台的关键组成部分,LMAX平台使用该框架对订单处理速度能达到600万TPS,除金融领域之外,其他一般的应用中都可以用到Disruptor,它可以带来显著的性能提升。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 其实Disruptor与其说是一个框架,不如说是一种设计思路,这个设计思路对于存在“并发、缓冲区、生产者—消费者模型、事务处理”这些元素的程序来说,Disruptor提出了一种大幅提升性能(TPS)的方案。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Disruptor的github主页:https://github.com/LMAX-Exchange/disruptor </section></li> </ol> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Disruptor 的核心概念</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">先从了解 Disruptor 的核心概念开始,来了解它是如何运作的。下面介绍的概念模型,既是领域对象,也是映射到代码实现上的核心对象。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Ring Buffer</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">如其名,环形的缓冲区。曾经 RingBuffer 是 Disruptor 中的最主要的对象,但从3.0版本开始,其职责被简化为仅仅负责对通过 Disruptor 进行交换的数据(事件)进行存储和更新。在一些更高级的应用场景中,Ring Buffer 可以由用户的自定义实现来完全替代。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Sequence Disruptor</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">通过顺序递增的序号来编号管理通过其进行交换的数据(事件),对数据(事件)的处理过程总是沿着序号逐个递增处理。一个 Sequence 用于跟踪标识某个特定的事件处理者( RingBuffer/Consumer )的处理进度。虽然一个 AtomicLong 也可以用于标识进度,但定义 Sequence 来负责该问题还有另一个目的,那就是防止不同的 Sequence 之间的CPU缓存伪共享(Flase Sharing)问题。(注:这是 Disruptor 实现高性能的关键点之一,网上关于伪共享问题的介绍已经汗牛充栋,在此不再赘述)。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Sequencer</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">Sequencer 是 Disruptor 的真正核心。此接口有两个实现类 SingleProducerSequencer、MultiProducerSequencer ,它们定义在生产者和消费者之间快速、正确地传递数据的并发算法。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Sequence Barrier</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">用于保持对RingBuffer的 main published Sequence 和Consumer依赖的其它Consumer的 Sequence 的引用。Sequence Barrier 还定义了决定 Consumer 是否还有可处理的事件的逻辑。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Wait Strategy</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">定义 Consumer 如何进行等待下一个事件的策略。(注:Disruptor 定义了多种不同的策略,针对不同的场景,提供了不一样的性能表现)</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Event</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">在 Disruptor 的语义中,生产者和消费者之间进行交换的数据被称为事件(Event)。它不是一个被 Disruptor 定义的特定类型,而是由 Disruptor 的使用者定义并指定。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">EventProcessor</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">EventProcessor 持有特定消费者(Consumer)的 Sequence,并提供用于调用事件处理实现的事件循环(Event Loop)。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">EventHandler</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">Disruptor 定义的事件处理接口,由用户实现,用于处理事件,是 Consumer 的真正实现。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Producer</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">即生产者,只是泛指调用 Disruptor 发布事件的用户代码,Disruptor 没有定义特定接口或类型。</p> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247512889&amp;idx=1&amp;sn=3f4600c571d97f1311def99c103365c2&amp;chksm=fcf76cf4cb80e5e2034beb924b8ba5dc0c76af6526d24313c978ede2e193ef13b18189edad1d&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="inset: auto;margin: 20px 0px;"><img class="rich_pages wxw-img" data-ratio="0.6650124069478908" src="/upload/91ecfad375c2c3627859fb32c62e6900.png" data-type="png" data-w="806" style="border-radius: 6px;display: block;margin: 0px;max-width: 95%;object-fit: contain;"></span></a> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">案例-demo</strong></span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 通过下面8个步骤,你就能将Disruptor Get回家啦: </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 1、添加pom.xml依赖 </section></li> </ul> <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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">groupId</span>&gt;</span>com.lmax<span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">artifactId</span>&gt;</span>disruptor<span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e45649;line-height: 26px;">version</span>&gt;</span>3.3.4<span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">version</span>&gt;</span><br><span style="line-height: 26px;">&lt;/<span style="color: #e45649;line-height: 26px;">dependency</span>&gt;</span><br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 2、消息体Model </section></li> </ul> <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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br>&nbsp;*&nbsp;消息体<br>&nbsp;*/</span><br><span style="color: #4078f2;line-height: 26px;">@Data</span><br><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">MessageModel</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">private</span>&nbsp;String&nbsp;message;<br>}<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 3、构造EventFactory </section></li> </ul> <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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">HelloEventFactory</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">EventFactory</span>&lt;<span style="color: #c18401;line-height: 26px;">MessageModel</span>&gt;&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #4078f2;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;MessageModel&nbsp;<span style="color: #4078f2;line-height: 26px;">newInstance</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">return</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;MessageModel();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 4、构造EventHandler-消费者 </section></li> </ul> <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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #4078f2;line-height: 26px;">@Slf</span>4j<br><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">HelloEventHandler</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">EventHandler</span>&lt;<span style="color: #c18401;line-height: 26px;">MessageModel</span>&gt;&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #4078f2;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">onEvent</span><span style="line-height: 26px;">(MessageModel&nbsp;event,&nbsp;<span style="color: #a626a4;line-height: 26px;">long</span>&nbsp;sequence,&nbsp;<span style="color: #a626a4;line-height: 26px;">boolean</span>&nbsp;endOfBatch)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//这里停止1000ms是为了确定消费消息是异步的</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="color: #986801;line-height: 26px;">1000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #50a14f;line-height: 26px;">"消费者处理消息开始"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">if</span>&nbsp;(event&nbsp;!=&nbsp;<span style="color: #a626a4;line-height: 26px;">null</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #50a14f;line-height: 26px;">"消费者消费的信息是:{}"</span>,event);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #a626a4;line-height: 26px;">catch</span>&nbsp;(Exception&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #50a14f;line-height: 26px;">"消费者处理消息失败"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #50a14f;line-height: 26px;">"消费者处理消息结束"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 5、构造BeanManager </section></li> </ul> <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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br>&nbsp;*&nbsp;获取实例化对象<br>&nbsp;*/</span><br><span style="color: #4078f2;line-height: 26px;">@Component</span><br><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">BeanManager</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">ApplicationContextAware</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">private</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">static</span>&nbsp;ApplicationContext&nbsp;applicationContext&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">null</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #4078f2;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">setApplicationContext</span><span style="line-height: 26px;">(ApplicationContext&nbsp;applicationContext)</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">throws</span>&nbsp;BeansException&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">this</span>.applicationContext&nbsp;=&nbsp;applicationContext;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">static</span>&nbsp;ApplicationContext&nbsp;<span style="color: #4078f2;line-height: 26px;">getApplicationContext</span><span style="line-height: 26px;">()</span>&nbsp;</span>{&nbsp;<span style="color: #a626a4;line-height: 26px;">return</span>&nbsp;applicationContext;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">static</span>&nbsp;Object&nbsp;<span style="color: #4078f2;line-height: 26px;">getBean</span><span style="line-height: 26px;">(String&nbsp;name)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">return</span>&nbsp;applicationContext.getBean(name);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">static</span>&nbsp;&lt;T&gt;&nbsp;<span style="line-height: 26px;">T&nbsp;<span style="color: #4078f2;line-height: 26px;">getBean</span><span style="line-height: 26px;">(Class&lt;T&gt;&nbsp;clazz)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">return</span>&nbsp;applicationContext.getBean(clazz);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 6、构造MQManager </section></li> </ul> <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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #4078f2;line-height: 26px;">@Configuration</span><br><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">MQManager</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #4078f2;line-height: 26px;">@Bean</span>(<span style="color: #50a14f;line-height: 26px;">"messageModel"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;RingBuffer&lt;MessageModel&gt;&nbsp;<span style="color: #4078f2;line-height: 26px;">messageModelRingBuffer</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//定义用于事件处理的线程池,&nbsp;Disruptor通过java.util.concurrent.ExecutorSerivce提供的线程来触发consumer的事件处理</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;executor&nbsp;=&nbsp;Executors.newFixedThreadPool(<span style="color: #986801;line-height: 26px;">2</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//指定事件工厂</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HelloEventFactory&nbsp;factory&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;HelloEventFactory();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//指定ringbuffer字节大小,必须为2的N次方(能将求模运算转为位运算提高效率),否则将影响效率</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">int</span>&nbsp;bufferSize&nbsp;=&nbsp;<span style="color: #986801;line-height: 26px;">1024</span>&nbsp;*&nbsp;<span style="color: #986801;line-height: 26px;">256</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//单线程模式,获取额外的性能</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Disruptor&lt;MessageModel&gt;&nbsp;disruptor&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;Disruptor&lt;&gt;(factory,&nbsp;bufferSize,&nbsp;executor,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProducerType.SINGLE,&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;BlockingWaitStrategy());<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//设置事件业务处理器---消费者</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;disruptor.handleEventsWith(<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;HelloEventHandler());<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//&nbsp;启动disruptor线程</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;disruptor.start();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//获取ringbuffer环,用于接取生产者生产的事件</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RingBuffer&lt;MessageModel&gt;&nbsp;ringBuffer&nbsp;=&nbsp;disruptor.getRingBuffer();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">return</span>&nbsp;ringBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 7、构造Mqservice和实现类-生产者 </section></li> </ul> <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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">interface</span>&nbsp;<span style="color: #c18401;line-height: 26px;">DisruptorMqService</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;消息<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span style="color: #a626a4;line-height: 26px;">@param</span>&nbsp;message<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">sayHelloMq</span><span style="line-height: 26px;">(String&nbsp;message)</span></span>;<br>}<br><br><span style="color: #4078f2;line-height: 26px;">@Slf</span>4j<br><span style="color: #4078f2;line-height: 26px;">@Component</span><br><span style="color: #4078f2;line-height: 26px;">@Service</span><br><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">DisruptorMqServiceImpl</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">DisruptorMqService</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #4078f2;line-height: 26px;">@Autowired</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">private</span>&nbsp;RingBuffer&lt;MessageModel&gt;&nbsp;messageModelRingBuffer;<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #4078f2;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">sayHelloMq</span><span style="line-height: 26px;">(String&nbsp;message)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #50a14f;line-height: 26px;">"record&nbsp;the&nbsp;message:&nbsp;{}"</span>,message);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//获取下一个Event槽的下标</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">long</span>&nbsp;sequence&nbsp;=&nbsp;messageModelRingBuffer.next();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//给Event填充数据</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageModel&nbsp;event&nbsp;=&nbsp;messageModelRingBuffer.get(sequence);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;event.setMessage(message);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #50a14f;line-height: 26px;">"往消息队列中添加消息:{}"</span>,&nbsp;event);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #a626a4;line-height: 26px;">catch</span>&nbsp;(Exception&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error(<span style="color: #50a14f;line-height: 26px;">"failed&nbsp;to&nbsp;add&nbsp;event&nbsp;to&nbsp;messageModelRingBuffer&nbsp;for&nbsp;:&nbsp;e&nbsp;=&nbsp;{},{}"</span>,e,e.getMessage());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #a626a4;line-height: 26px;">finally</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//发布Event,激活观察者去消费,将sequence传递给改消费者</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//注意最后的publish方法必须放在finally中以确保必须得到调用;如果某个请求的sequence未被提交将会堵塞后续的发布操作或者其他的producer</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;messageModelRingBuffer.publish(sequence);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 8、构造测试类及方法 </section></li> </ul> <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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #4078f2;line-height: 26px;">@Slf</span>4j<br><span style="color: #4078f2;line-height: 26px;">@RunWith</span>(SpringRunner<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>)<br>@<span style="color: #c18401;line-height: 26px;">SpringBootTest</span>(<span style="color: #c18401;line-height: 26px;">classes</span>&nbsp;</span>=&nbsp;DemoApplication<span style="line-height: 26px;">.<span style="color: #a626a4;line-height: 26px;">class</span>)<br><span style="color: #c18401;line-height: 26px;">public</span>&nbsp;<span style="color: #c18401;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">DemoApplicationTests</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #4078f2;line-height: 26px;">@Autowired</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">private</span>&nbsp;DisruptorMqService&nbsp;disruptorMqService;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;项目内部使用Disruptor做消息队列<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span style="color: #a626a4;line-height: 26px;">@throws</span>&nbsp;Exception<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #4078f2;line-height: 26px;">@Test</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">sayHelloMqTest</span><span style="line-height: 26px;">()</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">throws</span>&nbsp;Exception</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;disruptorMqService.sayHelloMq(<span style="color: #50a14f;line-height: 26px;">"消息到了,Hello&nbsp;world!"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #50a14f;line-height: 26px;">"消息队列已发送完毕"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//这里停止2000ms是为了确定是处理消息是异步的</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span style="color: #986801;line-height: 26px;">2000</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">测试运行结果</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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQa3AT91gGibCzcn7gTKBF908ibBgmbHfGPVTc2naYj2VoJRcac69ac5FsowsAI4ibYGliatBqP7ibrMzib/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;"><span style="color: #986801;line-height: 26px;">2020</span>-<span style="color: #986801;line-height: 26px;">04</span>-<span style="color: #986801;line-height: 26px;">05</span>&nbsp;<span style="color: #986801;line-height: 26px;">14</span>:<span style="color: #986801;line-height: 26px;">31</span>:<span style="color: #986801;line-height: 26px;">18.543</span>&nbsp;&nbsp;INFO&nbsp;<span style="color: #986801;line-height: 26px;">7274</span>&nbsp;---&nbsp;[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;main]&nbsp;c.e.u.d.d.s.Impl.DisruptorMqServiceImpl&nbsp;&nbsp;:&nbsp;record&nbsp;the&nbsp;message:&nbsp;消息到了,Hello&nbsp;world!<br><span style="color: #986801;line-height: 26px;">2020</span>-<span style="color: #986801;line-height: 26px;">04</span>-<span style="color: #986801;line-height: 26px;">05</span>&nbsp;<span style="color: #986801;line-height: 26px;">14</span>:<span style="color: #986801;line-height: 26px;">31</span>:<span style="color: #986801;line-height: 26px;">18.545</span>&nbsp;&nbsp;INFO&nbsp;<span style="color: #986801;line-height: 26px;">7274</span>&nbsp;---&nbsp;[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; main] c.e.u.d.d.s.Impl.DisruptorMqServiceImpl &nbsp;:&nbsp;往消息队列中添加消息:MessageModel(message=消息到了,Hello world!)<br><span style="color: #986801;line-height: 26px;">2020</span>-<span style="color: #986801;line-height: 26px;">04</span>-<span style="color: #986801;line-height: 26px;">05</span>&nbsp;<span style="color: #986801;line-height: 26px;">14</span>:<span style="color: #986801;line-height: 26px;">31</span>:<span style="color: #986801;line-height: 26px;">18.545</span>&nbsp;&nbsp;INFO&nbsp;<span style="color: #986801;line-height: 26px;">7274</span>&nbsp;---&nbsp;[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;main]&nbsp;c.e.utils.demo.DemoApplicationTests&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;消息队列已发送完毕<br><span style="color: #986801;line-height: 26px;">2020</span>-<span style="color: #986801;line-height: 26px;">04</span>-<span style="color: #986801;line-height: 26px;">05</span>&nbsp;<span style="color: #986801;line-height: 26px;">14</span>:<span style="color: #986801;line-height: 26px;">31</span>:<span style="color: #986801;line-height: 26px;">19.547</span>&nbsp;&nbsp;INFO&nbsp;<span style="color: #986801;line-height: 26px;">7274</span>&nbsp;---&nbsp;[pool-<span style="color: #986801;line-height: 26px;">1</span>-thread-<span style="color: #986801;line-height: 26px;">1</span>]&nbsp;c.e.u.d.disrupMq.mq.HelloEventHandler&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;消费者处理消息开始<br><span style="color: #986801;line-height: 26px;">2020</span>-<span style="color: #986801;line-height: 26px;">04</span>-<span style="color: #986801;line-height: 26px;">05</span>&nbsp;<span style="color: #986801;line-height: 26px;">14</span>:<span style="color: #986801;line-height: 26px;">31</span>:<span style="color: #986801;line-height: 26px;">19.547</span>&nbsp;&nbsp;INFO&nbsp;<span style="color: #986801;line-height: 26px;">7274</span>&nbsp;---&nbsp;[pool-<span style="color: #986801;line-height: 26px;">1</span>-thread-<span style="color: #986801;line-height: 26px;">1</span>] c.e.u.d.disrupMq.mq.HelloEventHandler &nbsp;&nbsp;&nbsp;:&nbsp;消费者消费的信息是:MessageModel(message=消息到了,Hello world!)<br><span style="color: #986801;line-height: 26px;">2020</span>-<span style="color: #986801;line-height: 26px;">04</span>-<span style="color: #986801;line-height: 26px;">05</span>&nbsp;<span style="color: #986801;line-height: 26px;">14</span>:<span style="color: #986801;line-height: 26px;">31</span>:<span style="color: #986801;line-height: 26px;">19.547</span>&nbsp;&nbsp;INFO&nbsp;<span style="color: #986801;line-height: 26px;">7274</span>&nbsp;---&nbsp;[pool-<span style="color: #986801;line-height: 26px;">1</span>-thread-<span style="color: #986801;line-height: 26px;">1</span>]&nbsp;c.e.u.d.disrupMq.mq.HelloEventHandler&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;消费者处理消息结束<br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><strong style="font-weight: 700;color: rgb(248, 57, 41);">总结</strong></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">其实 生成者 -&gt; 消费者 模式是很常见的,通过一些消息队列也可以轻松做到上述的效果。不同的地方在于,Disruptor 是在内存中以队列的方式去实现的,而且是无锁的。这也是 Disruptor 为什么高效的原因。</p> <hr data-tool="mdnice编辑器" style="margin: 10px 0px;height: 1px;padding: 0px;border-width: initial;border-style: none;border-color: initial;text-align: center;background-image: linear-gradient(to right, rgba(248, 57, 41, 0), rgba(248, 57, 41, 0.75), rgba(248, 57, 41, 0));"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">欢迎加入我的知识星球,<a href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247512889&amp;idx=1&amp;sn=3f4600c571d97f1311def99c103365c2&amp;chksm=fcf76cf4cb80e5e2034beb924b8ba5dc0c76af6526d24313c978ede2e193ef13b18189edad1d&amp;token=510846437&amp;lang=zh_CN&amp;scene=21#wechat_redirect" style="text-decoration: none;word-wrap: break-word;color: rgb(248, 57, 41);font-weight: 400;border-bottom: 1px solid rgb(248, 57, 41);" data-linktype="2">点击了<span style="display: none;line-height: 0px;">‍</span>解详情</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">星球会员可以免费观看陈某所有更新的<span style="color: rgb(255, 41, 65);"><strong>视频教程</strong></span>(几杯咖啡钱)。加入方式,长按下方二维码:</p> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247512889&amp;idx=1&amp;sn=3f4600c571d97f1311def99c103365c2&amp;chksm=fcf76cf4cb80e5e2034beb924b8ba5dc0c76af6526d24313c978ede2e193ef13b18189edad1d&amp;scene=21#wechat_redirect" textvalue="你已选中了添加链接的内容" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="1"><span class="js_jump_icon h5_image_link" data-positionback="static" style="inset: auto;margin: 20px 0px;"><img class="rich_pages wxw-img" data-ratio="0.5493333333333333" src="/upload/21a4b2197b0e6b273a80b02ced47cfc2.jpg" data-type="jpeg" data-w="1125" style="border-radius: 6px;display: block;margin: 0px;max-width: 95%;object-fit: contain;"></span></a> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">目前已更新视频如下:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">《Spring Cloud Alibaba 实战》</strong>:https://sourl.cn/72X9JV </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">《亿级数据分库分表实战》(正在更新)</strong> :https://sourl.cn/U9pKj4 </section></li> </ol> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <br> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <span style="color: rgb(255, 41, 65);"><strong>后期随着新视频加入价格会逐步上涨,前期加入的免费看~</strong></span> <br> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="outer" label="edit by 135editor" mpa-from-tpl="t"> <section data-role="paragraph" mpa-from-tpl="t"> <h1 style="margin-top: 1em;margin-bottom: 1em;outline: 0px;font-size: 28px;color: rgb(34, 34, 34);letter-spacing: 0.544px;line-height: 36px;text-align: center;"><span style="outline: 0px;color: rgb(255, 122, 69);font-size: 17px;">=== 《Spring Cloud Alibaba 实战》===</span></h1> <section data-mpa-template="t" style="margin-bottom: 0em;outline: 0px;color: rgb(34, 34, 34);font-size: 17px;letter-spacing: 0.544px;text-align: justify;" mpa-from-tpl="t"> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;"> <section data-style-type="5" data-tools="新媒体排版" data-id="1259732" mpa-from-tpl="t" style="outline: 0px;color: rgb(0, 0, 0);font-size: medium;"> <section mpa-from-tpl="t" style="outline: 0px;"> <section mpa-from-tpl="t" style="padding: 10px;outline: 0px;text-align: center;border-width: 1px;border-style: solid;border-color: rgb(240, 240, 240);"> <section mpa-from-tpl="t" style="outline: 0px;display: inline-block;"> <section mpa-from-tpl="t" style="outline: 0px;overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;"> <section mpa-from-tpl="t" style="padding: 3px 2px;outline: 0px;color: inherit;border-color: rgb(252, 180, 43);"> <p style="outline: 0px;clear: both;min-height: 1em;background-color: rgb(240, 240, 240);"><img class="rich_pages wxw-img" data-ratio="10.251040221914009" src="/upload/c4fa108d39460b62296450215a23330c.jpg" data-type="jpeg" data-w="721" style="outline: 0px;vertical-align: top;width: 100%;height: auto !important;visibility: visible !important;"></p> </section> </section> </section> <p style="margin: 15px auto 5px;outline: 0px;clear: both;min-height: 1em;"><strong style="outline: 0px;" mpa-from-tpl="t"><span style="outline: 0px;font-size: 13px;color: rgb(0, 122, 170);">滚动查看更多</span></strong></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="outer" label="edit by 135editor" mpa-from-tpl="t"> <section data-role="paragraph" mpa-from-tpl="t"> <h1 style="margin-top: 1em;margin-bottom: 1em;outline: 0px;font-size: 28px;color: rgb(34, 34, 34);letter-spacing: 0.544px;line-height: 36px;text-align: center;"><span style="outline: 0px;color: rgb(255, 122, 69);font-size: 17px;">=== 《亿级数据分库分表实战 》===</span></h1> <section data-mpa-template="t" style="margin-bottom: 0em;outline: 0px;color: rgb(34, 34, 34);font-size: 17px;letter-spacing: 0.544px;text-align: justify;" mpa-from-tpl="t"> <section data-mpa-template="t" mpa-from-tpl="t" style="outline: 0px;"> <section data-style-type="5" data-tools="新媒体排版" data-id="1259732" mpa-from-tpl="t" style="outline: 0px;color: rgb(0, 0, 0);font-size: medium;"> <section mpa-from-tpl="t" style="outline: 0px;"> <section mpa-from-tpl="t" style="padding: 10px;outline: 0px;text-align: center;border-width: 1px;border-style: solid;border-color: rgb(240, 240, 240);"> <section mpa-from-tpl="t" style="outline: 0px;display: inline-block;"> <section mpa-from-tpl="t" style="outline: 0px;overflow: hidden scroll;height: 344px;display: inline-block;color: inherit;"> <section mpa-from-tpl="t" style="padding: 3px 2px;outline: 0px;color: inherit;border-color: rgb(252, 180, 43);"> <p style="outline: 0px;clear: both;min-height: 1em;background-color: rgb(240, 240, 240);"><img class="rich_pages wxw-img" data-ratio="6.261772853185596" src="/upload/cf3d00018dfcbf4b83afd26fda262b38.jpg" data-type="jpeg" data-w="722" style="outline: 0px;vertical-align: top;width: 100%;height: auto !important;visibility: visible !important;"></p> </section> </section> </section> <p style="margin: 15px auto 5px;outline: 0px;clear: both;min-height: 1em;"><strong style="outline: 0px;" mpa-from-tpl="t"><span style="outline: 0px;font-size: 13px;color: rgb(0, 122, 170);">滚动查看更多</span></strong></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> <p><br mpa-from-tpl="t"></p> <section class="channels_iframe_wrp"> <mpvideosnap class="js_uneditable custom_select_card channels_iframe videosnap_video_iframe" data-pluginname="videosnap" data-id="export/UzFfAgtgekIEAQAAAAAASqI0zMZdLQAAAAstQy6ubaLX4KHWvLEZgBPE9qNgLkIhE6qDzNPgMIvacPAwfhmQsyDypUSNQO6c" data-url="https://findermp.video.qq.com/251/20304/stodownload?encfilekey=rjD5jyTuFrIpZ2ibE8T7YmwgiahniaXswqzcgibbmslI58cRQsf5kj4StubFX6atfiazhOibDQkeKIlIx0lhs4kI59a6yfcqwm5cWGgicv9DUZ23VNhiaXJqMwDrdg&amp;adaptivelytrans=0&amp;bizid=1023&amp;dotrans=0&amp;hy=SH&amp;idx=1&amp;m=&amp;scene=0&amp;token=x5Y29zUxcibAIvqUibe7BYsuuF7U7R2DbVxUbpKDrTvkPLtE2OSfqzt9cDVVSLicMk5CtV8NciaujVY" data-headimgurl="http://wx.qlogo.cn/finderhead/5Oom8vdOxTI453gNLedGe8Cjh0r6goaCUQdbMlXd4mo/0" data-username="v2_060000231003b20faec8c4e0801fc5d0cd01ed3cb0774a1a71882e00775192f7e6d81d63849e@finder" data-nickname="码猿技术专栏" data-desc="定义3个注解将微服务鉴权下放到下游服务" data-nonceid="8284320766962804662" data-type="video" data-width="1920" data-height="1080"></mpvideosnap> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <br> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: right;font-weight: 500;color: rgb(53, 53, 53);"> <strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: 0.544px;orphans: 2;text-align: right;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);">帅气的人都在点赞、分享、在看三连</strong> <img class="rich_pages wxw-img" data-fileid="100011967" data-ratio="1" data-type="png" data-w="20" src="/upload/1d550a991385b842a21e2b301725407e.png" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: text-bottom;height: auto !important;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;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-align: right;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;word-spacing: 0.8px;color: rgb(53, 53, 53);font-size: 16px;background-color: rgb(255, 255, 255);display: inline-block;visibility: visible !important;width: 20px !important;"> </section> </section>

基于代价的慢查询优化建议

作者:微信小助手

<p style="padding-right: 0.5em;padding-left: 0.5em;white-space: normal;" data-mpa-powered-by="yiban.io"><img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="48" data-ratio="0.10078125" data-s="300,640" src="/upload/4dbe1debe51138f467e6ce57d61bcbd7.png" data-type="png" data-w="1280" style="height: 58px;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;width: 578px;"><br></p> <p style="padding-right: 0.5em;padding-left: 0.5em;white-space: normal;text-align: center;"><strong 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;"><span style="color: rgb(136, 136, 136);font-size: 12px;letter-spacing: 1px;">总第503</span></strong><strong 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;"><span style="color: rgb(136, 136, 136);font-size: 12px;letter-spacing: 1px;">篇</span></strong></p> <p style="padding-right: 0.5em;padding-left: 0.5em;white-space: normal;text-align: center;"><strong><span style="color: rgb(136, 136, 136);font-size: 12px;letter-spacing: 1px;">2022年 第020篇</span></strong></p> <section data-role="outer" label="Powered by 135editor.com" style="margin-right: 0.5em;margin-left: 0.5em;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;"> <section data-role="outer" label="Powered by 135editor.com"> <section data-tools="135编辑器" data-id="127" style="border-width: 0px;border-style: none;border-color: initial;"> <section data-tools="135编辑器" data-id="127" style="border-width: 0px;border-style: none;border-color: initial;"> <section style="margin: 60px 16px 16px;border-width: 1px;border-style: solid;border-color: rgb(235, 234, 225);text-align: center;border-radius: 8px;"> <section style="margin-top: -3.3em;margin-right: 5px;margin-left: 5px;font-weight: inherit;text-decoration: inherit;font-size: 18px;color: inherit;"> <p style="margin-right: auto;margin-bottom: 15px;margin-left: auto;border-width: 2px;border-style: solid;border-color: rgb(235, 234, 225);width: 108px;height: 108px;border-radius: 50%;box-shadow: rgb(201, 201, 201) 0px 2px 2px 2px;background-color: rgb(254, 254, 254);"><img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="93" data-cropsely1="0" data-cropsely2="93" data-ratio="0.9966329966329966" src="/upload/c1f9e58a75e676cd4bee8d68e9fe8659.png" data-type="png" data-w="594" data-width="100%" opacity="" style="height: 103px;border-radius: 50%;color: inherit;display: inline-block;width: 103px;visibility: visible !important;" title="undefined" border="0"></p> </section> <section data-brushtype="text" data-style="text-align: left; font-size: 14px; color: inherit;" style="margin: 8px 15px;line-height: 1.4;"> <section style="text-align: justify;"> <span style="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: 14px;color: rgb(136, 136, 136);">对于数据库来说,慢查询往往意味着风险。SQL执行得越慢,消耗的CPU资源或IO资源也会越大。大量的慢查询可直接引发业务故障,关注慢查询即是关注故障本身。本文主要介绍了美团如何利用数据库的代价优化器来优化慢查询,并给出索引建议,评估跟踪建议质量,运营治理慢查询。</span> </section> </section> </section> </section> </section> </section> </section> <ul style="margin: 8px 32px;padding-left: 25px;" class="list-paddingleft-1"> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">1 背景</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">2 基于代价的优化器介绍</span></p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-1"> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">2.1 SQL执行与优化器</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">2.2 代价模型介绍</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">2.3 基于代价的索引选择</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">2.4 基于代价的索引推荐思路</span></p></li> </ul> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">3 索引推荐实现</span></p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-1"> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">3.1 前置校验</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">3.2 提取关键列名</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">3.3 生成候选索引</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">3.4 数据采集</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">3.5 统计数据计算</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">3.6 候选索引代价评估</span></p></li> </ul> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">4 推荐质量保证</span></p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-1"> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">4.1 有效性验证</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">4.2 效果追踪</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">4.3 仿真环境</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">4.4 测试案例库</span></p></li> </ul> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">5 慢查询治理运营</span></p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-1"> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">5.1 过去-历史慢查询</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">5.2 现在-新增慢查询</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">5.3 未来-潜在慢查询</span></p></li> </ul> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">6 项目运行情况</span></p></li> <li style="font-size: 13px;color: rgb(136, 136, 136);"><p><span style="font-size: 13px;color: rgb(136, 136, 136);">7 未来规划</span></p></li> </ul> <h2 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;font-weight: bold;font-size: 22px;"><span style="font-size: 20px;color: rgb(255, 195, 0);">1 背景</span></h2> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">慢查询是指数据库中查询时间超过指定阈值(</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">美团设置为100ms</span> <span style="font-size: 15px;">)的SQL,它是数据库的性能杀手,也是业务优化数据库访问的重要抓手。随着美团业务的高速增长,日均慢查询量已经过亿条,此前因慢查询导致的故障约占数据库故障总数的10%以上,而且高级别的故障呈日益增长趋势。因此,对慢查询的优化已经变得刻不容缓。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">那么如何优化慢查询呢?最直接有效的方法就是选用一个查询效率高的索引。关于高效率的索引推荐,主要有基于经验规则和代价的两种算法。在日常工作中,基于经验规则的推荐随处可见,对于简单的SQL,如</span> <code style="font-size: 14px;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: 15px;">select * from sync_test1 where name like 'Bobby%'</span></code> <span style="font-size: 15px;">,直接添加索引IX(</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">name</span> <span style="font-size: 15px;">) 就可以取得不错的效果;但对于稍微复杂点的SQL,如</span> <code style="font-size: 14px;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: 15px;">select * from sync_test1 where name like 'Bobby%' and dt &gt; '2021-07-06'</span></code> <span style="font-size: 15px;">,到底选择IX(</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">name</span> <span style="font-size: 15px;">)、IX(</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">dt</span> <span style="font-size: 15px;">)、IX(</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">dt,name</span> <span style="font-size: 15px;">) 还是IX(</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">name,dt</span> <span style="font-size: 15px;">),该方法也无法给出准确的回答。更别说像多表Join、子查询这样复杂的场景了。所以采用基于代价的推荐来解决该问题会更加普适,因为基于代价的方法使用了和数据库优化器相同的方式,去量化评估所有的可能性,选出的是执行SQL耗费代价最小的索引。</span> </section> <h2 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;font-weight: bold;font-size: 22px;"><span style="font-size: 20px;color: rgb(255, 195, 0);">2 基于代价的优化器介绍</span></h2> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;font-weight: bold;font-size: 20px;"><span style="font-size: 18px;">2.1 SQL执行与优化器</span></h3> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">一条SQL在MySQL服务器中执行流程主要包含:SQL解析、基于语法树的准备工作、优化器的逻辑变化、优化器的代价准备工作、基于代价模型的优化、进行额外的优化和运行执行计划等部分。具体如下图所示:</span> </section> <section 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: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;margin-left: 0px;margin-right: 0px;"> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="558" data-cropsely1="0" data-cropsely2="439" data-ratio="0.7870646766169154" src="/upload/452b9a9c64691a21edb3a5b4e18dea2b.jpg" data-type="jpeg" data-w="1005" style="display: block;margin-right: auto;margin-left: auto;width: 558px;height: 439px;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> <span style="font-size: 12px;">SQL执行与优化器</span> </figcaption> </figure> </section> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;font-weight: bold;font-size: 20px;"><span style="font-size: 18px;">2.2 代价模型介绍</span></h3> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">而对于优化器来说,执行一条SQL有各种各样的方案可供选择,如表是否用索引、选择哪个索引、是否使用范围扫描、多表Join的连接顺序和子查询的执行方式等。如何从这些可选方案中选出耗时最短的方案呢?这就需要定义一个量化数值指标,这个指标就是代价(</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">Cost</span> <span style="font-size: 15px;">),我们分别计算出可选方案的操作耗时,从中选出最小值。</span> </section> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">代价模型将操作分为Server层和Engine(</span> <span style="font-size: 15px;color: rgb(136, 136, 136);">存储引擎</span> <span style="font-size: 15px;">)层两类,Server层主要是CPU代价,Engine层主要是IO代价,比如MySQL从磁盘读取一个数据页的代价io_block_read_cost为1,计算符合条件的行代价为row_evaluate_cost为0.2。除此之外还有:</span> </section> <ol data-tool="mdnice编辑器" style="margin: 8px 0px;padding-left: 25px;" class="list-paddingleft-1"> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 14px;">memory_temptable_create_cost (</span> <span style="font-size: 14px;color: rgb(136, 136, 136);">default 2.0</span> <span style="font-size: 14px;">) 内存临时表的创建代价。</span> </section></li> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 14px;">memory_temptable_row_cost (</span> <span style="font-size: 14px;color: rgb(136, 136, 136);">default 0.2</span> <span style="font-size: 14px;">) 内存临时表的行代价。</span> </section></li> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 14px;">key_compare_cost (</span> <span style="font-size: 14px;color: rgb(136, 136, 136);">default 0.1</span> <span style="font-size: 14px;">) 键比较的代价,例如排序。</span> </section></li> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 14px;">disk_temptable_create_cost (</span> <span style="font-size: 14px;color: rgb(136, 136, 136);">default 40.0</span> <span style="font-size: 14px;">) 内部myisam或innodb临时表的创建代价。</span> </section></li> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 14px;">disk_temptable_row_cost (</span> <span style="font-size: 14px;color: rgb(136, 136, 136);">default 1.0</span> <span style="font-size: 14px;">) 内部myisam或innodb临时表的行代价。</span> </section></li> </ol> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">在MySQL 5.7中,这些操作代价的默认值都可以进行配置。为了计算出方案的总代价,还需要参考一些统计数据,如表数据量大小、元数据和索引信息等。MySQL的代价优化器模型整体如下图所示:</span> </section> <section style="padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;margin-left: 0px;margin-right: 0px;"> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-cropselx1="0" data-cropselx2="558" data-cropsely1="0" data-cropsely2="259" data-ratio="0.4634146341463415" src="/upload/1fd37163dc0b4f7552e7030e038050af.jpg" data-type="jpeg" data-w="861" style="display: block;margin-right: auto;margin-left: auto;width: 559px;height: 259px;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> <span style="font-size: 12px;">代价模型</span> </figcaption> </figure> </section> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;font-weight: bold;font-size: 20px;"><span style="font-size: 18px;">2.3 基于代价的索引选择</span></h3> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">还是继续拿上述的</span> <code style="font-size: 14px;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: 15px;">SQL select * from sync_test1 where name like 'Bobby%' and dt &gt; '2021-07-06'</span></code> <span style="font-size: 15px;">为例,我们看看MySQL优化器是如何根据代价模型选择索引的。首先,我们直接在建表时加入四个候选索引。</span> </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;"> <section style="overflow-x: auto;padding: 15px 16px 16px;color: rgb(56, 58, 66);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(250, 250, 250);border-radius: 5px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 12px;"><span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">Create</span>&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">Table</span>:&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">CREATE</span>&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">TABLE</span>&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`sync_test1`</span>&nbsp;(<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`id`</span>&nbsp;<span style="font-size: 12px;color: rgb(193, 132, 1);line-height: 26px;">int</span>(<span style="font-size: 12px;color: rgb(152, 104, 1);line-height: 26px;">11</span>)&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">NOT</span>&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">NULL</span>&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`cid`</span>&nbsp;<span style="font-size: 12px;color: rgb(193, 132, 1);line-height: 26px;">int</span>(<span style="font-size: 12px;color: rgb(152, 104, 1);line-height: 26px;">11</span>)&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">NOT</span>&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`phone`</span>&nbsp;<span style="font-size: 12px;color: rgb(193, 132, 1);line-height: 26px;">int</span>(<span style="font-size: 12px;color: rgb(152, 104, 1);line-height: 26px;">11</span>)&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">NOT</span>&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`name`</span>&nbsp;<span style="font-size: 12px;color: rgb(193, 132, 1);line-height: 26px;">varchar</span>(<span style="font-size: 12px;color: rgb(152, 104, 1);line-height: 26px;">10</span>)&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">NOT</span>&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`address`</span>&nbsp;<span style="font-size: 12px;color: rgb(193, 132, 1);line-height: 26px;">varchar</span>(<span style="font-size: 12px;color: rgb(152, 104, 1);line-height: 26px;">255</span>)&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">DEFAULT</span>&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`dt`</span>&nbsp;datetime&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">DEFAULT</span>&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;PRIMARY&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">KEY</span>&nbsp;(<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`id`</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">KEY</span>&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`IX_name`</span>&nbsp;(<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`name`</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">KEY</span>&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`IX_dt`</span>&nbsp;(<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`dt`</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">KEY</span>&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`IX_dt_name`</span>&nbsp;(<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`dt`</span>,<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`name`</span>),<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">KEY</span>&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`IX_name_dt`</span>&nbsp;(<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`name`</span>,<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">`dt`</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">ENGINE</span>=<span style="font-size: 12px;color: rgb(166, 38, 164);line-height: 26px;">InnoDB</span></span> </section></pre> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">通过执行explain看出MySQL最终选择了IX_name索引。</span> </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;"> <section style="overflow-x: auto;padding: 15px 16px 16px;color: rgb(56, 58, 66);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(250, 250, 250);border-radius: 5px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 12px;">mysql&gt;&nbsp;explain&nbsp;&nbsp;select&nbsp;*&nbsp;from&nbsp;sync_test1&nbsp;<span style="font-size: 12px;color: rgb(193, 132, 1);line-height: 26px;">where</span>&nbsp;name&nbsp;like&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">'Bobby%'</span>&nbsp;and&nbsp;dt&nbsp;&gt;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">'2021-07-06'</span>;<br>+----+-------------+------------+------------+-------+-------------------------------------+---------+---------+------+------+----------+------------------------------------+<br>|&nbsp;id&nbsp;|&nbsp;select_type&nbsp;|&nbsp;table&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;partitions&nbsp;|&nbsp;<span style="font-size: 12px;color: rgb(193, 132, 1);line-height: 26px;">type</span>&nbsp;&nbsp;|&nbsp;possible_keys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;key_len&nbsp;|&nbsp;ref&nbsp;&nbsp;|&nbsp;rows&nbsp;|&nbsp;filtered&nbsp;|&nbsp;Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>+----+-------------+------------+------------+-------+-------------------------------------+---------+---------+------+------+----------+------------------------------------+<br>|&nbsp;&nbsp;1&nbsp;|&nbsp;SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;sync_test1&nbsp;|&nbsp;NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;range&nbsp;|&nbsp;IX_name,IX_dt,IX_dt_name,IX_name_dt&nbsp;|&nbsp;IX_name&nbsp;|&nbsp;12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;NULL&nbsp;|&nbsp;&nbsp;572&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;36.83&nbsp;|&nbsp;Using&nbsp;index&nbsp;condition;&nbsp;Using&nbsp;<span style="font-size: 12px;color: rgb(193, 132, 1);line-height: 26px;">where</span>&nbsp;|<br>+----+-------------+------------+------------+-------+-------------------------------------+---------+---------+------+------+----------+------------------------------------+</span> </section></pre> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">然后再打开MySQL追踪优化器Trace功能。可以看出,没有选择其他三个索引的原因均是因为在其他三个索引上使用range scan的代价均&gt;= IX_name。</span> </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;"> <section style="overflow-x: auto;padding: 15px 16px 16px;color: rgb(56, 58, 66);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(250, 250, 250);border-radius: 5px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 12px;">mysql&gt;&nbsp;select&nbsp;*&nbsp;from&nbsp;INFORMATION_SCHEMA.OPTIMIZER_TRACE\G;<br>***************************&nbsp;1.&nbsp;row&nbsp;***************************<br><br>TRACE:&nbsp;{<br>...<br><span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rows_estimation"</span>:&nbsp;[<br>{<br><span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"table"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"`sync_test1`"</span>,<br><span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"range_analysis"</span>:&nbsp;{<br><span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"table_scan"</span>:&nbsp;{<br>&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rows"</span>:&nbsp;105084,<br>&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost"</span>:&nbsp;21628<br>},<br>...<br><span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"analyzing_range_alternatives"</span>:&nbsp;{<br>&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"range_scan_alternatives"</span>:&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"IX_name"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"ranges"</span>:&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"Bobby\u0000\u0000\u0000\u0000\u0000&nbsp;&lt;=&nbsp;name&nbsp;&lt;=&nbsp;Bobbyÿÿÿÿÿ"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index_dives_for_eq_ranges"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">true</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rowid_ordered"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"using_mrr"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index_only"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rows"</span>:&nbsp;572,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost"</span>:&nbsp;687.41,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"chosen"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">true</span><br>&nbsp;&nbsp;&nbsp;&nbsp;},<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"IX_dt"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"ranges"</span>:&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"0x99aa0c0000&nbsp;&lt;&nbsp;dt"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index_dives_for_eq_ranges"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">true</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rowid_ordered"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"using_mrr"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index_only"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rows"</span>:&nbsp;38698,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost"</span>:&nbsp;46439,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"chosen"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cause"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;},<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"IX_dt_name"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"ranges"</span>:&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"0x99aa0c0000&nbsp;&lt;&nbsp;dt"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index_dives_for_eq_ranges"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">true</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rowid_ordered"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"using_mrr"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index_only"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rows"</span>:&nbsp;38292,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost"</span>:&nbsp;45951,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"chosen"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cause"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;},<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"IX_name_dt"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"ranges"</span>:&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"Bobby\u0000\u0000\u0000\u0000\u0000&nbsp;&lt;=&nbsp;name&nbsp;&lt;=&nbsp;Bobbyÿÿÿÿÿ"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index_dives_for_eq_ranges"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">true</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rowid_ordered"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"using_mrr"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index_only"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rows"</span>:&nbsp;572,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost"</span>:&nbsp;687.41,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"chosen"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cause"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;],<br>&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"analyzing_roworder_intersect"</span>:&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"usable"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cause"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"too_few_roworder_scans"</span><br>&nbsp;&nbsp;}<br>},<br><span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"chosen_range_access_summary"</span>:&nbsp;{<br>&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"range_access_plan"</span>:&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"type"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"range_scan"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"index"</span>:&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"IX_name"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rows"</span>:&nbsp;572,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"ranges"</span>:&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"Bobby\u0000\u0000\u0000\u0000\u0000&nbsp;&lt;=&nbsp;name&nbsp;&lt;=&nbsp;Bobbyÿÿÿÿÿ"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;]<br>&nbsp;&nbsp;},<br>&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"rows_for_plan"</span>:&nbsp;572,<br>&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"cost_for_plan"</span>:&nbsp;687.41,<br>&nbsp;&nbsp;<span style="font-size: 12px;color: rgb(80, 161, 79);line-height: 26px;">"chosen"</span>:&nbsp;<span style="font-size: 12px;color: rgb(1, 132, 187);line-height: 26px;">true</span><br>}<br>...<br>}</span> </section></pre> <section style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-left: 0px;margin-right: 0px;"> <span style="font-size: 15px;">下面我们根据代价模型来推演一下代价的计算过程:</span> </section> <ol data-tool="mdnice编辑器" style="margin: 8px 0px;padding-left: 25px;" class="list-paddingleft-1"> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 14px;">走全表扫描的代价:io_cost + cpu_cost = (数据页个数 * io_block_read_cost)+ (数据行数 * row_evaluate_cost + 1.1) &nbsp;= (data_length / block_size + 1)+ (rows * 0.2 + 1.1) = &nbsp;(9977856 / 16384 + 1) + (105084 * 0.2 + 1.1) = &nbsp;21627.9。</span> </section></li> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 14px;">走二级索引IX_name的代价:io_cost + cpu_cost = (预估范围行数 * io_block_read_cost + 1) + (数据行数 * row_evaluate_cost + 0.01) = &nbsp;(572 * 1 + &nbsp;1) + (572*0.2 + 0.01) = 687.41。</span> </section></li> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="font-size: 14px;">走二级索引IX_dt的代价:io_cost + cpu_cost = (预估范围行数 * io_block_read_cost + 1) + (数据行数 * row_evaluate_cost + 0.01) &nbsp;= (38698 * 1 + 1) + (38698*0.2 + 0.01) = 46438.61。</span> </section></li> <li style="font-size: 14px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px

舒服了,踩到一个关于分布式锁的非比寻常的BUG!

作者:微信小助手

<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></span><span style="background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);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: 16px;text-align: left;">提到分布式锁,大家一般都会想到 Redis。</span></p> <p data-tool="mdnice编辑器" style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">想到 Redis,一部分同学会说到 Redisson。</p> <p data-tool="mdnice编辑器" style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">那么说到 Redisson,就不得不掰扯掰扯一下它的“看门狗”机制了。</p> <p data-tool="mdnice编辑器" style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">所以你以为这篇文章我要给你讲“看门狗”吗?</p> <p data-tool="mdnice编辑器" style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">不是,我主要是想给你汇报一下我最近研究的由于引入“看门狗”之后,给 Redisson 带来的两个看起来就心里一紧的 bug :</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;visibility: visible;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);visibility: visible;"> 看门狗不生效的 BUG。 </section></li> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);visibility: visible;"> 看门狗导致死锁的 BUG。 </section></li> </ul> <p data-tool="mdnice编辑器" style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">为了能让你丝滑入戏,我还是先简单的给你铺垫一下,Redisson 的看门狗到底是个啥东西。</p> <p style="margin: 0px 0px 0em;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: center;visibility: visible;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="1.0449897750511248" data-s="300,640" src="/upload/d5cbd1171e44db40fe2f39de080c776e.png" data-type="png" data-w="978" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;visibility: visible !important;width: 249px !important;"></p> <h2 data-tool="mdnice编辑器"><span style="color: rgb(123, 12, 0);font-size: 18px;"><strong>看门狗描述</strong></span><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"></h2> <p data-tool="mdnice编辑器" style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">你去看 Redisson 的 wiki 文档,在锁的这一部分,开篇就提到了一个单词:watchdog</p> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgb(255, 249, 249);visibility: visible;"> <p style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;font-size: 16px;color: black;line-height: 26px;visibility: visible;">https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizer<span style="color: rgb(51, 51, 51);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: 17px;text-align: justify;"></span></p> </blockquote> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);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: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;visibility: visible;"> <img class="rich_pages wxw-img" data-rat

这个队列的思路真的好,现在它是我简历上的亮点了。

作者:微信小助手

<section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">前几天在一个开源项目的 github 里面看到这样的一个 pr:</span> </section> <section style="font-size: 16px;color: black;padding: 0px 10px;word-spacing: 0px;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;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.12454479242534595" src="/upload/d6cda315b351563981c14d9731a5743.png" data-type="png" data-w="1373" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">光是看这个名字,里面有个 MemorySafe,我就有点陷进去了。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">我先给你看看这个东西:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.28969359331476324" src="/upload/cc473917e17f350930c16b7b32757810.png" data-type="png" data-w="718" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个肯定很眼熟吧?我是从阿里巴巴开发规范中截的图。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">为什么不建议使用 &nbsp;FixedThreadPool 和 SingleThreadPool 呢?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">因为队列太长了,请求会堆积,请求一堆积,容易造成 OOM。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">那么问题又来了:前面提到的线程池用的队列是什么队列呢?</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.4984984984984985" src="/upload/f19d9c9b34d95801087b769b7b9df2d3.png" data-type="png" data-w="666" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">用的是没有指定长度的 LinkedBlockingQueue。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">没有指定长度,默认长度是 Integer.MAX_VALUE,可以理解为无界队列了:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.2611464968152866" src="/upload/db821b8f1faf37f7ec78a9d9003db3b5.png" data-type="png" data-w="471" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,在我的认知里面,使用 LinkedBlockingQueue 是可能会导致 OOM 的。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">如果想避免这个 OOM 就需要在初始化的时候指定一个合理的值。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">“合理的值”,听起来轻描淡写的四个字,但是这个值到底是多少呢,你说的准吗?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">基本上说不准。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,当我看到 pr 上的 MemorySafeLinkedBlockingQueue 这个名字的时候,我就陷进去了。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">在 LinkedBlockingQueue 前面加上了 MemorySafe 这个限定词。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">表示这是一个内存安全的 LinkedBlockingQueue。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">于是,我想要研究一下到底是怎么样来实现“安全”的,所以啪的一下就点进去了,很快啊。</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" src="/upload/8ab34ee4600d01c8deb41472218ac1ba.png" data-cropx1="0" data-cropx2="435" data-cropy1="0" data-cropy2="417" data-ratio="0.9586206896551724" src="https://mmbiz.qpic.cn/mmbiz_jpg/ELQw2WCMgt3Kbp8TCq9H2KVCy5hCT6yB2y4wzICpMRrrU2TDMgcH2Av1eIyyyYsXMANJ0epEhB9NATmobn6dCQ/640?wx_fmt=jpeg" data-type="jpeg" data-w="435" style="display: block;margin: 0px auto;max-width: 100%;width: 242px;height: 232px;"> </figure> </section> <h2 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-bottom: 2px solid rgb(239, 112, 96);line-height: 1.75em;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px 3px 0px 0px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;font-size: 15px;overflow-wrap: break-word !important;box-sizing: border-box !important;">MemorySafeLBQ</span></h2> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">在这个 pr 里面我们看一下它主要是想干个什么事儿:</span> </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;background: rgb(255, 249, 249);"> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">https://github.com/apache/dubbo/pull/10021</span> </section> </blockquote> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.3674052894924946" src="/upload/ee26c4c8542abf98e24d391dace2fa71.png" data-type="png" data-w="1399" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">提供代码的哥们是这样描述它的功能的:</span> </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;background: rgb(255, 249, 249);"> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">可以完全解决因为 LinkedBlockingQueue 造成的 OOM 问题,而且不依赖 instrumentation,比 MemoryLimitedLinkedBlockingQueue 更好用。</span> </section> </blockquote> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">然后可以看到这次提交涉及到 7 个文件。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">实际上真正核心的代码是这两个:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.9017857142857143" src="/upload/f206c9c0deb88ee3c18b21675e08a0c7.png" data-type="png" data-w="1008" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">但是不要慌,先眼熟一下这两个类,然后我先按下不表。先追根溯源,从源头上讲。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这两个类的名字太长了,所以先约定一下,在本文中,<strong style="font-weight: bold;color: black;">我用 MemoryLimitedLBQ 来代替 MemoryLimitedLinkedBlockingQueue。用 MemorySafeLBQ 来代替 MemorySafeLinkedBlockingQueue。</strong></span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.9384965831435079" src="/upload/5774b932136bb2468b1ed2c22c81d412.png" data-type="png" data-w="439" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">可以看到,在 pr 里面它还提到了“比 MemoryLimitedLBQ 更好用”。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">也就是说,它是用来替代 MemoryLimitedLBQ 这个类的。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个类从命名上也看得出来,也是一个 LinkedBlockingQueue,但是它的限定词是 MemoryLimited,可以限制内存的。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">我找了一下,这个类对应的 pr 是这个:</span> </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;background: rgb(255, 249, 249);"> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">https://github.com/apache/dubbo/pull/9722</span> </section> </blockquote> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.41395623891188643" src="/upload/c9f92420c2406311ac79e96a65630e6f.png" data-type="png" data-w="1691" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">在这个 pr 里面,有大佬问他:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.1488138030194105" src="/upload/4f5650cd2ea14a213db7826541cb969e.png" data-type="png" data-w="1391" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">你这个新队列实现的意义或目的是什么?你能不能说出当前版本库中需要被这个队列取代的队列?这样我们才好决定是否使用这个队列。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">也就是说他只是提交了一个新的队列,但是并没有说到应用场景是什么,导致官方不知道该不该接受这个 pr。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">于是,他补充了一个回复:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5082555635319455" src="/upload/416a15fe96351c011da31a72393fbf11.png" data-type="png" data-w="1393" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">就是拿的 FixedThreadPool 做的示例。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">在这个里面,就使用了无参的 LinkedBlockingQueue,所以会有 OOM 的风险。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">那么就可以使用 MemoryLimitedLBQ 来代替这个队列。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">比如,我可以限制这个队列可以使用的最大内存为 100M,通过限制内存的方式来达到避免 OOM 的目的。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">好,到这里我先给你梳理一下。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">首先应该是有一个叫 MemoryLimitedLBQ 的队列,它可以限制这个队列最大可以占用的内存。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">然后,由于某些原因,又出现了一个叫做 MemorySafeLBQ 的队列,宣称比它更好用,所以来取代它。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,接下来我就要梳理清楚三个问题:</span> </section> <ul data-tool="mdnice编辑器" style="margin: 8px 0px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;text-align: left;color: rgb(1, 1, 1);font-weight: 500;line-height: 1.75em;"> <span style="font-size: 15px;">MemoryLimitedLBQ 的实现原理是什么?</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;text-align: left;color: rgb(1, 1, 1);font-weight: 500;line-height: 1.75em;"> <span style="font-size: 15px;">MemorySafeLBQ 的实现原理是什么?</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;text-align: left;color: rgb(1, 1, 1);font-weight: 500;line-height: 1.75em;"> <span style="font-size: 15px;">MemorySafeLBQ 为什么比 MemoryLimitedLBQ 更好用?</span> </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;line-height: 1.75em;"><span style="font-size: 15px;"><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">MemoryLimitedLBQ</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;"> </span></span></h2> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">别看这个玩意我是在 Dubbo 的 pr 里面看到的,但是它本质上是一个队列的实现方式。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,完全可以脱离于框架而存在。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">也就是说,你打开下面这个链接,然后直接把相关的两个类粘出来,就可以跑起来,为你所用:</span> </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;background: rgb(255, 249, 249);"> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">https://github.com/apache/dubbo/pull/9722/files</span> </section> </blockquote> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">我先给你看看 MemoryLimitedLBQ 这个类,它就是继承自 LinkedBlockingQueue,然后重写了它的几个核心方法。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">只是自定义了一个 memoryLimiter 的对象,然后每个核心方法里面都操作了 memoryLimiter 对象:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="1.3580470162748643" src="/upload/bb5766f46c84ba6bda240e717d8bde50.png" data-type="png" data-w="1106" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以真正的秘密就藏在 memoryLimiter 对象里面。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">比如,我带你看看这个 put 方法:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.3020030816640986" src="/upload/f3da8a4e2a95c5237da4927511265c34.png" data-type="png" data-w="649" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这里面调用了 memoryLimiter 对象的 acquireInterruptibly 方法。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">在解读 acquireInterruptibly 方法之前,我们先关注一下它的几个成员变量:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.878619153674833" src="/upload/6a0827fc1c65cb2b16362919759f5ee7.png" data-type="png" data-w="898" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <ul data-tool="mdnice编辑器" style="margin: 8px 0px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;text-align: left;color: rgb(1, 1, 1);font-weight: 500;line-height: 1.75em;"> <span style="font-size: 15px;">memoryLimit 就是表示这个队列最大所能容纳的大小。</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;text-align: left;color: rgb(1, 1, 1);font-weight: 500;line-height: 1.75em;"> <span style="font-size: 15px;">memory 是 LongAdder 类型,表示的是当前已经使用的大小。</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;text-align: left;color: rgb(1, 1, 1);font-weight: 500;line-height: 1.75em;"> <span style="font-size: 15px;">acquireLock、notLimited、releaseLock、notEmpty 是锁相关的参数,从名字上可以知道,往队列里面放元素和释放队列里面的元素都需要获取对应的锁。</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;text-align: left;color: rgb(1, 1, 1);font-weight: 500;line-height: 1.75em;"> <span style="font-size: 15px;">inst 这个参数是 Instrumentation 类型的。</span> </section></li> </ul> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">前面几个参数至少我还很眼熟的,但是这个 inst 就有点奇怪了。</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="1.0943396226415094" src="/upload/359508af5277467fe239c99e98650eca.png" data-type="png" data-w="318" style="display: block;margin: 0px auto;max-width: 100%;width: 193px;height: 211px;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这玩意日常开发中基本上用不上,但是用好了,这就是个黑科技了。很多工具都是基于这个玩意来实现的,比如大名鼎鼎的 Arthas。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">它可以更加方便的做字节码增强操作,允许我们对已经加载甚至还没有被加载的类进行修改的操作,实现类似于性能监控的功能。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">可以说 Instrumentation 就是 memoryLimiter 的关键点:</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">比如在 memoryLimiter 的 acquireInterruptibly 方法里面,它是这样的用的:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.46136618141097424" src="/upload/327d3d364e22b46c5c3db95a8720bb36.png" data-type="png" data-w="893" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">看方法名称你也知道了,get 这个 object 的 size,这个 object 就是方法的入参,也就是要放入到队列里面的元素。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">为了证明我没有乱说,我带你看看这个方法上的注释:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.2089116143170197" src="/upload/e3a0e62585cf2103433986e015c81d10.png" data-type="png" data-w="1369" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;background: rgb(255, 249, 249);"> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">an implementation-specific approximation of the amount of storage consumed by the specified object</span> </section> </blockquote> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">注意这个单词:approximation.</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这可是正儿八经的四级词汇,还是 a 开头的,你要是不眼熟的话可是要挨板子的。</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.39232053422370616" src="/upload/12cc5c3bc65094f83e5589574c12184b.png" data-type="png" data-w="599" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">整句话翻译过来就是:返回指定对象所消耗的存储量的一个特定实现的近似值。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">再说的直白点就是你传进来的这个对象,在内存里面到底占用了多长的长度,这个长度不是一个非常精确的值。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,理解了 inst.getObjectSize(e) 这行代码,我们再仔细看看 acquireInterruptibly 是怎么样的:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.8314977973568282" src="/upload/46094ade098026cb789fcf7c80742971.png" data-type="png" data-w="908" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">首先,两个标号为 ① 的地方,表示操作这个方法是要上锁的,整个 try 里面的方法是线程安全的。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">然后标号为 ② 的里面干了什么事儿?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">就是计算 memory 这个 LongAdder 类型的 sum 值加上当前这个对象的值之后,是不是大于或者等于 memoryLimit。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">如果计算后的值真的超过了 memoryLimit,那么说明需要阻塞一下下了,调用 notLimited.await() 方法。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">如果没有超过 memoryLimit,说明还能往队列里面放东西,那么就更新 memory 的值。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">接着到了标号为 ③ 的地方。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">来到这里,再次判断一下当前已经使用的值是否没有超过 memoryLimit,如果是的话,就调用 notLimited.signal() 方法,唤醒一下之前由于 memoryLimit 参数限制导致不能放入的对象。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">整个逻辑非常的清晰。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">而整个逻辑里面的核心逻辑就是调用 Instrumentation 类型的 getObjectSize 方法获得当前放入对象的一个 size,并判断当前已经使用的值加上这个 size 之后,是否大于了我们设置的最大值。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,你用脚趾头猜也能猜到了,在 release 方法里面,肯定也是计算当前对象的 size,然后再从 memory 里面减出去:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.7993311036789298" src="/upload/7a3d7357ce6cfeef7449dd7aabb33ff4.png" data-type="png" data-w="897" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">说穿了,也就这么屁大点事儿。</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="1.0870786516853932" src="/upload/21594fd61daaabd60b0e4b34ec2e4c8f.png" data-type="png" data-w="356" style="display: block;margin: 0px auto;max-width: 100%;width: 216px;height: 235px;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">然后,你再次审视一下这个 acquireInterruptibly 方法的 try 代码块里面的逻辑,你有没有发现什么 BUG:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.6444929116684842" src="/upload/3d20d116d8cf94c63a5524809a586f32.png" data-type="png" data-w="917" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">如果你没反应过来,那我再提个醒:你认真的分析一下 sum 这个局部变量是不是有点不妥?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">你要是还没反应过来,那我直接给你上个代码。后面有一次提交,是把 sum 修改为了 memory.sum() :</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5328185328185329" src="/upload/8a4250a0ed24664f6e542c5a7406cab0.png" data-type="png" data-w="1554" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">为什么这样改呢?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">我给你说个场景,假设我们的 memoryLimit 是 1000,当前已经使用的 memory 是 800,也就是 sum 是 800。这个时候我要放的元素计算出来的 size 是 300,也就是 objectSize 是 300。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">sum+objectSize=1100,比 memoryLimit 的值大,是不是在这个 while 判断的时候被拦截住了:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.600656455142232" src="/upload/8f84e7ea3272a8dc65c32ec851072658.png" data-type="png" data-w="914" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">之后,假设队列里面又释放了一个 size 为 600 的对象。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个时候执行 memory.add(-objectSize) 方法,memory 变为 200:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.7064116985376828" src="/upload/b96828634b501b231ee45f34e3563004.png" data-type="png" data-w="889" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">那么会调用 signalNotLimited 方法,唤醒这个被拦截的这个哥们:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.6446469248291572" src="/upload/7324a205b65229c059a84cec1e4f185f.png" data-type="png" data-w="439" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个哥们一被唤醒,一看代码:</span> </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;"> <section style="overflow-x: auto;padding: 15px 16px 16px;color: rgb(51, 51, 51);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(248, 248, 248);border-radius: 5px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <span style="font-size: 15px;"><span style="color: rgb(51, 51, 51);font-weight: bold;line-height: 26px;">while</span>&nbsp;(sum&nbsp;+&nbsp;objectSize&nbsp;&gt;=&nbsp;memoryLimit)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;notLimited.await();<br>}<br></span> </section></pre> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">心里想:我这里的 sum 是 800,objectSize 是 300,还是大于 memoryLimit 啊,把我唤醒干啥玩意,傻逼吗?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">那么你说,它骂的是谁?</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.8873239436619719" src="/upload/50f2b3b64bb2c90fe2bab1597b88f072.png" data-type="png" data-w="426" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个地方的代码肯定得这样,每次都查看最新的 memory 值才行:</span> </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;"> <section style="overflow-x: auto;padding: 15px 16px 16px;color: rgb(51, 51, 51);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(248, 248, 248);border-radius: 5px;margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <span style="font-size: 15px;"><span style="color: rgb(51, 51, 51);font-weight: bold;line-height: 26px;">while</span>&nbsp;(memory.sum()&nbsp;+&nbsp;objectSize&nbsp;&gt;=&nbsp;memoryLimit)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;notLimited.await();<br>}<br></span> </section></pre> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,这个地方是个 BUG,还是个死循环的 BUG。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">前面代码截图中还出现了一个链接,就是说的这个 BUG:</span> </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;background: rgb(255, 249, 249);"> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">https://github.com/apache/incubator-shenyu/pull/3335</span> </section> </blockquote> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.41785714285714287" src="/upload/31c37c382f39e1e7f82c5a7f215e5352.png" data-type="png" data-w="1400" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">另外,你可以看到链接中的项目名称是 incubator-shenyu,这是一个开源的 API 网关:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5833333333333334" src="/upload/7ca00d34472e7992226185526213778d.png" data-type="png" data-w="1152" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;"><strong style="font-weight: bold;color: black;">本文中的 MemoryLimitedLBQ 和 MemorySafeLBQ 最先都是出自这个开源项目。</strong></span> </section> <h2 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;line-height: 1.75em;"><span style="font-size: 15px;"><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">MemorySafeLBQ</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;"> </span></span></h2> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">前面了解了 MemoryLimitedLBQ 的基本原理。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">接下来我带你看看 MemorySafeLBQ 这个玩意。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">它的源码可以通过这个链接直接获取到:</span> </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;background: rgb(255, 249, 249);"> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">https://github.com/apache/dubbo/pull/10021/files</span> </section> </blockquote> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">也是拿出来就可以放到自己的项目跑,把文件作者修改为自己的名字的那种。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">让我们回到最开始的地方:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.3674052894924946" src="/upload/ee26c4c8542abf98e24d391dace2fa71.png" data-type="png" data-w="1399" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个 pr 里面说了,我搞 MemorySafeLBQ 出来,就是为了替代 MemoryLimitedLBQ 的,因为我比它好用,而且我还不依赖于 Instrumentation。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">但是看了源码之后,会发现其实思路都是差不多的。只不过 MemorySafeLBQ 属于是反其道而行之。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">怎么个“反其道”法呢?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">看一下源码:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.6656314699792961" src="/upload/54bf22d47dfee1ec5d29a5b6c8aa11d8.png" data-type="png" data-w="966" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">MemorySafeLBQ 还是继承自 LinkedBlockingQueue,只是多了一个自定义的成员变量,叫做 maxFreeMemory,初始值是 256 * 1024 * 1024。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个变量的名字就非常值得注意,你再细细品品。maxFreeMemory,最大的剩余内存,默认是 256M。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">前面一节讲的 MemoryLimitedLBQ 限制的是这个队列最多能使用多少空间,是站在队列的角度。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">而 MemorySafeLBQ 限制的是 JVM 里面的剩余空间。比如默认就是当整个 JVM 只剩下 256M 可用内存的时候,再往队列里面加元素我就不让你加了。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">因为整个内存都比较吃紧了,队列就不能无限制的继续添加了,从这个角度来规避了 OOM 的风险。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这样的一个反其道而行之。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">另外,它说它不依赖 Instrumentation 了,那么它怎么检测内存的使用情况呢?</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.17695852534562212" src="/upload/c4d95c9b9124de12c2afc2fbe597304b.png" data-type="png" data-w="1085" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">使用的是 ManagementFactory 里面的 MemoryMXBean。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个 MemoryMXBean 其实你一点也不陌生。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">JConsole 你用过吧?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">下面这个界面进去过吧?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这些信息就是从 ManagementFactory 里面拿出来的:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.6791383219954649" src="/upload/3771e93172a8d1ebaed346734d7510d6.png" data-type="png" data-w="882" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,确实它没有使用 Instrumentation,但是它使用了 ManagementFactory。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">目的都是为了获取内存的运行状态。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">那么怎么看出来它比 MemoryLimitedLBQ 更好用呢?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">我看了,关键方法就是这个 hasRemainedMemory,在调用 put、offer 方法之前就要先调用这个方法:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.49922360248447206" src="/upload/2e1737cdea29e698000d1067213162fd.png" data-type="png" data-w="1288" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">而且你看 MemorySafeLBQ 只是重写了放入元素的 put、offer 方法,并不关注移除元素。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">为什么呢?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">因为它的设计理念是只关心添加元素时候的剩余空间大小,它甚至都不会去关注当前这个元素的大小。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">而还记得前面讲的 MemoryLimitedLBQ 吗?它里面还计算了每个元素的大小,然后搞了一个变量来累加。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">MemoryLimitedLBQ 的 hasRemainedMemory 方法里面也只有一行代码,其中 maxFreeMemory 是类初始化的时候就指定好了。那么关键的代码就是 MemoryLimitCalculator.maxAvailable()。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以我们看看 MemoryLimitCalculator 的源码。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这个类的源码写的非常的简单,我全部截完都只有这么一点内容,全部加起来也就是 20 多行代码:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.9286666666666666" src="/upload/45d5e6f4f2886ca3cd31c4e7ccca70f0.png" data-type="png" data-w="1500" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">而整个方法的核心就是我框起来的 static 代码块,里面一共有三行代码。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">第一行是调用 refresh 方法,也就是对 maxAvilable 这个参数进行重新赋值,这个参数代表的意思是当前还可以使用的 JVM 内存。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">第二行是注入了一个每 50ms 运行一次的定时任务。到点了,就触发一下 refresh 方法,保证 maxAvilable 参数的准实时性。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">第三行是加入了 JVM 的 ShutdownHook,停服务的时候需要把这个定时任务给停了,达到优雅停机的目的。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">核心逻辑就这么点。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">从我的角度来说,确实是比 MemoryLimitedLBQ 使用起来更简单,更好用。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">最后,再看看作者提供的 MemorySafeLBQ 测试用例,我补充了一点注释,很好理解,自己去品,不再多说:</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5469988674971688" src="/upload/b2df38380e0a50e1cae148e1645bb49c.png" data-type="png" data-w="883" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> </section> <h2 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;font-weight: bold;color: black;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;line-height: 1.75em;"><span style="font-size: 15px;"><span style="display: inline-block;font-weight: bold;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">它是你的了</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;"> </span></span></h2> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">文章里面提到的 MemoryLimitedLBQ 和 MemorySafeLBQ,我说了,这两个玩意是完全独立于框架的,代码直接粘过来就可以用。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">代码也没几行,不管是用 Instrumentation 还是 ManagementFactory,核心思想都是限制内存。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">思路扩展一下,比如我们有的项目里面用 Map 来做本地缓存,就会放很多元素进去,也会有 OOM 的风险,那么通过前面说的思路,是不是就找到了一个问题的解决方案?</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">所以,思路是很重要的,掌握到了这个思路,面试的时候也能多掰扯几句嘛。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">再比如,我看到这个玩意的时候,联想到了之前写过的线程池参数动态调整。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">就拿 MemorySafeLBQ 这个队列来说,它里面的 maxFreeMemory 这个参数,可不可以做成动态调整的?</span> </section> <section style="margin-left: 0px;margin-right: 0px;line-height: 1.75em;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.8240963855421687" src="/upload/836d14512bfadc44ebf70ccc114f1467.png" data-type="png" data-w="415" style="display: block;margin: 0px auto;max-width: 100%;width: 340px;height: 280px;"> </figure> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">不外乎就是把之前的队列长度可调整修改为了队列占用的内存空间可调整。一个参数的变化而已,实现方案可以直接套用。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">这些都是我从开源项目里面看到的,但是在我看到的那一刻,它就是我的。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">现在,我把它写出来,分享给你,它就是你的了。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">不客气,来个三连就行。</span> </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 1.75em;"> <span style="font-size: 15px;">好了,那本文的技术部分就到这里啦。</span> </section>

别再写代码测试并发了,太 Low!模拟并发的 4 种方法,还有谁不会??

作者:微信小助手

<section data-class="_mbEditor" data-id="132148" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"> <section data-tools-id="46476" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"> <section style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Arial;border-width: 0px 0px 2px;border-style: none none solid;color: rgb(49, 147, 105);border-color: rgb(239, 112, 96);visibility: visible;"> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 32px;display: inline-block;font-weight: bold;font-size: 16px;line-height: 28px;color: rgb(239, 112, 96);visibility: visible;">Postman</p> </section> </section> </section> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;visibility: visible;">Postman是一个款http请求模拟工具</span></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"></p> <p style="margin: 0px 0px 0em;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: center;visibility: visible;"><img class="rich_pages wxw-img" data-ratio="1.156596794081381" src="/upload/9f245ef679505212cf69d188ebf66960.png" data-type="png" data-w="811" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;float: none;visibility: visible !important;width: 556px !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;visibility: visible;">首先演示一下postman最基本的使用</span></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;visibility: visible;">创建一个Springboot项目,测试的代码如下:</span></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"><br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;visibility: visible;"> <pre style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;background: none;visibility: visible;"><code style="margin: 0px 0.15em;padding: 5.95px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;border-radius: 4px;font-size: 0.85em;background: rgb(35, 36, 31);color: rgb(248, 248, 242);display: block;overflow-x: auto;white-space: nowrap;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 12px;font-family: CourierNewPS-ItalicMT;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;visibility: visible;">import</span>&nbsp;<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;visibility: visible;">org</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 105px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.springframework</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.web</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.bind</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 72px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.annotation</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 73px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.GetMapping</span>;<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;visibility: visible;">import</span>&nbsp;<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;visibility: visible;">org</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 105px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.springframework</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.web</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.bind</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 72px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.annotation</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 99px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.RequestMapping</span>;<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;visibility: visible;">import</span>&nbsp;<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;visibility: visible;">org</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 105px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.springframework</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.web</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.bind</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 72px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.annotation</span><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(166, 226, 46);background: rgba(0, 0, 0, 0);display: inline;width: 99px;text-decoration: none solid rgb(166, 226, 46);font-weight: 400;font-style: normal;visibility: visible;">.RestController</span>;<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"><br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;">@<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 93px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;visibility: visible;">RestController</span><br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;">@RequestMapping(<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(230, 219, 116);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(230, 219, 116);font-weight: 400;font-style: normal;visibility: visible;">"test"</span>)<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;">public class TestConrtoller {<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"><br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;">&nbsp;&nbsp;&nbsp;&nbsp;@<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 66px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;">GetMapping</span>("<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;">demo</span>")<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;public String testDemo() {<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;">return</span>&nbsp;"<span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: CourierNewPS-ItalicMT;font-size: 12px;color: rgb(249, 38, 114);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(249, 38, 114);font-weight: 400;font-style: normal;">result</span>~";<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;}<br mpa-from-tpl="t" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}</span></code></pre> </section> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><br></p> <p style="margin: 0px 0px 0em;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: center;"><img class="rich_pages wxw-img" data-ratio="0.24633991088478677" src="/upload/5507a24662f85e55c11fe14b872d6412.png" data-type="png" data-w="1571" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);vertical-align: bottom;float: none;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: 138.472px !important;width: 556px !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;">为了便于操作,一般会将</span></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;">http://127.0.0.1:8080 是经常使用的地址+端口号,可以设置为环境</span></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;">点击右上角的设置图标</span></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><br></p> <p style="margin: 0px 0px 0em;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: center;"><img class="rich_pages wxw-img" data-ratio="0.4130019120458891" data-type="png" data-w="523" src="/upload/c24aa9b48cf658d4f3a324781c063cbf.png" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);vertical-align: bottom;float: none;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: 217.174px !important;width: 523px !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;">选择global</span></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><br></p> <p style="margin: 0px 0px 0em;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: center;"><img class="rich_pages wxw-img" data-ratio="0.8853591160220995" data-type="png" data-w="724" src="/upload/cb8cd1740c959f4b2b36451f869f5479.png" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);vertical-align: bottom;float: none;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: 492.489px !important;width: 556px !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(34, 34, 34);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;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-style: initial;text-decoration-color: initial;text-align: left;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;">输入信息</span></p> <p style="margin: 0px;padding: 0px;outl

老大说:谁要再用double定义商品金额,就自己收拾东西走

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="white-space: normal;text-size-adjust: auto;padding-right: 10px;padding-left: 10px;line-height: 1.6;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;margin-top: -10px;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);"> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.42592592592592593" src="/upload/23679f8d3726c8bc6fb84a35a2ff74c7.png" data-type="png" data-w="3240" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <hr data-tool="mdnice编辑器" style="height: 1px;border-style: solid;border-color: rgb(53, 179, 120);margin: 1.5em auto;"> <h2 data-tool="mdnice编辑器" style="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);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;">先看现象</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">涉及诸如<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">float</code>或者<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">double</code>这两种浮点型数据的处理时,偶尔总会有一些<strong style="color: rgb(53, 179, 120);">怪怪的现象</strong>,不知道大家注意过没,举几个常见的栗子:</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">典型现象(一):条件判断超预期</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;">System.out.println(&nbsp;<span style="line-height: 26px;">1f</span>&nbsp;==&nbsp;<span style="line-height: 26px;">0.9999999f</span>&nbsp;);&nbsp;&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:false</span><br>System.out.println(&nbsp;<span style="line-height: 26px;">1f</span>&nbsp;==&nbsp;<span style="line-height: 26px;">0.99999999f</span>&nbsp;);&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:true &nbsp;&nbsp;&nbsp;纳尼?</span><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;"><strong style="color: rgb(53, 179, 120);">典型现象(二):数据转换超预期</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">float</span>&nbsp;f&nbsp;=&nbsp;<span style="line-height: 26px;">1.1f</span>;<br><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>&nbsp;d&nbsp;=&nbsp;(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">double</span>)&nbsp;f;<br>System.out.println(f);&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:1.1</span><br>System.out.println(d);&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:1.100000023841858 &nbsp;纳尼?</span><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;"><strong style="color: rgb(53, 179, 120);">典型现象(三):基本运算超预期</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;">System.out.println(&nbsp;<span style="line-height: 26px;">0.2</span>&nbsp;+&nbsp;<span style="line-height: 26px;">0.7</span>&nbsp;);&nbsp;&nbsp;<br><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:0.8999999999999999 &nbsp;&nbsp;纳尼?</span><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;"><strong style="color: rgb(53, 179, 120);">典型现象(四):数据自增超预期</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;"><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">float</span>&nbsp;f1&nbsp;=&nbsp;<span style="line-height: 26px;">8455263f</span>;<br><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>&nbsp;(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;i&nbsp;=&nbsp;<span style="line-height: 26px;">0</span>;&nbsp;i&nbsp;&lt;&nbsp;<span style="line-height: 26px;">10</span>;&nbsp;i++)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(f1);<br>&nbsp;&nbsp;&nbsp;&nbsp;f1++;<br>}<br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455263.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455264.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455265.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455266.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455267.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455268.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455269.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455270.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455271.0</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:8455272.0</span><br><br><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">float</span>&nbsp;f2&nbsp;=&nbsp;<span style="line-height: 26px;">84552631f</span>;<br><span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">for</span>&nbsp;(<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">int</span>&nbsp;i&nbsp;=&nbsp;<span style="line-height: 26px;">0</span>;&nbsp;i&nbsp;&lt;&nbsp;<span style="line-height: 26px;">10</span>;&nbsp;i++)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(f2);<br>&nbsp;&nbsp;&nbsp;&nbsp;f2++;<br>}<br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;&nbsp;&nbsp;&nbsp;打印:8.4552632E7 &nbsp;&nbsp;纳尼?不是&nbsp;+1了吗?</span><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;">看到没,这些简单场景下的使用情况都很难满足我们的需求,所以说用浮点数(包括<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">double</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">float</code>)处理问题有非常多<strong style="color: rgb(53, 179, 120);">隐晦的坑</strong>在等着咱们!</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">怪不得技术总监发狠话:谁要是敢在处理诸如&nbsp;<strong style="color: rgb(53, 179, 120);">商品金额</strong>、<strong style="color: rgb(53, 179, 120);">订单交易</strong>、以及<strong style="color: rgb(53, 179, 120);">货币计算</strong>时用浮点型数据(<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">double</code>/<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">float</code>),直接让我们走人!</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.8888888888888888" src="/upload/b4965d91e207b6a1c00ff7b79488a39d.png" data-type="png" data-w="198" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <hr data-tool="mdnice编辑器" style="height: 1px;border-style: solid;border-color: rgb(53, 179, 120);margin: 1.5em auto;"> <h2 data-tool="mdnice编辑器" style="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);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;">原因出在哪里?</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">我们就以第一个典型现象为例来分析一下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;">System.out.println(&nbsp;<span style="line-height: 26px;">1f</span>&nbsp;==&nbsp;<span style="line-height: 26px;">0.99999999f</span>&nbsp;);<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;">直接用代码去比较<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">1</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">0.99999999</code>,居然打印出<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">true</code>!</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="1.10625" src="/upload/8c38edbb78444c2f72f83e4a6ed72a04.png" data-type="png" data-w="160" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">这说明了什么?这说明了计算机压根<strong style="color: rgb(53, 179, 120);">区分不出来</strong>这两个数。这是为什么呢?</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">我们不妨来简单思考一下:</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(53, 179, 120);border-right: 0px solid rgb(53, 179, 120);color: rgb(97, 97, 97);quotes: none;background-color: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">我们知道输入的这两个浮点数只是我们人类肉眼所看到的具体数值,是我们通常所理解的十进制数,但是计算机底层在计算时可不是按照十进制来计算的,学过基本计组原理的都知道,计算机底层最终都是基于像<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">010100100100110011011</code>这种<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">0</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">1</code>二进制来完成的。</p> </blockquote> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">所以为了搞懂实际情况,我们应该将这两个十进制浮点数<strong style="color: rgb(53, 179, 120);">转化到二进制空间</strong>来看一看。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">十进制浮点数转二进制</strong>&nbsp;怎么转、怎么计算,我想这应该属于基础计算机进制转换常识,在&nbsp;<strong style="color: rgb(53, 179, 120);">《计算机组成原理》</strong>&nbsp;类似的课上肯定学过了,咱就不在此赘述了,直接给出结果(把它转换到<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">IEEE 754 Single precision 32-bit</code>,也就<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">float</code>类型对应的精度)</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;">1.0(十进制)<br> ↓<br>00111111 10000000 00000000 00000000(二进制)<br> ↓<br>0x3F800000(十六进制)<br></code></pre> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;">0.99999999(十进制)<br> ↓<br>00111111 10000000 00000000 00000000(二进制)<br> ↓<br>0x3F800000(十六进制)<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;"><strong style="color: rgb(53, 179, 120);">果不其然</strong>,这两个十进制浮点数的底层二进制表示是一毛一样的,怪不得<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">==</code>的判断结果返回<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">true</code>!</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">但是<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">1f == 0.9999999f</code>返回的结果是符合预期的,打印<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">false</code>,我们也把它们转换到二进制模式下看看情况:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;">1.0(十进制)<br> ↓<br>00111111 10000000 00000000 00000000(二进制)<br> ↓<br>0x3F800000(十六进制)<br></code></pre> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;">0.9999999(十进制)<br> ↓<br>00111111 01111111 11111111 11111110(二进制)<br> ↓<br>0x3F7FFFFE(十六进制)<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;">哦,很明显,它俩的二进制数字表示确实不一样,这是理所应当的结果。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">那么为什么<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">0.99999999</code>的底层二进制表示竟然是:<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">00111111 10000000 00000000 00000000</code>呢?</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">这不明明是浮点数<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">1.0</code>的二进制表示吗?</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">这就要谈一下浮点数的精度问题了。</p> <hr data-tool="mdnice编辑器" style="height: 1px;border-style: solid;border-color: rgb(53, 179, 120);margin: 1.5em auto;"> <h2 data-tool="mdnice编辑器" style="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);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;">浮点数的精度问题!</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">学过&nbsp;<strong style="color: rgb(53, 179, 120);">《计算机组成原理》</strong>&nbsp;这门课的小伙伴应该都知道,浮点数在计算机中的存储方式遵循<strong style="color: rgb(53, 179, 120);">IEEE 754 浮点数计数标准</strong>,可以用科学计数法表示为:</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><span style="cursor: pointer;"><span role="presentation" data-formula=" 1.M...×2^E " data-formula-type="inline-equation" style=""> <svg xmlns="http://www.w3.org/2000/svg" role="img" focusable="false" viewbox="0 -843.8 5031.2 843.8" aria-hidden="true" style="vertical-align: 0px;width: 11.383ex;height: 1.909ex;"> <g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"> <g data-mml-node="math"> <g data-mml-node="mn"> <path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path> <path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(500, 0)"></path> </g> <g data-mml-node="mi" transform="translate(778, 0)"> <path data-c="4D" d="M289 629Q289 635 232 637Q208 637 201 638T194 648Q194 649 196 659Q197 662 198 666T199 671T201 676T203 679T207 681T212 683T220 683T232 684Q238 684 262 684T307 683Q386 683 398 683T414 678Q415 674 451 396L487 117L510 154Q534 190 574 254T662 394Q837 673 839 675Q840 676 842 678T846 681L852 683H948Q965 683 988 683T1017 684Q1051 684 1051 673Q1051 668 1048 656T1045 643Q1041 637 1008 637Q968 636 957 634T939 623Q936 618 867 340T797 59Q797 55 798 54T805 50T822 48T855 46H886Q892 37 892 35Q892 19 885 5Q880 0 869 0Q864 0 828 1T736 2Q675 2 644 2T609 1Q592 1 592 11Q592 13 594 25Q598 41 602 43T625 46Q652 46 685 49Q699 52 704 61Q706 65 742 207T813 490T848 631L654 322Q458 10 453 5Q451 4 449 3Q444 0 433 0Q418 0 415 7Q413 11 374 317L335 624L267 354Q200 88 200 79Q206 46 272 46H282Q288 41 289 37T286 19Q282 3 278 1Q274 0 267 0Q265 0 255 0T221 1T157 2Q127 2 95 1T58 0Q43 0 39 2T35 11Q35 13 38 25T43 40Q45 46 65 46Q135 46 154 86Q158 92 223 354T289 629Z"></path> </g> <g data-mml-node="mo" transform="translate(1829, 0)"> <path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z"></path> </g> <g data-mml-node="mo" transform="translate(2273.7, 0)"> <path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z"></path> </g> <g data-mml-node="mo" transform="translate(2718.3, 0)"> <path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z"></path> </g> <g data-mml-node="mo" transform="translate(3163, 0)"> <path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z"></path> </g> <g data-mml-node="msup" transform="translate(3941, 0)"> <g data-mml-node="mn"> <path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path> </g> <g data-mml-node="mi" transform="translate(500, 363) scale(0.707)"> <path data-c="45" d="M492 213Q472 213 472 226Q472 230 477 250T482 285Q482 316 461 323T364 330H312Q311 328 277 192T243 52Q243 48 254 48T334 46Q428 46 458 48T518 61Q567 77 599 117T670 248Q680 270 683 272Q690 274 698 274Q718 274 718 261Q613 7 608 2Q605 0 322 0H133Q31 0 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H757Q764 676 764 669Q764 664 751 557T737 447Q735 440 717 440H705Q698 445 698 453L701 476Q704 500 704 528Q704 558 697 578T678 609T643 625T596 632T532 634H485Q397 633 392 631Q388 629 386 622Q385 619 355 499T324 377Q347 376 372 376H398Q464 376 489 391T534 472Q538 488 540 490T557 493Q562 493 565 493T570 492T572 491T574 487T577 483L544 351Q511 218 508 216Q505 213 492 213Z"></path> </g> </g> </g> </g> </svg></span></span></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">只要给出:<strong style="color: rgb(53, 179, 120);">符号(S)</strong>、<strong style="color: rgb(53, 179, 120);">阶码部分(E)</strong>、<strong style="color: rgb(53, 179, 120);">尾数部分(M)</strong>&nbsp;这三个维度的信息,一个浮点数的表示就完全确定下来了,所以<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">float</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">double</code>这两种浮点数在内存中的存储结构如下所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.23749119097956306" src="/upload/522d133b6772da5b3ca27c7aea4d4a71.png" data-type="png" data-w="2838" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="0.21780821917808219" src="/upload/94b6ff3972030d6030d08406b44d2434.png" data-type="png" data-w="2920" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">1、符号部分(S)</strong></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">0</code>-正&nbsp;&nbsp;<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">1</code>-负</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">2、阶码部分(E)(指数部分)</strong>:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 对于 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">float</code>型浮点数,指数部分 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">8</code>位,考虑可正可负,因此可以表示的指数范围为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">-127 ~ 128</code> </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 对于 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">double</code>型浮点数,指数部分 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">11</code>位,考虑可正可负,因此可以表示的指数范围为 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">-1023 ~ 1024</code> </section></li> </ul> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">3、尾数部分(M)</strong>:</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">浮点数的精度是由尾数的位数来决定的:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 对于 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">float</code>型浮点数,尾数部分 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">23</code>位,换算成十进制就是&nbsp; <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">2^23=8388608</code>,所以十进制精度只有 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">6 ~ 7</code>位; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 对于 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">double</code>型浮点数,尾数部分 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">52</code>位,换算成十进制就是&nbsp; <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">2^52 = 4503599627370496</code>,所以十进制精度只有 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">15 ~ 16</code>位 </section></li> </ul> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">所以对于上面的数值<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">0.99999999f</code>,很明显已经超过了<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">float</code>型浮点数据的精度范围,出问题也是在所难免的。</p> <hr data-tool="mdnice编辑器" style="height: 1px;border-style: solid;border-color: rgb(53, 179, 120);margin: 1.5em auto;"> <h2 data-tool="mdnice编辑器" style="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);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;">精度问题如何解决</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">所以如果涉及<strong style="color: rgb(53, 179, 120);">商品金额</strong>、<strong style="color: rgb(53, 179, 120);">交易值</strong>、<strong style="color: rgb(53, 179, 120);">货币计算</strong>等这种对精度要求很高的场景该怎么办呢?</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">方法一:用字符串或者数组解决多位数问题</strong></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">校招刷过算法题的小伙伴们应该都知道,用字符串或者数组表示大数是一个典型的解题思路。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">比如经典面试题:<strong style="color: rgb(53, 179, 120);">编写两个任意位数大数的加法、减法、乘法等运算</strong>。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">这时候我们我们可以用字符串或者数组来表示这种大数,然后按照四则运算的规则来手动模拟出具体计算过程,中间还需要考虑各种诸如:<strong style="color: rgb(53, 179, 120);">进位</strong>、<strong style="color: rgb(53, 179, 120);">借位</strong>、<strong style="color: rgb(53, 179, 120);">符号</strong>等等问题的处理,确实十分复杂,本文不做赘述。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">方法二:Java的大数类是个好东西</strong></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">JDK早已为我们考虑到了浮点数的计算精度问题,因此提供了专用于高精度数值计算的<strong style="color: rgb(53, 179, 120);">大数类</strong>来方便我们使用。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">在前文<a href="https://mp.weixin.qq.com/s?__biz=MzU4ODI1MjA3NQ==&amp;mid=2247485421&amp;idx=1&amp;sn=c4543020e3d347267dbd8491ee48d2d5&amp;scene=21#wechat_redirect" style="overflow-wrap: break-word;font-weight: bold;color: rgb(53, 179, 120);border-bottom: 1px solid rgb(53, 179, 120);" data-linktype="2">《不瞒你说,我最近跟Java源码杠上了》</a>中说过,Java的大数类位于<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">java.math</code>包下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"> <img data-ratio="1.1428571428571428" src="/upload/c05ba76399906763d03f5f84479bf2d.png" data-type="png" data-w="826" style="display: block;margin-right: auto;margin-left: auto;width: auto;"> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可以看到,常用的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">BigInteger</code>&nbsp;和&nbsp;<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">BigDecimal</code>就是处理高精度数值计算的利器。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background-color: rgb(39, 40, 34);color: rgb(221, 221, 221);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;font-size: 12px;background-position: initial initial;background-repeat: initial initial;">BigDecimal&nbsp;num3&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(&nbsp;Double.toString(&nbsp;<span style="line-height: 26px;">1.0f</span>&nbsp;)&nbsp;);<br>BigDecimal&nbsp;num4&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(&nbsp;Double.toString(&nbsp;<span style="line-height: 26px;">0.99999999f</span>&nbsp;)&nbsp;);<br>System.out.println(&nbsp;num3&nbsp;==&nbsp;num4&nbsp;);&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印&nbsp;false</span><br><br>BigDecimal&nbsp;num1&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(&nbsp;Double.toString(&nbsp;<span style="line-height: 26px;">0.2</span>&nbsp;)&nbsp;);<br>BigDecimal&nbsp;num2&nbsp;=&nbsp;<span style="color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;">new</span>&nbsp;BigDecimal(&nbsp;Double.toString(&nbsp;<span style="line-height: 26px;">0.7</span>&nbsp;)&nbsp;);<br><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;加</span><br>System.out.println(&nbsp;num1.add(&nbsp;num2&nbsp;)&nbsp;);&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:0.9</span><br><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;减</span><br>System.out.println(&nbsp;num2.subtract(&nbsp;num1&nbsp;)&nbsp;);&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:0.5</span><br><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;乘</span><br>System.out.println(&nbsp;num1.multiply(&nbsp;num2&nbsp;)&nbsp;);&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:0.14</span><br><br><span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;除</span><br>System.out.println(&nbsp;num2.divide(&nbsp;num1&nbsp;)&nbsp;);&nbsp;&nbsp;<span style="color: rgb(117, 113, 94);line-height: 26px;">//&nbsp;打印:3.5</span><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;">当然了,像<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">BigInteger</code>&nbsp;和&nbsp;<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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);">BigDecimal</code>这种大数类的运算效率肯定是不如原生类型效率高,代价还是比较昂贵的,是否选用需要根据实际场景来评估。</p> <hr data-tool="mdnice编辑器" style="height: 1px;border-style: solid;border-color: rgb(53, 179, 120);margin: 1.5em auto;"> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;margin: 1em 4px;line-height: normal;"> 每天进步一点点,Peace!&nbsp; </section> <section style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;margin: 1em 4px;line-height: normal;"> 2020.04.09晚 </section> <section class="js_darkmode__84" data-tools="135编辑器" data-id="94301" data-darkmode-color="rgb(168, 168, 168)" data-style="max-width: 100%; letter-spacing: 0.544px; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 16px; widows: 1; text-align: right; box-sizing: border-box !important; overflow-wrap: break-word !important;" style="max-width: 100%;color: rgb(62, 62, 62);letter-spacing: 0.544px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;widows: 1;text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-tools="135编辑器" data-id="94250" data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-tools="135编辑器" data-id="91842" data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;width: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-darkmode-color="rgb(168, 168, 168)" style="max-width: 100%;display: inline-block;clear: both;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section class="js_darkmode__85" data-brushtype="text" data-darkmode-color="rgb(168, 168, 168)" data-darkmode-bgimage="1" data-style="padding: 18px 15px 20px 10px; max-width: 100%; color: rgb(86, 146, 214); text-align: center; letter-spacing: 1.5px; background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/Pn4Sm0RsAuhpplm16ibb8iaib7RoGQ5iaHEdy66AHd7QqL7A2s5icSBE0aw4iaKOKPnXGYxQPhG7VMpbbYV6VJprSh7w/640?wx_fmt=png&quot;); background-size: 100% 100%; background-repeat: no-repeat; box-sizing: border-box !important; overflow-wrap: break-word !important;" style="padding: 18px 15px 20px 10px;max-width: 100%;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/Pn4Sm0RsAuhpplm16ibb8iaib7RoGQ5iaHEdy66AHd7QqL7A2s5icSBE0aw4iaKOKPnXGYxQPhG7VMpbbYV6VJprSh7w/640?wx_fmt=png&quot;);color: rgb(86, 146, 214);text-align: center;letter-spacing: 1.5px;background-size: 100% 100%;background-repeat: no-repeat;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-darkmode-color="rgb(168, 168, 168)" data-darkmode-bgimage="1" style="max-width: 100%;display: flex;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-darkmode-color="rgb(168, 168, 168)" data-darkmode-bgimage="1" style="margin-left: 2px;max-width: 100%;width: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.8936170212765957" data-type="png" data-w="47" src="/upload/737696b8734b6f688ae95660c4411917.png" style="margin-bottom: -6px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 20px !important;"> </section> <section data-brushtype="text" data-darkmode-color="rgb(168, 168, 168)" data-darkmode-bgimage="1" style="max-width: 100%;font-size: 14px;color: rgb(51, 51, 51);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span data-darkmode-color="rgb(168, 168, 168)" data-darkmode-bgimage="1" style="max-width: 100%;font-family: 楷体, 楷体_GB2312, SimKai;box-sizing: border-box !important;overflow-wrap: break-word !important;">给个[<strong data-darkmode-color="rgb(168, 168, 168)" data-darkmode-bgimage="1" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在看</strong>],是对程序羊最大的支持</span> </section> <p data-darkmode-color="rgb(168, 168, 168)" data-darkmode-bgimage="1" style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br data-darkmode-color="rgb(168, 168, 168)" data-darkmode-bgimage="1" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> </section> </section> </section> </section> </section> </section></pre> </section> </section> </section> </section> </section> </section>

监控神器Prometheus,开箱即用!

作者:微信小助手

<section class="mp_profile_iframe_wrp" data-mpa-powered-by="yiban.io"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkyNTI5NTQ1NQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/wxcY9TH8dPsYAnrjaZktBe0iahF8ic9QkF26cAw8pK6HPR1bfFEImdyJspvkQvQwmnYxP4eEVW60ewVVickcWXnrQ/0?wx_fmt=png" data-nickname="架构文摘" data-alias="ArchDigest" data-signature="每天一篇架构领域重磅好文,涉及一线互联网公司应用架构(高可用、高性能、高稳定)、大数据、机器学习、Java架构等各个热门领域。" data-from="0"></mpprofile> </section> <section powered-by="xmyeditor.com" style="box-sizing: border-box;max-width: 100% !important;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="box-sizing: border-box;max-width: 100% !important;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" powered-by="xmyeditor.com"> <p style="outline: 0px;color: rgb(34, 34, 34);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);font-size: 16px;font-weight: bold;text-align: right;visibility: visible;line-height: 1.5em;margin-top: 1em;"><span style="outline: 0px;font-size: 13px;color: rgb(136, 136, 136);visibility: visible;font-family: Optima-Regular, PingFangTC-light;">文章来源:【公众号:云加社区】</span><span style="font-family: Optima-Regular, PingFangTC-light;outline: 0px;font-size: 13px;color: rgb(136, 136, 136);visibility: visible;display: none;line-height: 0px;">‍<br></span></p> <section style="outline: 0px;color: rgb(34, 34, 34);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);font-size: 16px;font-weight: bold;text-align: right;visibility: visible;line-height: 1.5em;box-sizing: border-box;max-width: 100% !important;"> <br> </section> <section style="text-align: left;margin-bottom: 20px;box-sizing: border-box;max-width: 100% !important;"> <span style="font-family: Optima-Regular, PingFangTC-light;"><strong><span style="outline: 0px;font-size: 15px;visibility: visible;">目录</span></strong></span> </section> <ul class="list-paddingleft-1"> <li><p><span style="font-size: 15px;letter-spacing: 2px;font-family: Optima-Regular, PingFangTC-light;">简介</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">整体生态</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">工作原理</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">Metric 指标</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">PromQL</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">Grafana 可视化</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">监控告警</span></p></li> </ul> <p><br></p> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="text-align: center;justify-content: center;margin: 10px 0%;display: flex;flex-flow: row nowrap;box-sizing: border-box;"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;flex: 0 0 auto;height: auto;border-bottom: 1px solid rgb(126, 169, 195);border-bottom-right-radius: 0px;line-height: 0;align-self: flex-start;box-sizing: border-box;"> <section style="margin: 0px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="letter-spacing: 0px;line-height: 1.8;font-size: 15px;color: rgb(126, 169, 195);padding: 0px 5px;box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;">简介</strong></p> </section> </section> <section style="margin: 0px 0% -3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 5px;height: 5px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 202px;border-style: none;border-color: rgb(62, 62, 62);background-color: rgb(126, 169, 195);box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> </section> </section> <p><br></p> <p style="margin: 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(51, 51, 51);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: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;">Prometheus 是一个开源的完整监控解决方案,本文将从指标抓取到查询及可视化展示,以及最后的监控告警,对 Prometheus 做一个基本的认识。</span></p> <p style="margin: 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(51, 51, 51);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: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><br></p> <p style="margin: 0px 0px 8px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);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: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;overflow-wrap: break-word !important;box-sizing: bor

Spring Boot+gRPC构建微服务并部署到Istio(详细教程)

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style=""> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">作为Service Mesh和云原生技术的忠实拥护者,我却一直没有开发过Service Mesh的应用。正好最近受够了Spring Cloud的“折磨”,对Kubernetes也可以熟练使用了,而且网上几乎没有Spring Boot微服务部署到Istio的案例,我就开始考虑用Spring Boot写个微服务的Demo并且部署到Istio。项目本身不复杂,就是发送一个字符串并且返回一个字符串的最简单的Demo。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;">题外话:我本来是想用Spring MVC写的——因为周围有的同学不相信Spring MVC也可以开发微服务,但是Spring MVC的各种配置和依赖问题把我整的想吐,为了少掉几根头发,还是用了方便好用的Spring Boot。</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>为什么要用Istio?<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">目前,对于Java技术栈来说,构建微服务的最佳选择是Spring Boot而Spring Boot一般搭配目前落地案例很多的微服务框架Spring Cloud来使用。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">Spring Cloud看似很完美,但是在实际上手开发后,很容易就会发现Spring Cloud存在以下比较严重的问题:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 服务治理相关的逻辑存在于Spring Cloud Netflix等SDK中,与业务代码紧密耦合。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> SDK对业务代码侵入太大,SDK发生升级且无法向下兼容时,业务代码必须做出改变以适配SDK的升级——即使业务逻辑并没有发生任何变化。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 各种组件令人眼花缭乱,质量也参差不齐,学习成本太高,且组件之间代码很难完全复用,仅仅为了实现治理逻辑而学习SDK也并不是很好的选择。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 绑定于Java技术栈,虽然可以接入其他语言但要手动实现服务治理相关的逻辑,不符合微服务“可以用多种语言进行开发”的原则。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> Spring Cloud仅仅是一个开发框架,没有实现微服务所必须的服务调度、资源分配等功能,这些需求要借助Kubernetes等平台来完成。但Spring Cloud与Kubernetes功能上有重合,且部分功能也存在冲突,二者很难完美配合。 </section></li> </ul> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="font-weight: bold;color: black;">替代Spring Cloud的选择有没有呢?有!它就是Istio。</strong></p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">Istio彻底把治理逻辑从业务代码中剥离出来,成为了独立的进程(Sidecar)。部署时两者部署在一起,在一个Pod里共同运行,业务代码完全感知不到Sidecar的存在。这就实现了治理逻辑对业务代码的零侵入——实际上不仅是代码没有侵入,在运行时两者也没有任何的耦合。这使得不同的微服务完全可以使用不同语言、不同技术栈来开发,也不用担心服务治理问题,可以说这是一种很优雅的解决方案了。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">所以,“为什么要使用Istio”这个问题也就迎刃而解了——因为Istio解决了传统微服务诸如业务逻辑与服务治理逻辑耦合、不能很好地实现跨语言等痛点,而且非常容易使用。只要会用Kubernetes,学习Istio的使用一点都不困难。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>为什么要使用gRPC作为通信框架?<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">在微服务架构中,服务之间的通信是一个比较大的问题,一般采用RPC或者RESTful API来实现。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">Spring Boot可以使用RestTemplate调用远程服务,但这种方式不直观,代码也比较复杂,进行跨语言通信也是个比较大的问题;而gRPC相比Dubbo等常见的Java RPC框架更加轻量,使用起来也很方便,代码可读性高,并且与Istio和Kubernetes可以很好地进行整合,在Protobuf和HTTP2的加持下性能也还不错,所以这次选择了gRPC来解决Spring Boot微服务间通信的问题。并且,虽然gRPC没有服务发现、负载均衡等能力,但是Istio在这方面就非常强大,两者形成了完美的互补关系。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">由于考虑到各种<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">grpc-spring-boot-starter</code>可能会对Spring Boot与Istio的整合产生不可知的副作用,所以这一次我没有用任何的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">grpc-spring-boot-starter</code>,而是直接手写了gRPC与Spring Boot的整合。不想借助第三方框架整合gRPC和Spring Boot的可以简单参考一下我的实现。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>编写业务代码<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">首先使用<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Spring Initializr</code>建立父级项目<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">spring-boot-istio</code>,并引入gRPC的依赖。pom文件如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">&lt;?xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"?&gt;</span><br><span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">project</span>&nbsp;<span style="line-height: 26px;">xmlns</span>=<span style="color: #a6e22e;line-height: 26px;">"http://maven.apache.org/POM/4.0.0"</span>&nbsp;<span style="line-height: 26px;">xmlns:xsi</span>=<span style="color: #a6e22e;line-height: 26px;">"http://www.w3.org/2001/XMLSchema-instance"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">xsi:schemaLocation</span>=<span style="color: #a6e22e;line-height: 26px;">"http://maven.apache.org/POM/4.0.0&nbsp;https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">modelVersion</span>&gt;</span>4.0.0<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">modelVersion</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">modules</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">module</span>&gt;</span>spring-boot-istio-api<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">module</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">module</span>&gt;</span>spring-boot-istio-server<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">module</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">module</span>&gt;</span>spring-boot-istio-client<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">module</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">modules</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">parent</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span>org.springframework.boot<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>spring-boot-starter-parent<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span>2.2.6.RELEASE<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">relativePath</span>/&gt;</span>&nbsp;<span style="color: #75715e;line-height: 26px;">&lt;!--&nbsp;lookup&nbsp;parent&nbsp;from&nbsp;repository&nbsp;--&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">parent</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span>site.wendev<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>spring-boot-istio<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span>0.0.1-SNAPSHOT<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">name</span>&gt;</span>spring-boot-istio<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">name</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">description</span>&gt;</span>Demo&nbsp;project&nbsp;for&nbsp;Spring&nbsp;Boot&nbsp;With&nbsp;Istio.<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">description</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">packaging</span>&gt;</span>pom<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">packaging</span>&gt;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">properties</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">java.version</span>&gt;</span>1.8<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">java.version</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">properties</span>&gt;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">dependencyManagement</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">dependencies</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span>io.grpc<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>grpc-all<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span>1.28.1<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">dependencies</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">dependencyManagement</span>&gt;</span><br><span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">project</span>&gt;</span><br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">然后建立公共依赖模块<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">spring-boot-istio-api</code>,pom文件如下,主要就是gRPC的一些依赖:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">&lt;?xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"?&gt;</span><br><span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">project</span>&nbsp;<span style="line-height: 26px;">xmlns</span>=<span style="color: #a6e22e;line-height: 26px;">"http://maven.apache.org/POM/4.0.0"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">xmlns:xsi</span>=<span style="color: #a6e22e;line-height: 26px;">"http://www.w3.org/2001/XMLSchema-instance"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">xsi:schemaLocation</span>=<span style="color: #a6e22e;line-height: 26px;">"http://maven.apache.org/POM/4.0.0&nbsp;http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">parent</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>spring-boot-istio<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span>site.wendev<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span>0.0.1-SNAPSHOT<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">parent</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">modelVersion</span>&gt;</span>4.0.0<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">modelVersion</span>&gt;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>spring-boot-istio-api<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">dependencies</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span>io.grpc<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>grpc-all<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span>javax.annotation<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>javax.annotation-api<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span>1.3.2<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">dependencies</span>&gt;</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">build</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">extensions</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">extension</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span>kr.motd.maven<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>os-maven-plugin<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span>1.6.2<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">extension</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">extensions</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">plugins</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">plugin</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span>org.xolstice.maven.plugins<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span>protobuf-maven-plugin<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">artifactId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span>0.6.1<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">version</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">protocArtifact</span>&gt;</span>com.google.protobuf:protoc:3.11.3:exe:${os.detected.classifier}<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">protocArtifact</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">pluginId</span>&gt;</span>grpc-java<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">pluginId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">pluginArtifact</span>&gt;</span>io.grpc:protoc-gen-grpc-java:1.28.1:exe:${os.detected.classifier}<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">pluginArtifact</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">protocExecutable</span>&gt;</span>/Users/jiangwen/tools/protoc-3.11.3/bin/protoc<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">protocExecutable</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">executions</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">execution</span>&gt;</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;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">goals</span>&gt;</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;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">goal</span>&gt;</span>compile<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">goal</span>&gt;</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;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">goal</span>&gt;</span>compile-custom<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">goal</span>&gt;</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;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">goals</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">execution</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">executions</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">plugin</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">plugins</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">build</span>&gt;</span><br><span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">project</span>&gt;</span><br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">建立<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">src/main/proto</code>文件夹,在此文件夹下建立<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">hello.proto</code>,定义服务间的接口如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">syntax&nbsp;=&nbsp;<span style="color: #a6e22e;line-height: 26px;">"proto3"</span>;<br><br>option&nbsp;java_package&nbsp;=&nbsp;<span style="color: #a6e22e;line-height: 26px;">"site.wendev.spring.boot.istio.api"</span>;<br>option&nbsp;java_outer_classname&nbsp;=&nbsp;<span style="color: #a6e22e;line-height: 26px;">"HelloWorldService"</span>;<br><br>package&nbsp;helloworld;<br><br>service&nbsp;HelloWorld&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;rpc&nbsp;SayHello&nbsp;(HelloRequest)&nbsp;returns&nbsp;(HelloResponse)&nbsp;{}<br>}<br><br>message&nbsp;HelloRequest&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;name&nbsp;=&nbsp;1;<br>}<br><br>message&nbsp;HelloResponse&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;message&nbsp;=&nbsp;1;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">很简单,就是发送一个name返回一个带name的message。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">然后生成服务端和客户端的代码,并且放到java文件夹下。这部分内容可以参考gRPC的官方文档。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">有了API模块之后,就可以编写服务提供者(服务端)和服务消费者(客户端)了。这里我们重点看一下如何整合gRPC和Spring Boot。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>服务端<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">业务代码非常简单:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;*&nbsp;服务端业务逻辑实现<br>&nbsp;*<br>&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@author</span>&nbsp;江文<br>&nbsp;*/</span><br><span style="color: #75715e;line-height: 26px;">@Slf</span>4j<br><span style="color: #75715e;line-height: 26px;">@Component</span><br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">HelloServiceImpl</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">extends</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">HelloWorldGrpc</span>.<span style="font-weight: bold;color: white;line-height: 26px;">HelloWorldImplBase</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">sayHello</span><span style="line-height: 26px;">(HelloWorldService.HelloRequest&nbsp;request,<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;&nbsp;StreamObserver&lt;HelloWorldService.HelloResponse&gt;&nbsp;responseObserver)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">//&nbsp;根据请求对象建立响应对象,返回响应信息</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HelloWorldService.HelloResponse&nbsp;response&nbsp;=&nbsp;HelloWorldService.HelloResponse<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.newBuilder()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.setMessage(String.format(<span style="color: #a6e22e;line-height: 26px;">"Hello,&nbsp;%s.&nbsp;This&nbsp;message&nbsp;comes&nbsp;from&nbsp;gRPC."</span>,&nbsp;request.getName()))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseObserver.onNext(response);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responseObserver.onCompleted();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #a6e22e;line-height: 26px;">"Client Message Received:[{}]"</span>,&nbsp;request.getName());<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">光有业务代码还不行,我们还需要在应用启动时把<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">gRPC Server</code>也给一起启动起来。首先写一下Server端的启动、关闭等逻辑:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;*&nbsp;gRPC&nbsp;Server的配置——启动、关闭等<br>&nbsp;*&nbsp;需要使用&lt;code&gt;<span style="font-weight: bold;line-height: 26px;">@Component</span>&lt;/code&gt;注解注册为一个Spring&nbsp;Bean<br>&nbsp;*<br>&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@author</span>&nbsp;江文<br>&nbsp;*/</span><br><span style="color: #75715e;line-height: 26px;">@Slf</span>4j<br><span style="color: #75715e;line-height: 26px;">@Component</span><br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">GrpcServerConfiguration</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Autowired</span><br>&nbsp;&nbsp;&nbsp;&nbsp;HelloServiceImpl&nbsp;service;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">/**&nbsp;注入配置文件中的端口信息&nbsp;*/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #75715e;line-height: 26px;">@Value</span>(<span style="color: #a6e22e;line-height: 26px;">"${grpc.server-port}"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">int</span>&nbsp;port;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;Server&nbsp;server;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-heigh

聊聊 分布式配置中心 Apollo

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;overflow-wrap: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;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: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">今天深入聊一聊携程开源的一款分布式配置中心Apollo,在功能上和Nacos不相上下。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 22px;text-align: left;margin: 20px 10px 0px 0px;"><span style="display: none;"></span><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"><a href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511213&amp;idx=1&amp;sn=9635f9d57390269edef798fa66a03e3b&amp;chksm=fcf77360cb80fa76fe5c9abee83c54fb4e06038d555663c07f5c1be7838bc7abdee5417a8e18&amp;token=1267466554&amp;lang=zh_CN&amp;scene=21#wechat_redirect" style="text-decoration: none;word-wrap: break-word;color: rgb(248, 57, 41);font-weight: 400;border-bottom: 1px solid rgb(248, 57, 41);" data-linktype="2">1. 基本概念</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">由于 Apollo 概念比较多,刚开始使用比较复杂,最好先过一遍概念再动手实践尝试使用。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;"><a href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511213&amp;idx=1&amp;sn=9635f9d57390269edef798fa66a03e3b&amp;chksm=fcf77360cb80fa76fe5c9abee83c54fb4e06038d555663c07f5c1be7838bc7abdee5417a8e18&amp;token=1267466554&amp;lang=zh_CN&amp;scene=21#wechat_redirect" style="text-decoration: none;word-wrap: break-word;color: rgb(248, 57, 41);font-weight: 400;border-bottom: 1px solid rgb(248, 57, 41);" data-linktype="2">1、背景</a></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">随着程序功能的日益复杂,程序的配置日益增多,各种功能的开关、参数的配置、服务器的地址……对程序配置的期望值也越来越高,配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制…… 在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。因此 Apollo 配置中心应运而生!</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2、简介</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">3、特点</span><span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 部署简单 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 灰度发布 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 版本发布管理 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 提供开放平台API </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 客户端配置信息监控 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 提供Java和.Net原生客户端 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 配置修改实时生效(热发布) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 权限管理、发布审核、操作审计 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 统一管理不同环境、不同集群的配置 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">4、基础模型</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">如下即是 Apollo 的基础模型:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> (1)、用户在配置中心对配置进行修改并发布 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> (2)、配置中心通知Apollo客户端有配置更新 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> (3)、Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.6329896907216495" src="/upload/8b60dc52f2c172b1f891a1412829827.png" data-type="png" data-w="970" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">5、Apollo 的四个维度</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;"><strong style="font-weight: 700;color: rgb(248, 57, 41);">Apollo支持4个维度管理Key-Value格式的配置:</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> application (应用) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> environment (环境) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> cluster (集群) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> namespace (命名空间) </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;"><strong style="font-weight: 700;color: rgb(248, 57, 41);">(1)、application</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Apollo 客户端在运行时需要知道当前应用是谁,从而可以根据不同的应用来获取对应应用的配置。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 每个应用都需要有唯一的身份标识,可以在代码中配置 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(271, 93, 108);">app.id</code> 参数来标识当前应用,Apollo 会根据此指来辨别当前应用。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;"><strong style="font-weight: 700;color: rgb(248, 57, 41);">(2)、environment</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">在实际开发中,我们的应用经常要部署在不同的环境中,一般情况下分为开发、测试、生产等等不同环境,不同环境中的配置也是不同的,在 Apollo 中默认提供了四种环境:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> FAT(Feature Acceptance Test):功能测试环境 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> UAT(User Acceptance Test):集成测试环境 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> DEV(Develop):开发环境 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> PRO(Produce):生产环境 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">在程序中如果想指定使用哪个环境,可以配置变量 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(271, 93, 108);">env</code> 的值为对应环境名称即可。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;"><strong style="font-weight: 700;color: rgb(248, 57, 41);">(3)、cluster</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 一个应用下不同实例的分组,比如典型的可以按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另一个集群。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 对不同的集群,同一个配置可以有不一样的值,比如说上面所指的两个北京、上海两个机房设置两个集群,两个集群中都有 mysql 配置参数,其中参数中配置的地址是不一样的。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;"><strong style="font-weight: 700;color: rgb(248, 57, 41);">(4)、namespace</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">一个应用中不同配置的分组,可以简单地把 namespace 类比为不同的配置文件,不同类型的配置存放在不同的文件中,如数据库配置文件,RPC 配置文件,应用自身的配置文件等。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">熟悉 SpringBoot 的都知道,SpringBoot 项目都有一个默认配置文件 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(271, 93, 108);">application.yml</code>,如果还想用多个配置,可以创建多个配置文件来存放不同的配置信息,通过指定 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(271, 93, 108);">spring.profiles.active</code> 参数指定应用不同的配置文件。这里的 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(271, 93, 108);">namespace</code> 概念与其类似,将不同的配置放到不同的配置 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(271, 93, 108);">namespace</code> 中。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">Namespace 分为两种权限,分别为:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">public(公共的):</strong> public权限的 Namespace,能被任何应用获取。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">private(私有的):</strong> 只能被所属的应用获取到。一个应用尝试获取其它应用 private 的 Namespace,Apollo 会报 "404" 异常。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">Namespace 分为三种类型,分别为:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">私有类型:</strong> 私有类型的 Namespace 具有 private 权限。例如 application Namespace 为私有类型。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">公共类型:</strong> 公共类型的 Namespace 具有 public 权限。公共类型的N amespace 相当于游离于应用之外的配置,且通过 Namespace 的名称去标识公共 Namespace,所以公共的 Namespace 的名称必须全局唯一。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">关联类型(继承类型):</strong> 关联类型又可称为继承类型,关联类型具有 private 权限。关联类型的 Namespace 继承于公共类型的 Namespace,将里面的配置全部继承,并且可以用于覆盖公共 Namespace 的某些配置。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">6、本地缓存</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">Apollo客户端会把从服务端获取到的配置在本地文件系统缓存一份,用于在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置,不影响应用正常运行。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">本地缓存路径默认位于以下路径,所以请确保/opt/data或C:\opt\data\目录存在,且应用有读写权限。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">Mac/Linux:</strong> /opt/data/{appId}/config-cache </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <strong style="font-weight: 700;color: rgb(248, 57, 41);">Windows:</strong> C:\opt\data{appId}\config-cache </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">本地配置文件会以下面的文件名格式放置于本地缓存路径下:</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;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oexqmcDw0weKQfou5D5p14lh1GbM2X2JzcqPRQrNwmL00gjsQyVRHD9L7u5zwiaPTRaaB7sdrvwJxF4GL6UU92icqC/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #383a42;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fafafa;border-radius: 5px;">{appId}+{cluster}+{namespace}.properties<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">7、客户端设计</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img src="/upload/35581efe6d32946e8ee178c3985bd28a.jpg" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;" data-type="jpeg" data-ratio="0.48556701030927835" data-w="970"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;"><strong style="font-weight: 700;color: rgb(248, 57, 41);">上图简要描述了Apollo客户端的实现原理</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">客户端还会定时从 Apollo 配置中心服务端拉取应用的最新配置。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <br> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: #f83929;font-size: 16px;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 这是一个 fallback 机制,为了防止推送机制失效导致配置不更新 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回 304 - Not Modified </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 定时频率默认为每 5 分钟拉取一次,客户端也可以通过在运行时指定 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(271, 93, 108);">apollo.refreshInterval</code> 来覆盖,单位为分钟。 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">客户端从 Apollo 配置中心服务端获取到应用的最新配置后,会保存在内存中。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">客户端会把从服务端获取到的配置在本地文件系统缓存一份 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">应用程序从 Apollo 客户端获取最新的配置、订阅配置更新通知。</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;"><a href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511213&amp;idx=1&amp;sn=9635f9d57390269edef798fa66a03e3b&amp;chksm=fcf77360cb80fa76fe5c9abee83c54fb4e06038d555663c07f5c1be7838bc7abdee5417a8e18&amp;token=1267466554&amp;lang=zh_CN&amp;scene=21#wechat_redirect" style="text-decoration: none;word-wrap: break-word;color: rgb(248, 57, 41);font-weight: 400;border-bottom: 1px solid rgb(248, 57, 41);" data-linktype="2"><strong style="font-weight: 700;color: rgb(248, 57, 41);">配置更新推送实现</strong></a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">前面提到了 Apollo 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。长连接实际上我们是通过 Http Long Polling 实现的,具体而言:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">客户端发起一个 Http 请求到服务端</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">服务端会保持住这个连接 60 秒</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <br> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: #f83929;font-size: 16px;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 如果在 60 秒内有客户端关心的配置变化,被保持住的客户端请求会立即返回,并告知客户端有配置变化的 namespace 信息,客户端会据此拉取对应 namespace 的最新配置 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 如果在 60 秒内没有客户端关心的配置变化,那么会返回 Http 状态码 304 给客户端 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">客户端在收到服务端请求后会立即重新发起连接,回到第一步</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">考虑到会有数万客户端向服务端发起长连,在服务端我们使用了 async servlet(Spring DeferredResult) 来服务 Http Long Polling 请求。</p> </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">8、总体设计</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img src="/upload/15d94e37340367e957d93bc1f8554ab7.jpg" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;" data-type="jpeg" data-ratio="0.865979381443299" data-w="970"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">上图简要描述了Apollo的总体设计,我们可以从下往上看:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Config Service 提供配置的读取、推送等功能,服务对象是 Apollo 客户端 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Admin Service 提供配置的修改、发布等功能,服务对象是 Apollo Portal(管理界面) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Config Service 和 Admin Service 都是多实例、无状态部署,所以需要将自己注册到 Eureka 中并保持心跳 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 在 Eureka 之上我们架了一层 Meta Server 用于封装Eureka的服务发现接口 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Client 通过域名访问 Meta Server 获取Config Service服务列表(IP+Port),而后直接通过 IP+Port 访问服务,同时在 Client 侧会做 load balance 错误重试 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Portal 通过域名访问 Meta Server 获取 Admin Service 服务列表(IP+Port),而后直接通过 IP+Port 访问服务,同时在 Portal 侧会做 load balance、错误重试 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 为了简化部署,我们实际上会把 Config Service、Eureka 和 Meta Server 三个逻辑角色部署在同一个 JVM 进程中 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">9、可用性考虑</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">配置中心作为基础服务,可用性要求非常高,下面的表格描述了不同场景下Apollo的可用性:</p> <section data-tool="mdnice编辑器" style="overflow-x: auto;"> <table> <thead> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <th style="border-width: 1px;borde

学会这些 Logback 高级知识点,日志排查轻松了不少!

作者:微信小助手

<p data-mpa-powered-by="yiban.io"><em style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-style: italic;color: rgb(34, 34, 34);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;font-size: 17px;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-align: justify;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);visibility: visible;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;letter-spacing: 0.544px;font-size: 16px;text-align: left;color: rgb(0, 0, 0);font-family: 微软雅黑;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;visibility: visible;">点击关注公众号,实用技术文章</span></strong><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;letter-spacing: 0.544px;font-size: 16px;text-align: left;color: rgb(123, 12, 0);visibility: visible;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: 微软雅黑;visibility: visible;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;visibility: visible;">及时了解</span></strong></span><img class="rich_pages wxw-img" data-fileid="100031040" data-ratio="1" data-type="png" data-w="64" src="/upload/29316807de8eec165a101cfe6173a39c.png" style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;letter-spacing: 0.544px;font-size: 16px;text-align: left;color: rgb(0, 0, 0);font-family: 微软雅黑;visibility: visible !important;max-height: 20px !important;width: 20px !important;"></em></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzI4Njc5NjM1NQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/eQPyBffYbueAgIuCqZdZnW3NW44AOD32W2BOe28vCWLC2XdcNqJufjmlCCI2YVbFh0fjL6qCxEoNjHN9jTBItQ/0?wx_fmt=png" data-nickname="Java知音" data-alias="Java_friends" data-signature="专注于java。分享java基础、原理性知识、JavaWeb实战、spring全家桶、设计模式及面试资料、开源项目,助力开发者成长!" data-from="0"></mpprofile> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style=""> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>前言<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">组内许多服务既有同步接口也有异步脚本,接口和脚本的日志都打印在同一个日志文件中,日志繁杂给排查问题带来不少的阻碍。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">为了解决这个问题,同事提了个按照接口分类日志文件的技术需求,也就是一个同步接口对应一个日志文件,从而将日志区分开。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">目前组内所有服务都是使用 logback 日志框架,笔者对这个需求产生了一定的兴趣,查找资料了解到了 logback 日志过滤器,因此有了本文,读者有兴趣的话也可以去官方文档:</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;color: black;line-height: 26px;">https://logback.qos.ch/manual/filters.html</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>1. Logback 过滤器的分类<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">logback 提供两种类型的过滤器, 一种是常规过滤器(regular filters) ,另一种是全局过滤器(turbo filter)。常规过滤器与 appender 绑定, 全局过滤器与 logger context 绑定,二者的区别就是全局过滤器过滤所有 logging request ,而常规过滤器只过滤某个 appender 的 logging request</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>2. 常规过滤器<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">在 logback-classic 中常规过滤器继承 ch.qos.logback.core.filter.Filter 抽象类,该抽象类的 decide()抽象方法接收一个 ILoggingEvent 参数,返回一个FilterReply枚举值。枚举值标明了过滤器对当前日志事件的过滤情况,具体处理如下表</p> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.20150187734668334" src="/upload/baa1349d383d169343b285f7af5cf650.png" data-type="png" data-w="799" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>2.1 日志级别过滤器 LevelFilter<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">LevelFilter 的过滤是基于日志事件的级别,如果日志级别等于配置的 level,则过滤器通过,否则拒绝,其代码实现如下。另外ThresholdFilter也是基于日志等级门槛过滤的,只不过其逻辑是当日志级别大于等于配置等级才能通过过滤器,此处不再赘述</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">需注意源码中涉及的成员变量 this.level、this.onMatch以及this.onMismatch都是在过滤器初始化时根据配置的值自动注入的,代码中只要提供其 set 方法即可</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">class</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">LevelFilter</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">extends</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">AbstractMatcherFilter</span>&lt;<span style="font-weight: bold;color: white;line-height: 26px;">ILoggingEvent</span>&gt;&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;Level&nbsp;level;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">LevelFilter</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;FilterReply&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">decide</span><span style="line-height: 26px;">(ILoggingEvent&nbsp;event)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">if</span>&nbsp;(!<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.isStarted())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;FilterReply.NEUTRAL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">else</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;event.getLevel().equals(<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.level)&nbsp;?&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.onMatch&nbsp;:&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.onMismatch;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">setLevel</span><span style="line-height: 26px;">(Level&nbsp;level)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.level&nbsp;=&nbsp;level;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">start</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">if</span>&nbsp;(<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.level&nbsp;!=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">null</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">super</span>.start();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">以下为LevelFilter 配置示例,该配置需要关注的点如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; appender &gt;</code>标签配置指定的 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">RollingFileAppender</code> 为滚动文件追加器,其滚动策略由 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; rollingPolicy &gt;</code>标签配置,指定为 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">TimeBasedRollingPolicy</code></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">常规过滤器需与 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">appender</code> 绑定,过滤器元素<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; filter &gt;</code>需要在 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; appender &gt;</code>标签之间。配置<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">LevelFilter</code> 的<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; filter &gt;</code>标签中的 3 个子标签配置了需要注入 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">this.level</code>、<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">this.onMatch</code>以及<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">this.onMismatch</code> 属性的值,实现自定义过滤器时标签名可以自定义,只要与属性名相对应即可</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; appender-ref &gt;</code> 标签启用指定的 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">appender</code></p> </section></li> </ul> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">appender</span>&nbsp;<span style="line-height: 26px;">name</span>=<span style="color: #a6e22e;line-height: 26px;">"FILE_ALL"</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.RollingFileAppender"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">filter</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.classic.filter.LevelFilter"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">level</span>&gt;</span>INFO<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">level</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">onMatch</span>&gt;</span>ACCEPT<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">onMatch</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">onMismatch</span>&gt;</span>DENY<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">onMismatch</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">filter</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">rollingPolicy</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">maxHistory</span>&gt;</span>90<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">maxHistory</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">fileNamePattern</span>&gt;</span>${BASE_PATH_ERROR}/%d{yyyy-MM-dd}.%i.log.gz<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">fileNamePattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">timeBasedFileNamingAndTriggeringPolicy</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">maxFileSize</span>&gt;</span>200MB<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">maxFileSize</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">timeBasedFileNamingAndTriggeringPolicy</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">rollingPolicy</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">pattern</span>&gt;</span>&nbsp;%d{yyyy-MM-dd&nbsp;HH:mm:ss.SSS}&nbsp;[%thread]&nbsp;%-5level&nbsp;%logger{30}&nbsp;-&nbsp;%msg%n<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">appender</span>&gt;</span><br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">root</span>&nbsp;<span style="line-height: 26px;">level</span>=<span style="color: #a6e22e;line-height: 26px;">"INFO"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">appender-ref</span>&nbsp;<span style="line-height: 26px;">ref</span>=<span style="color: #a6e22e;line-height: 26px;">"FILE_ALL"</span>&nbsp;/&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">root</span>&gt;</span><br>&nbsp;&nbsp;<br><span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>2.2 日志评估过滤器 EvaluatorFilter<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">EvaluatorFilter</code> 是一个抽象类,它包含了一个 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">EventEvaluator</code> 对象,这个对象是日志评估过滤器实现的关键。它会封装配置在<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; expression &gt;</code>标签中的过滤逻辑,在处理日志事件时负责过滤条件的判断</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">EventEvaluator</code>主要有两个实现类,分别是 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">GEventEvaluator</code> 和 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JaninoEventEvaluator</code>。<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">GEventEvaluator</code> 接收 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Groovy</code> 语言的条件表达式作为判断条件,<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JaninoEventEvaluator</code> 接收一个 java 的判断表达式作为判断条件,logback 默认使用的是 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JaninoEventEvaluator</code>,其依赖于 Janino 相关库</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>JaninoEventEvaluator 的使用<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">使用 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JaninoEventEvaluator</code>评估器时 logback 会自动导出日志事件对象的属性到 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">evaluation</code> 表达式中,所以可以直接使用以下属性</p> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.6105919003115264" src="/upload/6e62e48b702de5772902a67b0ce7efd8.png" data-type="png" data-w="963" style="display: block;margin: 0 auto;max-width: 100%;"> </figure> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">JaninoEventEvaluator</code> 的使用配置如下所示,<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; expression &gt;</code>标签包裹的表达式即为日志过滤的判断逻辑。根据其源代码实现来看,如果未检测到表达式中的 return 字符串将直接在表达式首尾添上 return 和 分号</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">appender</span>&nbsp;<span style="line-height: 26px;">name</span>=<span style="color: #a6e22e;line-height: 26px;">"FILE_ALL"</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.RollingFileAppender"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">filter</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.filter.EvaluatorFilter"</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">evaluator</span>&gt;</span>&nbsp;<span style="color: #75715e;line-height: 26px;">&lt;!--&nbsp;defaults&nbsp;to&nbsp;type&nbsp;ch.qos.logback.classic.boolex.JaninoEventEvaluator&nbsp;--&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">expression</span>&gt;</span>return&nbsp;message.contains("nathan");<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">expression</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">evaluator</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">OnMismatch</span>&gt;</span>NEUTRAL<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">OnMismatch</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">OnMatch</span>&gt;</span>ACCEPT<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">OnMatch</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">filter</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">rollingPolicy</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">maxHistory</span>&gt;</span>90<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">maxHistory</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">fileNamePattern</span>&gt;</span>${BASE_PATH_ERROR}/%d{yyyy-MM-dd}.%i.log.gz<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">fileNamePattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">timeBasedFileNamingAndTriggeringPolicy</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">maxFileSize</span>&gt;</span>200MB<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">maxFileSize</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">timeBasedFileNamingAndTriggeringPolicy</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">rollingPolicy</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">pattern</span>&gt;</span>&nbsp;%d{yyyy-MM-dd&nbsp;HH:mm:ss.SSS}&nbsp;[%thread]&nbsp;%-5level&nbsp;%logger{30}&nbsp;-&nbsp;%msg%n<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">appender</span>&gt;</span><br><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">root</span>&nbsp;<span style="line-height: 26px;">level</span>=<span style="color: #a6e22e;line-height: 26px;">"INFO"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">appender-ref</span>&nbsp;<span style="line-height: 26px;">ref</span>=<span style="color: #a6e22e;line-height: 26px;">"FILE_ALL"</span>&nbsp;/&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">root</span>&gt;</span><br><br><span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>3. 全局过滤器<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">在 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">logback-classic</code> 中全局过滤器都继承自抽象类 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">ch.qos.logback.classic.turbo.TurboFilter</code> ,其实 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Trubo Filter</code> 与 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">Regular Filter</code> 只有两点主要的不同:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">TurboFilter 对象与 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">logging context</code> 绑定,因此它会处理所有的 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">logging request</code>,而不是单独的appender,过滤范围更广</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">TurboFilter 过滤器在 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">LoggingEvent</code> 对象创建之前就已经被调用,所以并不需要日志事件来过滤<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">logging request</code>,因此会有更好的性能表现</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">logback 提供了一些常用的 TurboFilter:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;">MDCFilter</strong> : 通过 MDC 过滤,主要校验 MDC 中指定 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">key-value</code> 是否存在 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;">DynamicThresholdFilter</strong> :通过 MDC 或 level 过滤 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;">MarkerFilter</strong> :通过 marker 标签过滤 </section></li> </ul> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">以下为全局过滤器使用的配置示例</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">turboFilter</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.classic.turbo.DynamicThresholdFilter"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">Key</span>&gt;</span>username<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">Key</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">DefaultThreshold</span>&gt;</span>DEBUG<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">DefaultThreshold</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">MDCValueLevelPair</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">value</span>&gt;</span>nathan<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">value</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">level</span>&gt;</span>DEBUG<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">level</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">MDCValueLevelPair</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">turboFilter</span>&gt;</span><br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">turboFilter</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.classic.turbo.MDCFilter"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">MDCKey</span>&gt;</span>username<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">MDCKey</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">Value</span>&gt;</span>nathan<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">Value</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">OnMatch</span>&gt;</span>ACCEPT<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">OnMatch</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">turboFilter</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">turboFilter</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.classic.turbo.MarkerFilter"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">Marker</span>&gt;</span>nathan<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">Marker</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">OnMatch</span>&gt;</span>DENY<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">OnMatch</span>&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">turboFilter</span>&gt;</span><br><br>&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">appender</span>&nbsp;<span style="line-height: 26px;">name</span>=<span style="color: #a6e22e;line-height: 26px;">"STDOUT"</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.ConsoleAppender"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">pattern</span>&gt;</span>%date&nbsp;[%thread]&nbsp;%-5level&nbsp;%logger&nbsp;-&nbsp;%msg%n<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">appender</span>&gt;</span><br><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">root</span>&nbsp;<span style="line-height: 26px;">level</span>=<span style="color: #a6e22e;line-height: 26px;">"INFO"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">appender-ref</span>&nbsp;<span style="line-height: 26px;">ref</span>=<span style="color: #a6e22e;line-height: 26px;">"STDOUT"</span>/&gt;</span><br>&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">root</span>&gt;</span>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br><span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span>4. 日志分类归档方案<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">按照接口的名称分类日志,将接口方法执行期间的所有日志输出到指定到接口文件中,其需要解决的主要问题有两个:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 怎么分辨哪些日志是哪个接口被调用过程中打印的? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 接口的日志怎么输出到指定到文件? </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>问题1方案<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">对于问题1,首先想到的就是对特定的日志打上特定的标记,可以参考文章 Slf4j 中的 MDC ,借助 MDC 把接口名称以一个 key 存储下来,则可据此区分不同的接口的日志</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;"><span style="display: none;"></span>问题2方案<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">对于问题2,本文介绍的 logback 日志过滤器便起到了作用。我们可以为每个接口重新配置一个 appender,其关键点如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">使用 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">EvaluatorFilter</code> 过滤器,配置<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; expression &gt;</code>标签表达式通过 MDC 获取指定 key 的 value 是否等于目标值</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">配置日志的滚动策略中 <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">&lt; fileNamePattern &gt; </code>日志文件名标签为指定的格式</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">配置<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;"> &lt; appender-ref &gt;</code> 标签启用指定的 appender</p> </section></li> </ul> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">configuration</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">appender</span>&nbsp;<span style="line-height: 26px;">name</span>=<span style="color: #a6e22e;line-height: 26px;">"FILE_METHOD"</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.RollingFileAppender"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">filter</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.filter.EvaluatorFilter"</span>&gt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">evaluator</span>&gt;</span>&nbsp;<span style="color: #75715e;line-height: 26px;">&lt;!--&nbsp;defaults&nbsp;to&nbsp;type&nbsp;ch.qos.logback.classic.boolex.JaninoEventEvaluator&nbsp;--&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">expression</span>&gt;</span>return&nbsp;((String)mdc.get("key")).equals("method");<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">expression</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">evaluator</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">OnMismatch</span>&gt;</span>NEUTRAL<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">OnMismatch</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">OnMatch</span>&gt;</span>ACCEPT<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">OnMatch</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">filter</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">rollingPolicy</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">maxHistory</span>&gt;</span>90<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">maxHistory</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">fileNamePattern</span>&gt;</span>${BASE_PATH_ERROR}/%d{yyyy-MM-dd}.%i.log.method.gz<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">fileNamePattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">timeBasedFileNamingAndTriggeringPolicy</span>&nbsp;<span style="line-height: 26px;">class</span>=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">maxFileSize</span>&gt;</span>200MB<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">maxFileSize</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">timeBasedFileNamingAndTriggeringPolicy</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">rollingPolicy</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">pattern</span>&gt;</span>&nbsp;%d{yyyy-MM-dd&nbsp;HH:mm:ss.SSS}&nbsp;[%thread]&nbsp;%-5level&nbsp;%logger{30}&nbsp;-&nbsp;%msg%n<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">pattern</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">encoder</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">appender</span>&gt;</span><br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">root</span>&nbsp;<span style="line-height: 26px;">level</span>=<span style="color: #a6e22e;line-height: 26px;">"INFO"</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;<span style="color: #f92672;line-height: 26px;">appender-ref</span>&nbsp;<span style="line-height: 26px;">ref</span>=<span style="color: #a6e22e;line-height: 26px;">"FILE_METHOD"</span>&nbsp;/&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;line-height: 26px;">&lt;/<span style="color: #f92672;line-height: 26px;">root</span>&gt;</span><br></code></pre> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin: 0px;padding: 0px 10px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;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;visibility: visible;"> <h3 data-tool="mdnice编辑器" style="margin: 0px;padding: 0px;outline: 0px;font-weight: 400;font-size: 16px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;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;text-align: right;visibility: visible;"><em style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-style: italic;color: rgb(136, 136, 136);font-size: 12px;letter-spacing: 0.5px;visibility: visible;">来源:https://blog.csdn.net/weixin_45505313</em></h3> </section>