文章列表

这类注解都不知道,还好意思说用过Spring Boot?

作者:微信小助手

<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;">不知道大家在使用Spring Boot开发的日常中有没有用过<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);">@Conditionalxxx</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);">@ConditionalOnMissingBean</code>。相信看过Spring Boot源码的朋友一定不陌生。</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;"><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);">@Conditionalxxx</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;">今天这篇文章就从前世今生介绍一下该类注解。</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);">Spring Boot 版本</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;">本文基于的Spring Boot的版本是<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);">2.3.4.RELEASE</code>。</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);">@Conditional</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;"><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);">@Conditional</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);">Spring4.0</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);">@Conditional</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);">@Conditional</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容器</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;"><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);">@Conditional</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);">Bean</code>是否需要注册,在Spring Boot中的变形很多,比如<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);">@ConditionalOnMissingBean</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);">@ConditionalOnBean</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;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="1.083969465648855" src="/upload/3bca6c033a748992b32ae650f6524722.png" data-type="png" data-w="262" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </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;">该注解的源码其实很简单,只有一个属性<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);">value</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);">org.springframework.context.annotation.Condition</code>类型,源码如下:</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/A7sq8BD8oexqmcDw0weKQfoMEUzbE9uQacGYziaoPEJs1gicSGKWHjSBr0cqG1KEjpvibibH7DBpRl6JhaVrWicEp16ORbGSbpsjJ/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;">@Target</span>({ElementType.TYPE,&nbsp;ElementType.METHOD})<br><span style="color: #4078f2;line-height: 26px;">@Retention</span>(RetentionPolicy.RUNTIME)<br><span style="color: #4078f2;line-height: 26px;">@Documented</span><br><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">@interface</span>&nbsp;Conditional&nbsp;{<br><br>&nbsp;<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;All&nbsp;{<span style="color: #a626a4;line-height: 26px;">@link</span>&nbsp;Condition}&nbsp;classes&nbsp;that&nbsp;must&nbsp;{<span style="color: #a626a4;line-height: 26px;">@linkplain</span>&nbsp;Condition#matches&nbsp;match}<br>&nbsp;&nbsp;*&nbsp;in&nbsp;order&nbsp;for&nbsp;the&nbsp;component&nbsp;to&nbsp;be&nbsp;registered.<br>&nbsp;&nbsp;*/</span><br>&nbsp;Class&lt;?&nbsp;extends&nbsp;Condition&gt;[]&nbsp;value();<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;"><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);">@Conditional</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);">org.springframework.context.annotation.Condition</code>这个接口判断是否应该执行操作。</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);">Condition接口</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;"><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);">@Conditional</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);">value</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);">Condition</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);">matches()</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);">true</code>表示条件成立,反之不成立,接口如下:</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/A7sq8BD8oexqmcDw0weKQfoMEUzbE9uQacGYziaoPEJs1gicSGKWHjSBr0cqG1KEjpvibibH7DBpRl6JhaVrWicEp16ORbGSbpsjJ/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(250, 250, 250);height: 30px;width: 100%;margin-bottom: -7px;bord

SpringBoot 使用 RedisTemplate Cluster集群的正确姿势(万字图文)

作者:微信小助手

<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="font-size: 16px;color: black;padding: 0 10px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"> <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;">Redis就不多做介绍了,直接进入正题,通过本篇将学习到(代码地址:<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;">https://gitee.com/chaitou/leilema.git</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;"> Redis常见功能 </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;"> Redis高可用分布式 </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;"> Springboot集成RedisTemplate的正确姿势 </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 Cache </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="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;">初学者往往认为Redis就是缓存,这其实是个误区,仅仅拿Redis当缓存好比拿瑞士军刀开瓶盖,但是Redis能做的远不止如此,以下列举几种Redis的常见应用</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;"> 分布式锁、数据结构(常见于分布式架构的系统,对分布式有较高要求的小伙伴可以考虑集成Redission) </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;"> 统计(通过RedisBitmap 位图或者hyperLogLog可以实现在极小空间消耗的情况下进行用户统计等功能) </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;"> 消息队列(对于只有简单消息队列需求的系统来说,通过Redis发布订阅 + 队列就足够了,不一定非要集成Rabbitmq之类的中间件) </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;"> GEO地理位置计算可以用于实现像微信摇一摇、附近商家等功能 </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>Redis高可用分布式<span style="display: none;"></span></h3> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;"><span style="display: none;"></span>单机版<span style="display: none;"></span></h5> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;">Redis只有一个实例,没有任何高可用分布式可言,只适合于初学者学习时使用,生产环境是绝对不允许这种情况出现的。一旦这个Redis实例崩溃了,小则缓存失效,全部数据查询走数据库,数据库访问需求暴增。大则影响分布式锁的等功能造成业务异常</p> <h5 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;"><span style="display: none;"></span>高可用Sentinel<span style="display: none;"></span></h5> <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/82b91457b8b5b4efe6de7ba2220b4216.png" data-type="png" style="display: block;margin: 0px auto;max-width: 100%;" data-ratio="0.6722222222222223" data-w="1080"> </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;bor

一个依赖搞定 Spring Boot 接口防盗刷

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;word-wrap: break-word;text-align: left;padding: 5px;font-size: 16px;color: #353535;word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-light, PingFangTC-light, 'Open Sans', 'Helvetica Neue', 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;">kk-anti-reptile 是适用于基于 spring-boot 开发的分布式系统的反爬虫组件。</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><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="系统要求" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="2"><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">系统要求</span></a><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"></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;"> 基于 spring-boot 开发(spring-boot1.x, spring-boot2.x均可) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 需要使用 redis </section></li> </ul> <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><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="工作流程" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="2"><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">工作流程</span></a><span style="font-size: 18px;font-weight: 700;color: #222;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);"></span></h2> <p data-tool="mdnice编辑器" style="line-height: 1.75;margin: 0.8em 0px;font-size: 16px;color: rgb(53, 53, 53);word-break: break-word;overflow-wrap: break-word;text-align: left;padding: 5px;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;"><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="kk-anti-reptile 使用基于 Servlet 规范的的 Filter 对请求进行过滤,在其内部通过 spring-boot 的扩展点机制,实例化一个 Filter,并注入到 Spring 容器 FilterRegistrationBean 中,通过 Spring 注入到 Servlet 容器中,从而实现对请求的过滤。" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="2"><span style="color: rgb(0, 0, 0);">kk-anti-reptile 使用基于 Servlet 规范的的 Filter 对请求进行过滤,在其内部通过 spring-boot 的扩展点机制,实例化一个 Filter,并注入到 Spring 容器 FilterRegistrationBean 中,通过 Spring 注入到 Servlet 容器中,从而实现对请求的过滤。</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;">在 kk-anti-reptile 的过滤 Filter 内部,又通过责任链模式,将各种不同的过滤规则织入,并提供抽象接口,可由调用方进行规则扩展。</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;"><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="Filter 调用则链进行请求过滤,如过滤不通过,则拦截请求,返回状态码 509,并输出验证码输入页面,输出验证码正确后,调用过滤规则链对规则进行重置。" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">Filter 调用则链进行请求过滤,如过滤不通过,则拦截请求,返回状态码 509,并输出验证码输入页面,输出验证码正确后,调用过滤规则链对规则进行重置。</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;">目前规则链中有如下两个规则</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><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="ip-rule" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="2"><span style="font-size: 16px;color: #222;">ip-rule</span></a><span style="font-size: 16px;color: #222;"></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;">ip-rule 通过时间窗口统计当前时间窗口内请求数,小于规定的最大请求数则可通过,否则不通过。时间窗口、最大请求数、ip 白名单等均可配置。</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;">ua-rule</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;">ua-rule 通过判断请求携带的 User-Agent,得到操作系统、设备信息、浏览器信息等,可配置各种维度对请求进行过滤。</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);">命中规则后</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;"><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="命中爬虫和防盗刷规则后,会阻断请求,并生成接除阻断的验证码,验证码有多种组合方式,如果客户端可以正确输入验证码,则可以继续访问" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">命中爬虫和防盗刷规则后,会阻断请求,并生成接除阻断的验证码,验证码有多种组合方式,如果客户端可以正确输入验证码,则可以继续访问</span></a></p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.8185053380782918" src="/upload/9fc06dc3452840d10500fbb307c97dc3.png" data-type="png" data-w="562" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> </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;"><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="验证码有中文、英文字母+数字、简单算术三种形式,每种形式又有静态图片和 GIF 动图两种图片格式,即目前共有如下六种,所有类型的验证码会随机出现,目前技术手段识别难度极高,可有效阻止防止爬虫大规模爬取数据" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">验证码有中文、英文字母+数字、简单算术三种形式,每种形式又有静态图片和 GIF 动图两种图片格式,即目前共有如下六种,所有类型的验证码会随机出现,目前技术手段识别难度极高,可有效阻止防止爬虫大规模爬取数据</span></a></p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.36923076923076925" src="/upload/94cae7442725915cfdecba66c7a19372.png" data-type="gif" data-w="130" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> </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);">接入使用</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;">后端接入非常简单,只需要引用 <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);">kk-anti-reptile</code> 的 maven 依赖,并配置启用 <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);">kk-anti-reptile</code> 即可加入 maven 依赖</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/A7sq8BD8oexqmcDw0weKQQVcWoJiaJWcRWwnVqv2PJTzEmCztWWxlh5QdKtbxf56x1pXuFNdUfuDQgdB2Wib7EBPuILcRyKAPb/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>cn.keking.project<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>kk-anti-reptile<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>1.0.0-SNAPSHOT<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> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">配置启用 kk-anti-reptile</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/A7sq8BD8oexqmcDw0weKQQVcWoJiaJWcRWwnVqv2PJTzEmCztWWxlh5QdKtbxf56x1pXuFNdUfuDQgdB2Wib7EBPuILcRyKAPb/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;">anti.reptile.manager.enabled=true</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;"><a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="前端需要在统一发送请求的 ajax 处加入拦截,拦截到请求返回状态码 509 后弹出一个新页面,并把响应内容转出到页面中,然后向页面中传入后端接口 baseUrl 参数即可,以使用 axios 请求为例:" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">前端需要在统一发送请求的 ajax 处加入拦截,拦截到请求返回状态码 509 后弹出一个新页面,并把响应内容转出到页面中,然后向页面中传入后端接口 baseUrl 参数即可,以使用 axios 请求为例:</span></a></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/A7sq8BD8oexqmcDw0weKQQVcWoJiaJWcRWwnVqv2PJTzEmCztWWxlh5QdKtbxf56x1pXuFNdUfuDQgdB2Wib7EBPuILcRyKAPb/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;">import</span>&nbsp;axios&nbsp;from&nbsp;<span style="color: #50a14f;line-height: 26px;">'axios'</span>;<br><span style="color: #a626a4;line-height: 26px;">import</span>&nbsp;{baseUrl}&nbsp;from&nbsp;<span style="color: #50a14f;line-height: 26px;">'./config'</span>;<br><br>axios.interceptors.response.use(<br>&nbsp;&nbsp;data&nbsp;=&amp;gt;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">return</span>&nbsp;data;<br>&nbsp;&nbsp;},<br>&nbsp;&nbsp;error&nbsp;=&amp;gt;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">if</span>&nbsp;(error.response.status&nbsp;===&nbsp;<span style="color: #986801;line-height: 26px;">509</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;html&nbsp;=&nbsp;error.response.data;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;verifyWindow&nbsp;=&nbsp;window.open(<span style="color: #50a14f;line-height: 26px;">""</span>,<span style="color: #50a14f;line-height: 26px;">"_blank"</span>,<span style="color: #50a14f;line-height: 26px;">"height=400,width=560"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;verifyWindow.document.write(html);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;verifyWindow.document.getElementById(<span style="color: #50a14f;line-height: 26px;">"baseUrl"</span>).value&nbsp;=&nbsp;baseUrl;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>);<br>export&nbsp;<span style="color: #a626a4;line-height: 26px;">default</span>&nbsp;axios;<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);">注意</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;"> apollo-client 需启用 bootstrap </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 target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="使用 apollo 配置中心的用户,由于组件内部用到 @ConditionalOnProperty,要在 application.properties/bootstrap.properties 中加入如下样例配置,(apollo-client 需要 0.10.0 及以上版本)详见 apollo bootstrap 说明" linktype="text" imgurl="" imgdata="null" tab="innerlink" data-linktype="2"><span style="color: rgb(0, 0, 0);">使用 apollo 配置中心的用户,由于组件内部用到 </span><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);"><span style="color: rgb(0, 0, 0);">@ConditionalOnProperty</span></code><span style="color: rgb(0, 0, 0);">,要在 </span><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);"><span style="color: rgb(0, 0, 0);">application.properties/bootstrap.properties</span></code><span style="color: rgb(0, 0, 0);"> 中加入如下样例配置,(apollo-client 需要 0.10.0 及以上版本)详见 apollo bootstrap 说明</span></a></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/A7sq8BD8oexqmcDw0weKQQVcWoJiaJWcRWwnVqv2PJTzEmCztWWxlh5QdKtbxf56x1pXuFNdUfuDQgdB2Wib7EBPuILcRyKAPb/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;">apollo.bootstrap.enabled = true</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;"> 需要有 Redisson </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 target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzU3MDAzNDg1MA==&amp;mid=2247511732&amp;idx=1&amp;sn=56519bf049140f17c713f5c8af40e5c5&amp;chksm=fcf77179cb80f86ffb23213b5c21d7ce3eeb99ffa1744b0fbe148b461de4976ec15e6f38753a&amp;scene=21&amp;cur_album_id=2042874937312346114#wechat_redirect" textvalue="连接如果项目中有用到 Redisson,kk-anti-reptile 会自动获取 RedissonClient 实例对象; 如果没用到,需要在配置文件加入如下 Redisson 连接相关配置:" linktype="text" imgurl="" imgdata="null" tab="innerlink" style="color: rgb(0, 0, 0);" data-linktype="2"><span style="color: rgb(0, 0, 0);">连接如果项目中有用到 Redisson,kk-anti-reptile 会自动获取 RedissonClient 实例对象; 如果没用到,需要在配置文件加入如下 Redisson 连接相关配置:</span></a></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/A7sq8BD8oexqmcDw0weKQQVcWoJiaJWcRWwnVqv2PJTzEmCztWWxlh5QdKtbxf56x1pXuFNdUfuDQgdB2Wib7EBPuILcRyKAPb/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;">spring.redisson.address=redis://192.168.1.204:6379<br>spring.redisson.password=xxx</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);">配置一览表</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;">在 spring-boot 中,所有配置在配置文件都会有自动提示和说明,如下图:</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.42706964520367935" src="/upload/83001fa2d71a6dce04c81f8cbe201dde.png" data-type="png" data-w="761" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> </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;">所有配置都以 <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);">anti.reptile.manager</code> 为前缀,如下为所有配置项及说明:</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;padding: 0px 0.5em;"> <img class="rich_pages wxw-img" data-ratio="0.6895475819032761" src="/upload/eb014a46e09c1d4a1b8f110d6f6dc7df.png" data-type="png" data-w="641" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;font-size: 17px;"> </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);">最后说一句(别白嫖,求关注)</span></h2> </section>

聊聊服务器性能优化~(建议收藏)

作者:微信小助手

<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;">大家好,我是飘渺。听多了架构优化,数据库优化,今天我们来聊聊服务器优化。</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;">我们开发的软件服务需要在服务器上运行,所以服务器性能代表了软件的性能上限,因此服务器性能调优是个十分重要的环节,然而大部分同学对服务器性能调优关注的较少,今天从3个部分对服务器性能调优进行介绍,分别是:服务器配置选择,服务器负载分析,服务器内核参数调优。</p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzAwMTk4NjM1MA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/PxMzT0Oibf4gcBzLSUNh2cgXUsuLIsvQYJE1lzZd74qpC3iciaM6gcYIfOVV0KjDDkeN4CTLTn4ETPtaHOAuTWSWA/0?wx_fmt=png" data-nickname="JAVA日知录" data-alias="javadaily" data-signature="写代码的架构师,做架构的程序员! 实战、源码、数据库、架构...只要你来,你想了解的这里都有!" data-from="0"></mpprofile> </section> <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);">服务器配置选择</span><span></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;">服务器一般是由CPU、内存、磁盘和网卡组成,因此选择服务器配置就是选择CPU核数、内存大小、磁盘大小及类型、网络带宽。但是,服务器配置的选择是很难标准化的,也就是说很难推断出“一台需要达到1000TPS的后端服务器”的配置应该是什么样的。因为软件的最终运行性能与软件的实现方式是紧密相关的,即使是同一个后端应用程序中的两个接口,由于具体功能的差别,性能也会有所差别。</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;">因此,服务器配置的选择应该基于具体的测试结果。一开始可以选用配置较低的服务器做调优和测试,并以该服务器的测试结果作为选择服务器的依据。</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;">以一个订单业务为例,经过测试后,一台配置为4核 CPU 、16GB内存、10Mbps带宽、50GB机械磁盘的服务器的测试结果为:支持50并发量和300TPS吞吐量(增大并发量后会出现超时报错)。而在压力测试过程中, CPU 的使用率接近75%,内存使用率在 50%以下,带宽使用率在50%以下,除去日志以外无磁盘操作。</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;">因此可以认为,一台配置为4核 CPU ( CPU 使用率需要在75%以下)、8GB内存(内存使用率可以接近100%)、 5Mbps 带宽(带宽使用率可以接近100%)的服务器,可以满足订单接口支持50并发量、300TPS吞吐量的压力。</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;">如果需要达到200并发数、2400TPS吞吐量的目标的话,则需要8台配置为4核 CPU 、8GB内存、5Mbps带宽的服务器,或者1台配置为32核 CPU 、64GB内存、40Mbps带宽的服务器。当然,最终的服务器配置还是需要通过测试来验证。</p> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;display: block;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;font-style: normal;padding: 15px 10px;line-height: 1.75;border-radius: 13px;color: rgb(53, 53, 53);background: rgb(245, 245, 245);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: #353535;font-size: 16px;margin: 0 10px;display: block;">注意:在以上订单接口的例子中,后端服务器和数据库等服务器需要一起调试,避免后端服务器性能过剩,而数据库等服务器性能不足的情况发生。另外,以上选择服务器配置的方法不一定适用于所有场景,请斟酌参考。</p> </blockquote> <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);">服务器负载分析</span><span></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;">在性能调优时,需要先对服务器负载进行分析,通常而言,我们主要分析CPU使用率、内存使用率、磁盘I/O,服务器负载和带宽使用情况。</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;">CPU使用率</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;">CPU使用率反应的是CPU的忙碌情况。当CPU达到100%时,部分进程会进入等待状态,CPU暂时不会对其进行处理。<strong style="font-weight: 700;color: rgb(248, 57, 41);">在实际情况下,为了应对一下突发性的请求压力,服务器CPU使用率一般需要在75%以下。如果一台服务器的CPU使用率多次高于75%,这时候就考虑增加新的服务器。</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;">监控CPU使用率我推荐大家使用<strong style="font-weight: 700;color: rgb(248, 57, 41);">htop</strong>工具,可以非常直观看到CPU使用率、内存使用率、及负载等信息。</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><span>使用htop查看CPU负载</span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">首先我们需要安装htop,以centos为例,安装命令如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">yum&nbsp;install&nbsp;htop&nbsp;-y<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;">安装完成后我们就可以通过<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);">htop</code>命令观察CPU负载了</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">htop<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;">输入<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);">htop</code>命令后我们可以很直观的看到CPU负载情况,该命令的CPU使用率会以多个核作为单位进行显示。操作系统机会自动分配多个核的负载,当所有核的CPU使用率都超过75%时才能认为服务器的CPU使用率已经超过75%。</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;"> <img class="rich_pages wxw-img" data-ratio="0.3905160390516039" src="/upload/80d1a7c083d24ad9366c41cb2891f9d1.png" data-type="png" data-w="1434" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;display: block;font-size: 12px;"> cpu负载 </figcaption> </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;">如上图所示,这是一个4核CPU服务器,在截图的时候其中3核CPU使用率都超过了75%,再观察一会发现所有CPU的使用率都在85%左右徘徊,说明CPU负载很高了,需要考虑增加新的服务器。</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;">内存使用率</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;">内存使用率反应的是内存的使用情况。内存用于存放程序的代码及数据,一般分为物理内存和虚拟内存,其中物理内存指的是服务器的内存,而虚拟内存指的是硬盘的一块空间。当物理内存使用率达到100%时将会使用虚拟内存。需要注意的是,虚拟内存的读写速度远远低于物理内存,如果程序被放在了虚拟内存执行,那么程序的执行效率会变得很低。</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);">一般而言,服务器的物理内存应该保持在80%以下,虚拟内存使用率保持在0%。</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;">服务器内存使用情况还是可以通过hop工具进行查看</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;"> <img class="rich_pages wxw-img" data-ratio="0.41657922350472193" src="/upload/eb7427a8a8e4d846a1bba267afe99d.png" data-type="png" data-w="1906" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;display: block;font-size: 12px;"> 内存使用率 </figcaption> </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;">上面显示了服务器的内存使用情况:总内存16G,使用了10G左右,内存使用率62%,可以继续使用,同时关闭了Swap虚拟内存。</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;">在下<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);">MEM%</code>栏中显示了单个进程的内存使用率。</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;">磁盘I/O</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;">磁盘I/O指的是磁盘的读写,在软件系统中,日志、文件操作、数据库操作都会造成磁盘读写压力,其中又以数据库操作为甚,在高并发情况下往往数据库会首先成为系统的瓶颈。</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;">磁盘监控我推荐大家使用iostat工具,可以很方便查看磁盘的使用情况。</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><span>使用iostat查看磁盘I/O</span><span style="display: none;"></span></h4> <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);">iostat</code>,以centos为例,安装命令如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">yum&nbsp;install&nbsp;sysstat&nbsp;-y<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;">安装完成后我们就可以通过<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);">iostat</code>命令磁盘使用情况了。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #4078f2;line-height: 26px;">#</span><span style="line-height: 26px;">&nbsp;查看磁盘总体读写情况,&nbsp;1代表每1秒读取一次数据</span><br>iostat&nbsp;-x&nbsp;1<br></code></pre> <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.16613418530351437" src="/upload/d8c477cadaaa3e0c6522cb33fed137d2.png" data-type="png" data-w="1878" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;display: block;font-size: 12px;"> 磁盘IO </figcaption> </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;">输入<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);">iostat</code>命令后,磁盘总体读写情况如上所示。磁盘负载主要关注2个指标:<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);">%idle</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);">%util</code></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;"> <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);">%idle</code>:表示CPU <strong style="font-weight: 700;color: rgb(248, 57, 41);">除去等待磁盘I/O以外</strong>的空闲时间百分比,这个指标应该要保证在70%以上 </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);">%util</code>:该设备用于I/O操作的时间百分比,这个指标需要保证在70%以下,当到达100%时表示已经满负载。为了降低磁盘负载,可以采用性能更高的磁盘(OSD,PCIE)或者降低磁盘的操作频率(异步写、合并写) </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;">平均负载</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;">平均负载指的是单位时间内平均的活跃进程数,是一个表示服务器负载的指标。一般情况下需要保证平均负载的值小于当前服务器的CPU核数。</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;">同样的,查看服务器平均负载我们也可以使用<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);">htop</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;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.15894868585732166" src="/upload/76366b657577de2b89289c90c37cb1f.png" data-type="png" data-w="1598" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: left;color: rgb(136, 136, 136);display: block;font-size: 12px;"> <span style="color: rgb(53, 53, 53);font-size: 16px;letter-spacing: 0.8px;word-spacing: 0.8px;">在这里我们主要关注</span> <code style="letter-spacing: 0.8px;word-spacing: 0.8px;font-size: 14px;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(255, 93, 108);">Load average</code> <span style="color: rgb(53, 53, 53);font-size: 16px;letter-spacing: 0.8px;word-spacing: 0.8px;">指标,上图有3个数字,分别代表1分钟,5分钟,15分钟的平均负载。</span> <br> </figcaption> </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;">一般情况下服务器的平均负载需要小于当前服务器的CPU核数,为了应对突发状况,服务器的平均负载应该在75%即3 以下,很显然,上图这台服务器平均负载超过了75%,需要考虑提升性能了。</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;">网络使用情况</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;">网络使用情况也是监控的重要指标。当带宽不足时会大大增加请求的响应时间。为了防止突发性并发压力,应该保证服务器的带宽使用率在80%以上。这里需要注意的是,物理网卡限制了服务器所能使用的最大宽带。</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;">查看网络使用情况我推荐使用<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);">nload</code>工具。</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><span>使用nload查看网络</span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">首先需要安装nload,以centos为例</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">yum&nbsp;install&nbsp;nload&nbsp;-y<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;">安装完成后我们直接运行<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);">nload</code></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">nload<br></code></pre> <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.8351409978308026" src="/upload/c2573276c4d52e3c8292f44dc4a28c4b.png" data-type="png" data-w="1844" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </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;">输入<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);">nload</code>命令后,网络使用情况如上图所示。其中,网络使用情况分为流入网卡的数据与流出网卡的数据。流入网卡的对应下行带宽的网速,流出网卡的数据对应上行带宽的网速。如果 “当前网速” 持续接近 “最大网速” 时,代表带宽使用率已经接近100%。</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;">指标说明:</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;"> Curr:当前网速 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Avg:平均网速 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Min:最小网速 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Max:最大网速 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Ttl:总流量 </section></li> </ul> <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);">服务器内核参数调优</span><span></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;">光有强大的物理性能是不够的,还需要对内核参数进行调优,这样才能在高并发压力下充分体现服务器应有的性能。当然,并不是所有的服务器都需要做高并发性能调优,一般来说,只需要对要处理高并发请求的服务器进行内核参数调优即可,常见的包括:前端服务器,后端服务器,数据库服务器。</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;">服务器常见的调优参数主要有两个:单个进程最大打开文件数 和 TCP相关设置。</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;">单个进程最大打开文件数</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;">修改单个文件最大打开文件数,只需要编辑<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);">/etc/security/limits.conf</code>文件,在文件末尾加上以下四句</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">* soft nofile 65535<br>* hard nofile 65535<br>* soft nproc 65535<br>* hard nproc 65535</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;">其中<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);">*</code> 代表所有用户,65536代表修改的值,重启后生效。</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;">TCP相关设置</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;">修改TCP相关参数,可以优化TCP高并发通信,编辑<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);">/etc/sysctl.conf</code>文件,添加以下内容</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"># 为防止洪水攻击,高并发系统需要将此项关闭<br>net.ipv4.tcp_syncookies = 0<br><br># 开启TCP连接重用,允许处理TIME-WAIT状态的连接重新用于新的TCP连接<br>net.ipv4.tcp_tw_reuse = 1<br><br># 开启快速回收TCP连接中处于TIME-WAIT状态的连接<br>net.ipv4.tcp_tw_recycle = 1<br><br>#修改超时时间( s ),该值表示如果连接由本端关闭,则连接处于 FIN-WAIT-2状态的时间为 <br>net.ipv4.tcp_fin_timeout = 30<br><br>#当 keepalive(长连接)启用的时候,TCP发送 keepalive 消息(探测包)的时间间隔( s ),默认为2个小时<br>net.ipv4.tcp_keepalive_time =1200<br><br>#服务器对外连接的端口范围,影响该服务器与其他服务器的连接数<br>net.ipv4.ip_local_port_range =102465535<br><br>#SYN队列的长度,可以容纳更多等待连接的网络连接数,默认为1024 <br>net.ipv4.tcp_max_syn_backlog = 65535<br><br>#保持 TIME_WAIT 状态连接的最大数量,如果超过此值,TIME_WAIT 将立刻被清除并打印警告信息,默认为180000<br>net.ipv4.tcp_max_tw_buckets =5000<br><br>#每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目<br>net.core.netdev_max_backlog =65535<br><br># TCP最大连接数<br>net.core.somaxconn = 65535<br><br>#预留用于接收缓冲的内存默认值(字节) <br>net.core.rmem_default = 8388608<br><br>#预留用于接收缓冲的内存最大值(字节) <br>net.core.rmem_max = 16777216<br><br>#预留用于发送缓冲的内存默认值(字节) <br>net.core.wmem_default = 8388608<br><br>#预留用于发送缓冲的内存最大值(字节) <br>net.core.wmem_maX = 16777216<br><br>#避免时间戳异常<br>net.ipv4.tcp_timestamps = 0<br><br>#系统中最多有多少个 TCP 套接字不被关联到任何一个用户文件句柄上,如果超过这个数字,连接将即刻被复位并打印警告信息,这个限制仅仅是为了防止简单的DoS 攻击<br>net.ipv4.tcp_max_orphans =3276800</code></pre> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="box-sizing: border-box !important;margin: 0px;padding: 5px;outline: 0px;display: block;max-width: 100%;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;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.6;word-break: break-word;text-align: left;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;visibility: visible;"> <p data-tool="mdnice编辑器" style="box-sizing: border-box !important;margin: 0.8em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;clear: both;min-height: 1em;line-height: 1.75;"><span style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;color: rgb(248, 57, 41);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-weight: 700;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);">好了,今天就到这儿吧,我是飘渺,我们下期见~~</span><span style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;letter-spacing: 0.8px;word-spacing: 0.8px;"></span></p> </section> <h2 data-tool="mdnice编辑器" style="box-sizing: border-box !important;margin: 20px 10px 0px 0px;padding: 0px;outline: 0px;font-family: inherit;font-weight: bold;color: black;font-size: 22px;max-width: 100%;overflow-wrap: break-word !important;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;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;background-color: rgb(255, 255, 255);letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;"><span style="box-sizing: border-box !important;margin: 0px;padding: 0px 0px 0px 10px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-size: 18px;color: rgb(34, 34, 34);display: inline-block;border-left: 5px solid rgb(248, 57, 41);">最后说一句(别白嫖,求关注)</span></h2> <p data-tool="mdnice编辑器" style="box-sizing: border-box !important;margin: 0.8em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;clear: both;min-height: 1em;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;-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: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;line-height: 1.75;"><span style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;letter-spacing: 0.8px;word-spacing: 0.8px;font-weight: 700;color: rgb(248, 57, 41);">新</span><span style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;letter-spacing: 0.8px;word-spacing: 0.8px;font-weight: 700;color: rgb(248, 57, 41);">开了一个纯技术交流群(一群已满),群里氛围还不错,无广告,无套路,单纯的吹牛逼,侃人生,想进的可以通过下方二维码加我微信,备注进群!</span><span style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-weight: 700;color: rgb(248, 57, 41);"></span></p> <p style="box-sizing: border-box !important;margin: 0px 0px 0em;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;clear: both;min-height: 1em;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;-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: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.8px;word-spacing: 0.8px;text-align: center;"><img class="rich_pages wxw-img" data-ratio="1" src="/upload/8b7563d4d4d258fa30f9f6b60029eb7e.jpg" data-type="jpeg" data-w="430" style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;vertical-align: bottom;border-style: none;max-width: 100%;overflow-wrap: break-word !important;height: auto !important;visibility: visible !important;width: 239px !important;"></p> <p><br></p>

是时候给传统的设计模式换个写法了~

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;word-wrap: break-word;text-align: left;padding: 5px;font-size: 16px;color: #353535;word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', 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;">java8中提供的很多新特性可以用来重构传统设计模式中的写法,相比传统模式,这种写法更简单优雅。下面是一些示例:</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);">一、策略模式</span></h2> <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" src="/upload/6d76a922a4b98063cff95f00d2e12d9b.png" data-type="png" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;" data-ratio="0.33055555555555555" data-w="1080"> </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;">上图是策略模式的类图,假设我们现在要保存订单,<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);">OrderService</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);">NoSqlSaveOrderStragegy</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);">MySqlSaveOrderStrategy</code>则提供了二种策略,分别是保存到nosql数据库,以及传统的mysql关系型数据库,最后在<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);">OrderServiceExecutor</code>中通过构造函数注入最终要使用的策略。</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;">传统写法</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;">使用传统写法,这个场景至少得4个类,代码如下:</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;">OrderService接口:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">OrderService</span>&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;">saveOrder</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span></span>;<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;">Mysql策略实现:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">MySqlSaveOrderStrategy</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">OrderService</span>&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;">saveOrder</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"order:"</span>&nbsp;+&nbsp;orderNo&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"&nbsp;save&nbsp;to&nbsp;mysql"</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;">Nosql策略实现</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">NoSqlSaveOrderStrategy</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">OrderService</span>&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;">saveOrder</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"order:"</span>&nbsp;+&nbsp;orderNo&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"&nbsp;save&nbsp;to&nbsp;nosql"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}&nbsp;<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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">OrderServiceExecutor</span>&nbsp;</span>{<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">private</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">final</span>&nbsp;OrderService&nbsp;service;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">OrderServiceExecutor</span><span style="line-height: 26px;">(OrderService&nbsp;service)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">this</span>.service&nbsp;=&nbsp;service;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;<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;">save</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">this</span>.service.saveOrder(orderNo);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;<br>}&nbsp;&nbsp;<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;"><br></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;">运行测试类:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">OrderServiceTest</span>&nbsp;</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;">static</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">main</span><span style="line-height: 26px;">(String[]&nbsp;args)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OrderServiceExecutor&nbsp;executor1&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;OrderServiceExecutor(<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;MySqlSaveOrderStrategy());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executor1.save(<span style="color: #50a14f;line-height: 26px;">"001"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OrderServiceExecutor&nbsp;executor2&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;OrderServiceExecutor(<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;NoSqlSaveOrderStrategy());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executor2.save(<span style="color: #50a14f;line-height: 26px;">"002"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}&nbsp;&nbsp;<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;">重构写法</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;">重构后,可以省去2个策略实现类,代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">main</span><span style="line-height: 26px;">(String[]&nbsp;args)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;OrderServiceExecutor&nbsp;executor1&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;OrderServiceExecutor((String&nbsp;orderNo)&nbsp;-&gt;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"order:"</span>&nbsp;+&nbsp;orderNo&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"&nbsp;save&nbsp;to&nbsp;mysql"</span>));<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;executor1.save(<span style="color: #50a14f;line-height: 26px;">"001"</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;OrderServiceExecutor&nbsp;executor2&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;OrderServiceExecutor((String&nbsp;orderNo)&nbsp;-&gt;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"order:"</span>&nbsp;+&nbsp;orderNo&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"&nbsp;save&nbsp;to&nbsp;nosql"</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;executor2.save(<span style="color: #50a14f;line-height: 26px;">"002"</span>);<br>}<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);">二、模板方法</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;">类图如下,核心思路是把一些通用的标准方法,在抽象父类里仅定义方法签名,实现逻辑交给子类。</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;">比如:会员系统中,每个商家都会有一些营销活动,需要推送某种信息给会员,但是不同的商家推送的内容可能不同,有些需要推送优惠券,有些需要积分通知。</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;"> <img class="rich_pages wxw-img" src="/upload/a17833348bbcd6a537c5e75b90ea302a.png" data-type="png" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;" data-ratio="0.37448559670781895" data-w="972"> </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;">传统写法</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;">抽象模板类:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">abstract</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">AbstractPushTemplate</span>&nbsp;</span>{<br>&nbsp;<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;">push</span><span style="line-height: 26px;">(<span style="color: #a626a4;line-height: 26px;">int</span>&nbsp;customerId,&nbsp;String&nbsp;shopName)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"准备推送..."</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;execute(customerId,&nbsp;shopName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"推送完成\n"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">abstract</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">protected</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">execute</span><span style="line-height: 26px;">(<span style="color: #a626a4;line-height: 26px;">int</span>&nbsp;customerId,&nbsp;String&nbsp;shopName)</span></span>;<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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">PushCouponTemplate</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">extends</span>&nbsp;<span style="color: #c18401;line-height: 26px;">AbstractPushTemplate</span>&nbsp;</span>{<br>&nbsp;<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;">protected</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">execute</span><span style="line-height: 26px;">(<span style="color: #a626a4;line-height: 26px;">int</span>&nbsp;customerId,&nbsp;String&nbsp;shopName)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"会员:"</span>&nbsp;+&nbsp;customerId&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">",你好,"</span>&nbsp;+&nbsp;shopName&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"送您一张优惠券"</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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">PushScoreTemplate</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">extends</span>&nbsp;<span style="color: #c18401;line-height: 26px;">AbstractPushTemplate</span>&nbsp;</span>{<br>&nbsp;<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;">protected</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">execute</span><span style="line-height: 26px;">(<span style="color: #a626a4;line-height: 26px;">int</span>&nbsp;customerId,&nbsp;String&nbsp;shopName)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"会员:"</span>&nbsp;+&nbsp;customerId&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">",你好,"</span>&nbsp;+&nbsp;shopName&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"送您10个积分"</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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">AbstractPushTemplate&nbsp;template1&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;PushCouponTemplate();<br>template1.push(<span style="color: #986801;line-height: 26px;">1</span>,&nbsp;<span style="color: #50a14f;line-height: 26px;">"糖果店"</span>);<br>&nbsp;<br>AbstractPushTemplate&nbsp;template2&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;PushScoreTemplate();<br>template2.push(<span style="color: #986801;line-height: 26px;">1</span>,&nbsp;<span style="color: #50a14f;line-height: 26px;">"服装店"</span>);&nbsp;<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;">重构写法</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;">显然如果模板的实现方式越多,子类就越多。使用java8重构后,可以把上面的3个模板(包括抽象类模板)减少到1个,参考下面:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">PushTemplateLambda</span>&nbsp;</span>{<br>&nbsp;<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;">push</span><span style="line-height: 26px;">(<span style="color: #a626a4;line-height: 26px;">int</span>&nbsp;customerId,&nbsp;String&nbsp;shopName,&nbsp;Consumer&lt;Object[]&gt;&nbsp;execute)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"准备推送..."</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object[]&nbsp;param&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;Object[]{customerId,&nbsp;shopName};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;execute.accept(param);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"推送完成\n"</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;">借助<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);">Consumer&lt;T&gt;这个function interface</code>,可以省去实现子类,具体的实现留到使用时再来决定,如:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;PushTemplateLambda().push(<span style="color: #986801;line-height: 26px;">1</span>,&nbsp;<span style="color: #50a14f;line-height: 26px;">"糖果店"</span>,&nbsp;(Object[]&nbsp;obj)&nbsp;-&gt;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"会员:"</span>&nbsp;+&nbsp;obj[<span style="color: #986801;line-height: 26px;">0</span>]&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">",你好,"</span>&nbsp;+&nbsp;obj[<span style="color: #986801;line-height: 26px;">1</span>]&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"送您一张优惠券"</span>);<br>});<br>&nbsp;<br><span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;PushTemplateLambda().push(<span style="color: #986801;line-height: 26px;">1</span>,&nbsp;<span style="color: #50a14f;line-height: 26px;">"服装店"</span>,&nbsp;(Object[]&nbsp;obj)&nbsp;-&gt;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"会员:"</span>&nbsp;+&nbsp;obj[<span style="color: #986801;line-height: 26px;">0</span>]&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">",你好,"</span>&nbsp;+&nbsp;obj[<span style="color: #986801;line-height: 26px;">1</span>]&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"送您10个积分"</span>);<br>});<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);">三、观察者模式</span></h2> <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" src="/upload/bd5bfbb76208180a92b0972ff8eb49d4.png" data-type="png" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;" data-ratio="0.3159379407616361" data-w="709"> </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;">思路:基于某个Subject主题,然后一堆观察者Observer注册到主题上,有事件发生时,subject根据注册列表,去通知所有的observer。</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;">传统写法</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;">Observer接口:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">Observer</span>&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;">notify</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span></span>;<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;">Subject接口:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">Subject</span>&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;">registerObserver</span><span style="line-height: 26px;">(Observer&nbsp;o)</span></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;">notifyAllObserver</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span></span>;<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;">Subject接口实现:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">SubjectImpl</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">Subject</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">private</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">final</span>&nbsp;List&lt;Observer&gt;&nbsp;list&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;ArrayList&lt;&gt;();<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;">registerObserver</span><span style="line-height: 26px;">(Observer&nbsp;o)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.add(o);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<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;">notifyAllObserver</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.forEach(c&nbsp;-&gt;&nbsp;c.notify(orderNo));<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}&nbsp;<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> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0;font-size: 16px;color: #353535;">OrderObserver:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">OrderObserver</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">Observer</span>&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;">notify</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"订单&nbsp;"</span>&nbsp;+&nbsp;orderNo&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"&nbsp;状态更新为【已支付】"</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;">StockObserver:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">StockObserver</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">Observer</span>&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;">notify</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"订单&nbsp;"</span>&nbsp;+&nbsp;orderNo&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"&nbsp;已通知库房发货!"</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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">static</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">test1</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;Subject&nbsp;subject&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;SubjectImpl();<br>&nbsp;&nbsp;&nbsp;&nbsp;subject.registerObserver(<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;OrderObserver());<br>&nbsp;&nbsp;&nbsp;&nbsp;subject.registerObserver(<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;StockObserver());<br>&nbsp;&nbsp;&nbsp;&nbsp;subject.notifyAllObserver(<span style="color: #50a14f;line-height: 26px;">"001"</span>);<br>}&nbsp;<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;">重构写法</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;">用java8重构后,接口可以提供默认实现方法,我们弄一个新的主题接口:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">NewSubject</span>&nbsp;</span>{<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Observer&gt;&nbsp;list&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;ArrayList&lt;&gt;();<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">default</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">registerObserver</span><span style="line-height: 26px;">(Observer&nbsp;o)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.add(o);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">default</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">nofityAllObserver</span><span style="line-height: 26px;">(String&nbsp;orderNo)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.forEach(c&nbsp;-&gt;&nbsp;c.notify(orderNo));<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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">static</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">test2</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;NewSubject&nbsp;subject&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;NewSubject()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;subject.registerObserver((String&nbsp;orderNo)&nbsp;-&gt;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"订单&nbsp;"</span>&nbsp;+&nbsp;orderNo&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"&nbsp;状态更新为【已支付】"</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;subject.registerObserver((String&nbsp;orderNo)&nbsp;-&gt;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"订单&nbsp;"</span>&nbsp;+&nbsp;orderNo&nbsp;+&nbsp;<span style="color: #50a14f;line-height: 26px;">"&nbsp;已通知库房发货!"</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;subject.nofityAllObserver(<span style="color: #50a14f;line-height: 26px;">"002"</span>);<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;">只用2个接口实现了观察者模式。</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);">四、责任链/职责链模式</span></h2> <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" src="/upload/f502df7ecb08d3511b85f6f05de4b1c0.png" data-type="png" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;" data-ratio="0.8179419525065963" data-w="758"> </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> <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;">传统写法</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;">Processor接口:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">Processor</span>&nbsp;</span>{<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">Processor&nbsp;<span style="color: #4078f2;line-height: 26px;">getNextProcessor</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<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;">process</span><span style="line-height: 26px;">(String&nbsp;param)</span></span>;<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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">abstract</span>&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span>&nbsp;<span style="color: #c18401;line-height: 26px;">AbstractProcessor</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">implements</span>&nbsp;<span style="color: #c18401;line-height: 26px;">Processor</span>&nbsp;</span>{<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">private</span>&nbsp;Processor&nbsp;next;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">AbstractProcessor</span><span style="line-height: 26px;">(Processor&nbsp;processor)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">this</span>.next&nbsp;=&nbsp;processor;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;<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;Processor&nbsp;<span style="color: #4078f2;line-height: 26px;">getNextProcessor</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;next;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;<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;">abstract</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">process</span><span style="line-height: 26px;">(String&nbsp;param)</span></span>;<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;">定义2个具体的实现</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">ProcessorImpl1</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">extends</span>&nbsp;<span style="color: #c18401;line-height: 26px;">AbstractProcessor</span>&nbsp;</span>{<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">ProcessorImpl1</span><span style="line-height: 26px;">(Processor&nbsp;processor)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">super</span>(processor);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;<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;">process</span><span style="line-height: 26px;">(String&nbsp;param)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"processor&nbsp;1&nbsp;is&nbsp;processing:"</span>&nbsp;+&nbsp;param);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">if</span>&nbsp;(getNextProcessor()&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;getNextProcessor().process(param);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><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;">ProcessorImpl2</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">extends</span>&nbsp;<span style="color: #c18401;line-height: 26px;">AbstractProcessor</span>&nbsp;</span>{<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">ProcessorImpl2</span><span style="line-height: 26px;">(Processor&nbsp;next)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">super</span>(next);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;<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;">process</span><span style="line-height: 26px;">(String&nbsp;param)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"processor&nbsp;2&nbsp;is&nbsp;processing:"</span>&nbsp;+&nbsp;param);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #a626a4;line-height: 26px;">if</span>&nbsp;(getNextProcessor()&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;getNextProcessor().process(param);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">static</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">test1</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;Processor&nbsp;p1&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;ProcessorImpl1(<span style="color: #a626a4;line-height: 26px;">null</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;Processor&nbsp;p2&nbsp;=&nbsp;<span style="color: #a626a4;line-height: 26px;">new</span>&nbsp;ProcessorImpl2(p1);<br>&nbsp;&nbsp;&nbsp;&nbsp;p2.process(<span style="color: #50a14f;line-height: 26px;">"something&nbsp;happened"</span>);<br>}<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;">重构写法</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;">用java8重构后,只需要一个新接口</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #4078f2;line-height: 26px;">@FunctionalInterface</span><br><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;">NewProcessor</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">Consumer&lt;String&gt;&nbsp;<span style="color: #4078f2;line-height: 26px;">process</span><span style="line-height: 26px;">(String&nbsp;param)</span></span>;<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;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">static</span>&nbsp;<span style="color: #a626a4;line-height: 26px;">void</span>&nbsp;<span style="color: #4078f2;line-height: 26px;">test2</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;Consumer&lt;String&gt;&nbsp;p1&nbsp;=&nbsp;param&nbsp;-&gt;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"processor&nbsp;1&nbsp;is&nbsp;processing:"</span>&nbsp;+&nbsp;param);<br>&nbsp;&nbsp;&nbsp;&nbsp;Consumer&lt;String&gt;&nbsp;p2&nbsp;=&nbsp;param&nbsp;-&gt;&nbsp;System.out.println(<span style="color: #50a14f;line-height: 26px;">"processor&nbsp;2&nbsp;is&nbsp;processing:"</span>&nbsp;+&nbsp;param);<br>&nbsp;&nbsp;&nbsp;&nbsp;p2.andThen(p1).accept(<span style="color: #50a14f;line-height: 26px;">"something&nbsp;happened"</span>);<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;"><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);">andThen</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);">getNextProcessor</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);">重要提示:什么时候该用lambda,什么时候不用,这是要看情况的,如果处理逻辑相对比较简单,可以用lamdba来重构,以便让代码更简洁易读,如果处理逻辑很复杂,应该还是用“类”。</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0.8em 0px;font-size: 16px;color: rgb(53, 53, 53);text-align: right;"><strong style="font-weight: 700;color: rgb(248, 57, 41);"><em style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-style: italic;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-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.8px;orphans: 2;text-align: right;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0.8px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(248, 57, 41);"><em style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-style: italic;color: rgb(178, 178, 178);font-family: -apple-system, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;"><span style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-size: 10px;">转自:</span></em></em><em style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-style: italic;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-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.8px;orphans: 2;text-align: right;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0.8px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(248, 57, 41);"><em style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-style: italic;color: rgb(178, 178, 178);font-family: -apple-system, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;"><span style="box-sizing: border-box !important;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-size: 10px;">http://cnblogs.com/yjmyzz/p/refactor-design-pattern-using-java8.html</span></em></em></strong></p> </section> <h2 data-tool="mdnice编辑器" style="box-sizing: border-box !important;margin: 20px 10px 0px 0px;padding: 0px;outline: 0px;font-family: inherit;font-weight: bold;color: black;font-size: 22px;max-width: 100%;overflow-wrap: break-word !important;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;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;background-color: rgb(255, 255, 255);letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;"><span style="box-sizing: border-box !important;margin: 0px;padding: 0px 0px 0px 10px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;font-size: 18px;color: rgb(34, 34, 34);display: inline-block;border-left: 5px solid rgb(248, 57, 41);">最后说一句(别白嫖,求关注)</span></h2>

千万级数据查询:CK、ES、RediSearch怎么选?

作者:微信小助手

<section powered-by="xmyeditor.com" data-mpa-powered-by="yiban.io"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <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;">文章来源:https://c1n.cn/EmgJv<span style="display: none;line-height: 0px;">‍</span><span style="display: none;line-height: 0px;">‍</span></span><br></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;"> <br> </section> <section style="text-align: left;margin-bottom: 20px;"> <strong><span style="outline: 0px;font-size: 15px;visibility: visible;">目录</span></strong> </section> <ul class="list-paddingleft-1"> <li><p><span style="font-size: 15px;letter-spacing: 2px;">前言</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;">初版设计方案</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;">CK 分页查询</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;">使用ES Scroll Scan 优化深翻页</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;">ES+Hbase 组合查询方案</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;">RediSearch+RedisJSON 优化方案</span></p></li> <li><p><span style="outline: 0px;letter-spacing: 2px;visibility: visible;font-size: 15px;">总结</span></p></li> </ul> <p><br></p> <section style="box-sizing: border-box;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-right: 0%;margin-left: 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-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">前言</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;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><span style="font-size: 15px;">在开发中遇到一个业务诉求,需要在千万量级的底池数据中筛选出不超过 10W 的数据,并根据配置的权重规则进行排序、打散(如同一个类目下的商品数据不能连续出现 3 次)。下面对该业务诉求的实现,设计思路和方案优化进行介绍。</span></p> <p><br></p> <p><span style="font-size: 15px;color: rgb(0, 122, 170);">对“千万量级数据中查询 10W 量级的数据”设计了如下方案:</span></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li style="font-weight: bold;"><p><strong><span style="font-size: 15px;">多线程+CK 翻页方案</span></strong></p></li> <li style="font-weight: bold;"><p><strong><span style="font-size: 15px;">ES scroll scan 深翻页方案</span></strong></p></li> <li style="font-weight: bold;"><p><strong><span style="font-size: 15px;">ES+Hbase 组合方案</span></strong></p></li> <li style="font-weight: bold;"><p><strong><span style="font-size: 15px;">RediSearch+RedisJSON 组合方案</span></strong></p></li> </ul> <h2 data-id="heading-2"><br></h2> <section style="box-sizing: border-box;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-right: 0%;margin-left: 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-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">初版设计方案</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;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><span style="font-size: 15px;color: rgb(0, 122, 170);">整体方案设计为:</span></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;">先根据配置的「筛选规则」,从底池表中筛选出「目标数据」</span></p></li> <li><p><span style="font-size: 15px;">在根据配置的「排序规则」,对「目标数据」进行排序,得到「结果数据」</span></p></li> </ul> <p><br></p> <p><span style="font-size: 15px;color: rgb(0, 122, 170);">技术方案如下:</span></p> <p><br></p> <p><strong><span style="font-size: 15px;">①</span></strong><span style="font-size: 15px;">每天运行导数任务,把现有的千万量级的底池数据(Hive 表)导入到 Clickhouse 中,后续使用 CK 表进行数据筛选。</span></p> <p><br></p> <p><strong><span style="font-size: 15px;">②</span></strong><span style="font-size: 15px;">将业务配置的筛选规则和排序规则,构建为一个「筛选 + 排序」对象 SelectionQueryCondition。</span></p> <p><br></p> <p style="margin-bottom: 8px;"><strong><span style="font-size: 15px;">③</span></strong><span style="font-size: 15px;">从 CK 底池表取「目标数据」时,开启多线程,进行分页筛选,将获取到的「目标数据」存放到 result 列表中。</span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//分页大小&nbsp;&nbsp;默认&nbsp;5000</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;pageSize&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.getPageSize();<br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//页码数</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;pageCnt&nbsp;=&nbsp;totalNum&nbsp;/&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">this</span>.getPageSize()&nbsp;+&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">1</span>;<br><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&gt;&nbsp;result&nbsp;=&nbsp;Lists.newArrayList();<br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;Future&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&gt;&gt;&gt;&nbsp;futureList&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ArrayList&lt;&gt;(pageCnt);<br><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//开启多线程调用</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;i&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">1</span>;&nbsp;i&nbsp;&lt;=&nbsp;pageCnt;&nbsp;i++)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//将业务配置的筛选规则和排序规则&nbsp;构建为&nbsp;SelectionQueryCondition&nbsp;对象</span><br>&nbsp;&nbsp;&nbsp;&nbsp;SelectionQueryCondition&nbsp;selectionQueryCondition&nbsp;=&nbsp;buildSelectionQueryCondition(selectionQueryRuleData);<br>&nbsp;&nbsp;&nbsp;&nbsp;selectionQueryCondition.setPageSize(pageSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;selectionQueryCondition.setPage(i);<br>&nbsp;&nbsp;&nbsp;&nbsp;futureList.add(selectionQueryEventPool.submit(<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;QuerySelectionDataThread(selectionQueryCondition)));<br>}<br><br><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>&nbsp;(Future&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&gt;&gt;&nbsp;future&nbsp;:&nbsp;futureList)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//RPC&nbsp;调用</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&gt;&nbsp;queryRes&nbsp;=&nbsp;future.<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">get</span>(<span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">20</span>,&nbsp;TimeUnit.SECONDS);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(CollectionUtils.isNotEmpty(queryRes))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;将目标数据存放在&nbsp;result&nbsp;中</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.addAll(queryRes);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> </section> <p><br></p> <p><span style="font-size: 15px;">④对目标数据 result 进行排序,得到最终的「结果数据」。</span></p> <p><br></p> <section style="box-sizing: border-box;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-right: 0%;margin-left: 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-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">CK 分页查询</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;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><span style="font-size: 15px;">在「初版设计方案」章节的第 3 步提到了「从 CK 底池表取目标数据时,开启多线程,进行分页筛选」。此处对 CK 分页查询进行介绍。</span></p> <p><br></p> <p style="margin-bottom: 8px;"><span style="font-size: 15px;">①封装了 queryPoolSkuList 方法,负责从 CK 表中获得目标数据。该方法内部调用了 sqlSession.selectList 方法。</span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">public&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&gt;&nbsp;queryPoolSkuList(&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&nbsp;params&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&gt;&nbsp;resultMaps&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ArrayList&lt;&gt;();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;QueryCondition&nbsp;queryCondition&nbsp;=&nbsp;parseQueryCondition(params);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&gt;&nbsp;mapList&nbsp;=&nbsp;lianNuDao.queryPoolSkuList(getCkDt(),queryCondition);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;(CollectionUtils.isNotEmpty(mapList))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>&nbsp;(<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&nbsp;data&nbsp;:&nbsp;mapList)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resultMaps.add(camelKey(data));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;resultMaps;<br>}<br></code></pre> </section> <p><br></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;lianNuDao.queryPoolSkuList</span><br><br><span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;">@Autowired</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;">@Qualifier</span>(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"ckSqlNewSession"</span>)<br>private&nbsp;SqlSession&nbsp;sqlSession;<br><br>public&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Map</span>&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>,&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Object</span>&gt;&gt;&nbsp;queryPoolSkuList(&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;dt,&nbsp;QueryCondition&nbsp;queryCondition&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;queryCondition.setDt(dt);<br>&nbsp;&nbsp;&nbsp;&nbsp;queryCondition.checkMultiQueryItems();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;sqlSession.selectList(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"LianNu.queryPoolSkuList"</span>,queryCondition);<br>}<br></code></pre> </section> <p><br></p> <pre></pre> <p style="margin-bottom: 8px;"><span style="font-size: 15px;">②sqlSession.selectList 方法中调用了和 CK 交互的 queryPoolSkuList 查询方法,部分代码如下:</span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;id=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"queryPoolSkuList"</span>&nbsp;parameterType=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"com.jd.bigai.domain.liannu.QueryCondition"</span>&nbsp;resultType=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"java.util.Map"</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&nbsp;sku_pool_id,i<br>&nbsp;&nbsp;&nbsp;&nbsp;tem_sku_id,<br>&nbsp;&nbsp;&nbsp;&nbsp;skuPoolName,<br>&nbsp;&nbsp;&nbsp;&nbsp;price,<br>&nbsp;&nbsp;&nbsp;&nbsp;...<br>&nbsp;&nbsp;&nbsp;&nbsp;...<br>&nbsp;&nbsp;&nbsp;&nbsp;businessType<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">from</span>&nbsp;liannu_sku_pool_indicator_all<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">where</span><br>&nbsp;&nbsp;&nbsp;&nbsp;dt=<span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;">#{dt}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;and<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">foreach</span>&nbsp;collection=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"queryItems"</span>&nbsp;separator=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"&nbsp;and&nbsp;"</span>&nbsp;item=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"queryItem"</span>&nbsp;open=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"&nbsp;"</span>&nbsp;close=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"&nbsp;"</span>&nbsp;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;choose&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;when&nbsp;test=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"queryItem.type&nbsp;==&nbsp;'equal'"</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${queryItem.field}&nbsp;=&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;">#{queryItem.value}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/when&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/choose&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">foreach</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;test=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"orderBy&nbsp;==&nbsp;null"</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">group</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">by</span>&nbsp;sku_pool_id,item_sku_id<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;test=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"orderBy&nbsp;!=&nbsp;null"</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">group</span>&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">by</span>&nbsp;sku_pool_id,item_sku_id,${orderBy}&nbsp;order&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">by</span>&nbsp;${orderBy}&nbsp;${orderAd}<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&nbsp;test=<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"limitEnd&nbsp;!=&nbsp;0"</span>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;limit&nbsp;<span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;">#{limitStart},#{limitEnd}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>&gt;<br>&lt;/<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">select</span>&gt;<br></code></pre> </section> <p><br></p> <p><span style="font-size: 15px;">③可以看到,在 CK 分页查询时,是通过 limit #{limitStart},#{limitEnd} 实现的分页。</span></p> <p><br></p> <p><span style="font-size: 15px;">limit 分页方案,在「深翻页」时会存在性能问题。初版方案上线后,在 1000W 量级的底池数据中筛选 10W 的数据,最坏耗时会达到 10s~18s 左右。</span></p> <p><br></p> <section style="box-sizing: border-box;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-right: 0%;margin-left: 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-right: 5px;padding-left: 5px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">使用 ES Scroll Scan 优化深翻页</strong></p> </section> </section> <section style="margin-right: 0%;margin-bottom: -3px;margin-left: 0%;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>

京东一面:如何用 Nginx 禁止国外 IP 访问网站!

作者:微信小助手

<section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible;" data-mpa-powered-by="yiban.io"> <section powered-by="xiumi.us" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible;"> <section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible;"> <section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible;"> <section powered-by="xiumi.us" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible;"> <section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible;"> <p style="white-space: normal;text-align: center;visibility: visible;"><span style="color: rgb(140, 140, 140);font-size: 13px;letter-spacing: 0.12px;visibility: visible;">学最好的别人,做最好的自己</span></p> <p style="white-space: normal;text-align: center;visibility: visible;"><span style="color: rgb(140, 140, 140);font-size: 13px;letter-spacing: 0.12px;visibility: visible;">点击关注<strong style="visibility: visible;">后端面试那些事</strong>,</span><span style="font-size: 13px;letter-spacing: 0.12px;color: rgb(2, 30, 170);visibility: visible;">Java面经</span><span style="font-size: 13px;letter-spacing: 0.12px;color: rgb(255, 76, 65);visibility: visible;">都在这里<img class="rich_pages wxw-img" data-ratio="1" src="/upload/29316807de8eec165a101cfe6173a39c.png" data-type="png" data-w="64" style="visibility: visible !important;overflow-wrap: break-word !important;max-height: 20px !important;width: 20px !important;height: auto !important;"></span></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzI5MzYzMDAwNw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/hkZHkS4iaqMX6EXG4ibJXmMls0Zy2MkWb3ehWbRHaQqgwcLrA1EEFAtakqOsfJKibJ78znEoqyAd0Hcv6lKl8fFLQ/0?wx_fmt=png" data-nickname="程序员乔戈里" data-alias="CXYqiaogeli" data-signature="乔戈里是BAT大厂后端工程师,专注于 Java 技术,包括 Spring 全家桶,MySQL,JavaWeb,Git,Linux,Nginx,IDEA,高并发,多线程,面试题,GitHub项目精选等相关内容,欢迎 Java 程序员关注。" data-from="0"></mpprofile> </section> <p style="white-space: normal;text-align: left;visibility: visible;"><span style="font-size: 13px;letter-spacing: 0.12px;color: rgb(255, 76, 65);visibility: visible;"></span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 10px;font-family: arial, helvetica, sans-serif;color: rgb(136, 136, 136);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">来源:toutiao.com/i6860736292339057156/</span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">之前看了下 Nginx 的访问日志,发现每天有好多国外的 IP 地址来访问我的网站,并且访问的内容基本上都是恶意的。因此我决定禁止国外 IP 来访问我的网站。</span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">想要实现这个功能有很多方法,下面我就来介绍基于 Nginx 的 ngx_http_geoip2 模块来禁止国外 IP 访问网站。</span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"># 安装 geoip2 扩展依赖</span></strong><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &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);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <section class="code-snippet__fix code-snippet__js" style="visibility: visible;"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">[<span class="code-snippet__meta" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">root@fxkj ~</span>]<span class="code-snippet__meta" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"># yum install libmaxminddb-devel -y</span></span></code></pre> </section> </section> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"># 下载 ngx_http_geoip2_module 模块</span></strong><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <section class="code-snippet__fix code-snippet__js"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">[<span class="code-snippet__meta" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">root@fxkj tmp</span>]<span class="code-snippet__meta" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"># git clone https://github.com/leev/ngx_http_geoip2_module.git</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> [<span class="code-snippet__meta" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">ro tmp</span>]<span class="code-snippet__meta" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">#</span></span></code></pre> </section> </section> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">解压模块到指定路径</span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">我这里解压到 /usr/local 目录下:</span></p> <section class="code-snippet__fix code-snippet__js"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">[root@fxkj&nbsp;tmp]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">#&nbsp;mv&nbsp;ngx_http_geoip2_module/&nbsp;/usr/local/</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> [root@fxkj local]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"># ll ngx_http_geoip2_module/</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> total 60</span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> -rw-r<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">--r-- 1 root root 1199 Aug 13 17:20 config</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> -rw-r<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">--r-- 1 root root 1311 Aug 13 17:20 LICENSE</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> -rw-r<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">--r-- 1 root root 23525 Aug 13 17:20 ngx_http_geoip2_module.c</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> -rw-r<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">--r-- 1 root root 21029 Aug 13 17:20 ngx_stream_geoip2_module.c</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> -rw-r<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">--r-- 1 root root 3640 Aug 13 17:20 README.md</span></span></code></pre> </section> </section> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &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);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"># 安装 nginx 模块</span></strong><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">首先说明下环境,我的 nginx 版本是 1.16,在网上查了下安装 ngx_http_geoip2 模块至少需要 1.18 版本及以上,因此此次安装我是升级 nginx1.18,添加 ngx_http_geoip2 模块。</span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">下载 nginx 1.18 版本:</span></p> <section class="code-snippet__fix code-snippet__js"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">[<span class="code-snippet__meta" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">root@fxkj&nbsp;~</span>]<span class="code-snippet__meta" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#&nbsp;yum&nbsp;install&nbsp;libmaxminddb-devel&nbsp;-y</span></span></code></pre> </section> </section> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">解压 nginx1.18 软件包,并升级为 nginx1.18,添加 ngx_http_geoip2 模块。</span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">需要注意:</span></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <ul class="list-paddingleft-1" style="padding-left: 1.5em;outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &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);overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="outline: 0px;max-width: 100%;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">升级 nginx,添加 nginx 模块,只需要编译,然后 make。不需要 make instll,不然线上的 nginx 会被新版本 nginx 完完整整的替换掉。</span></p></li> <li style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="outline: 0px;max-width: 100%;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">编译前需要看下 nginx 当前安装了哪些模块。</span></p></li> </ul> <section class="code-snippet__fix code-snippet__js"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">[root@fxkj&nbsp;tmp]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#&nbsp;/usr/local/nginx/sbin/nginx&nbsp;-V</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> nginx version: nginx/1.16.0</span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)</span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> built <span class="code-snippet__keyword" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">with</span> OpenSSL <span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1.0</span><span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.2</span>k-fips <span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">26</span> Jan <span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2017</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> TLS SNI support enabled</span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> configure arguments: –<span class="code-snippet__keyword" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">with</span>-http_stub_status_module –prefix=/usr/<span class="code-snippet__keyword" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">local</span>/nginx –<span class="code-snippet__keyword" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">user</span>=nginx –<span class="code-snippet__keyword" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">group</span>=nginx –<span class="code-snippet__keyword" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">with</span>-http_ssl_module –<span class="code-snippet__keyword" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">with</span>-stream</span></code></pre> </section> </section> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 16px;font-family: arial, helvetica, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">编译安装:</span></p> <section class="code-snippet__fix code-snippet__js"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="ruby"><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">[root@fxkj&nbsp;tmp]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#&nbsp;tar&nbsp;-xf&nbsp;nginx-1.18.0.tar.gz</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> [root@fxkj tmp]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"># cd nginx-1.18.0/</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> [root@fxkj nginx-<span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1.18</span>.<span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">0</span>]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"># ./configure --with-http_stub_status_module \</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> --prefix=<span class="code-snippet__regexp" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">/usr/local</span><span class="code-snippet__regexp" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">/nginx \</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> --user=nginx --group=nginx --with-http_ssl_module --with-stream \</span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> --add-module=/usr</span><span class="code-snippet__regexp" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">/local/ngx</span>_http_geoip2_module</span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> [root@fxkj nginx-<span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1.18</span>.<span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">0</span>]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"># make</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> [root@fxkj nginx-<span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1.18</span>.<span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">0</span>]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"># cp /usr/loca/nginx/sbin/nginx /usr/loca/nginx/sbin/nginx1.16 #备份</span></span></code><code style="white-space:pre-wrap;outline: 0px;max-width: 1000%;text-align: left;display: flex;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span class="code-snippet_outer" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> [root@fxkj nginx-<span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1.18</span>.<span class="code-snippet__number" style="outline: 0px;max-width: 1000%;box-sizing: border-box !important;overflow-wrap: break-word !important;">0</span>]<span class="code-snippet__comment" style="outline: 0px;max-width: 1000%;box-sizing: border-box !impo

从单点 Redis 到 1 主 2 从 3 哨兵的架构演进之路

作者:微信小助手

<p style="text-align: center;margin-bottom: 0em;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.4255555555555556" data-s="300,640" src="/upload/c5abb6ec45a0e1cab0562880f1e418a4.jpg" data-type="jpeg" data-w="900" style=""></p> <p data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-style="margin-top: 10px; margin-bottom: 10px; 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; white-space: normal; word-spacing: 0.8px; letter-spacing: 0.75px; text-align: center; visibility: visible;" class="js_darkmode__1" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="margin-top: 10px;margin-bottom: 10px;white-space: normal;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;background-color: rgb(255, 255, 255);font-size: 16px;word-spacing: 0.8px;text-align: right;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;font-size: 14px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(0, 0, 0);">这是悟空的第&nbsp;</span><span style="color: rgb(255, 104, 39);">150</span></span><span data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="color: rgb(0, 0, 0);max-width: 100%;font-size: 14px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;篇原创文章</span><br data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p data-tool="mdnice编辑器" data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-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; white-space: normal; word-spacing: 0.8px; letter-spacing: 0.75px; text-align: center; visibility: visible;" class="js_darkmode__2" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="margin-top: 10px;margin-bottom: 10px;white-space: normal;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;background-color: rgb(255, 255, 255);font-size: 16px;word-spacing: 0.8px;text-align: right;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;font-size: 14px;visibility: visible;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">官网:www.passjava.cn</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;word-wrap: break-word;text-align: left;padding: 0px;font-size: 15px;color: #353535;word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzAwMjI0ODk0NA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/SfAHMuUxqJ2JicQpKzblLHz64qoibVa3ATNA4rH8mIYXAF3OErAzxFKHzf5qiaiblb4rAMuAXXMJHEcKcvaHv4ia9rA/0?wx_fmt=png" data-nickname="悟空聊架构" data-alias="PassJava666" data-signature="用故事讲解分布式、架构。 《 JVM 性能调优实战》专栏作者, 《Spring Cloud 实战 PassJava》开源作者, 自主开发了 PMP 刷题小程序。" data-from="0"></mpprofile> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">你好,我是悟空呀~</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">本文目录如下:</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;color: #f83929;font-size: 16px;" class="list-paddingleft-1"> <li><p>一、前言</p></li> <li><p>二、部署拓扑图</p></li> <li><p>三、搭建 Redis 一主两从</p></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><p>1.1 备份和还原 Redis 镜像</p></li> <li><p>1.2 主节点配置</p></li> <li><p>1.3 从节点配置</p></li> <li><p>1.4 启动容器</p></li> <li><p>1.5 查看 Redis 状态</p></li> <li><p>1.6 测试主从复制</p></li> </ul> <li><p>四、搭建哨兵集群</p></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><p>4.1 哨兵集群拓扑图</p></li> <li><p>4.2 哨兵服务是怎么启动的</p></li> <li><p>4.3 哨兵配置</p></li> <li><p>4.4 启动哨兵容器</p></li> </ul> <li><p>五、客户端自动感知故障</p></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><p>如何实现自动感知故障</p></li> <li><p>客户端自动感知的原理</p></li> </ul> <li><p>六、遇到的问题</p></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><p>6.1 提示不能写只读的 redis 节点</p></li> <li><p>6.2 提示连接 Redis 失败</p></li> </ul> <li><p>七、总结</p></li> </ul> <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);">一、前言</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">我们有个项目中用的 MySQL、Redis、ES、微服务都是单节点部署的,没有做集群模式部署,为了提高整体的可用性,对项目的部署架构进行了升级,支持高可用。相关内容可参考之前的两篇:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="https://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451963004&amp;idx=1&amp;sn=2667d0e6e9142939e3645de680a4533f&amp;chksm=8d1c05e3ba6b8cf5a6a0ab2ecb66af10496838e25814cbefcd45907dd652a5ec6ef3917b6ada&amp;token=94995646&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">MySQL 高可用篇</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="https://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451963107&amp;idx=1&amp;sn=22df0b863365b5a0e1b5eab2bf5ce5a6&amp;chksm=8d1c057cba6b8c6a8783282a470ae1c67262a5b6983ca38f4c17420a0eab728fe364d2a1557e&amp;token=94995646&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">ELK Stack 篇</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">通过本篇,你可以学到以下内容:</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;"> Redis <strong style="font-weight: 700;color: rgb(248, 57, 41);">真实的多服务器</strong>部署实战 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Redis <strong style="font-weight: 700;color: rgb(248, 57, 41);">真实的主从模式</strong>部署实战。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Redis <strong style="font-weight: 700;color: rgb(248, 57, 41);">真实的哨兵集群模式</strong>部署实战。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Redis 主节点宕机后,Redis 哨兵如何进行 <strong style="font-weight: 700;color: rgb(248, 57, 41);">故障转移</strong>的。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> Redis 切换主节点后,客户端如何 <strong style="font-weight: 700;color: rgb(248, 57, 41);">自动感知</strong>并连接新的主节点。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">缓存实战的文章写了很多篇,把历史文章汇总下,方便大家查看:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451954442&amp;idx=1&amp;sn=e5ec784a11fcbad89eb2e4c7a809378d&amp;chksm=8d1c2295ba6bab833b77318661d4aeb4533234f03d4b9e5a298e84b8041258569af4301a21c3&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">《缓存实战(一)缓存初级打怪》</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451954663&amp;idx=1&amp;sn=4bd071b6aaede114263f88c790b61371&amp;chksm=8d1c2278ba6bab6eca2ef44f21b2178cc719fffe124289b68128c0dad72429fe5f286854157a&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">《缓存实战(二)Redis分布式锁》</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451955246&amp;idx=1&amp;sn=5db231b88fb9e735e907873d420f26a5&amp;chksm=8d1c27b1ba6baea7d3ef65860276140ae30a4e2bbe45179931c3f476f1fcb30d8365905dd413&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">《缓存实战(三)Redisson 分布式锁》</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451955726&amp;idx=1&amp;sn=009fc5b48e070422303d68bb905f4ade&amp;chksm=8d1c1991ba6b9087abe3ba30e115da0561c32627066cec58945127a16b4b9a9bdcbe1592c601&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">《缓存实战(四)实战 Spring Cach</a><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451955726&amp;idx=1&amp;sn=009fc5b48e070422303d68bb905f4ade&amp;chksm=8d1c1991ba6b9087abe3ba30e115da0561c32627066cec58945127a16b4b9a9bdcbe1592c601&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">e</a>》</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451957279&amp;idx=1&amp;sn=a19fce7a170d51b1261bae1cff8af773&amp;chksm=8d1c1f80ba6b9696fca551356555ae291c129cba2cdeefdb62567ae600fdab1d737396c4a6c8&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">《</a><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451955726&amp;idx=1&amp;sn=009fc5b48e070422303d68bb905f4ade&amp;chksm=8d1c1991ba6b9087abe3ba30e115da0561c32627066cec58945127a16b4b9a9bdcbe1592c601&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">缓存实战(五)</a><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451957279&amp;idx=1&amp;sn=a19fce7a170d51b1261bae1cff8af773&amp;chksm=8d1c1f80ba6b9696fca551356555ae291c129cba2cdeefdb62567ae600fdab1d737396c4a6c8&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">Redis 开发手册 | 花果山版</a>》</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451957797&amp;idx=1&amp;sn=2608a3dccce3f606b288eb2956b2e0ec&amp;chksm=8d1c11baba6b98ac81bb58809b755f2cfca9143ef4758f178a9fa4bc5feb5e4d95ef8fb645a0&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">《缓存实战(六)详解 Redis 冷备》</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451958462&amp;idx=1&amp;sn=5380b7967443f88ef180ccd9db11fcc2&amp;chksm=8d1c1321ba6b9a374ceeb993775d57800c4f98c3b5d4a85c3d3bc5eab649a2b0ca96c3db6c12&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">《缓存实战(七)镜 | 深入剖析主从架构原理》</a></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><a href="https://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451958511&amp;idx=1&amp;sn=31edcb2b143286f065e939ac3118dc78&amp;chksm=8d1c1370ba6b9a669cedd213fafdfc9b581029a4a35510cac047b67c297f89bbdcd0b4a1c2a0&amp;scene=21&amp;cur_album_id=1835581086177755145#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">《缓存实战(八)「手摸手」主从环境的部署+压测》</a></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);">二、部署拓扑图</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">我们项目的测试环境 12 台服务器已经部署好了,其中三台用来部署 Redis 的 一主 + 两从 + 三哨兵的服务器。服务器资源清单如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><img class="rich_pages wxw-img" data-ratio="0.5823529411764706" src="/upload/642ff932a4c2933cf714daa25124708b.png" data-type="png" data-w="340" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"><span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.8px;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0.8px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">另外 Redis 的端口都是 6379,</span><span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.8px;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0.8px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">Sentinel(哨兵) 的</span><span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.8px;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0.8px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">端口都是&nbsp;</span><span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.8px;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0.8px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">26379</span><span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.8px;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0.8px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">部署的拓扑图如下,三台服务器上都部署了一个哨兵。<img class="rich_pages wxw-img" data-ratio="1.399004975124378" src="/upload/aae472ef5587afce16d51fa1a2766c22.png" data-type="png" data-w="1005" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"></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);">三、搭建 Redis 一主两从</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">我们原来的单点的服务器上是有运行的 Redis 容器的,把这个容器的镜像打包备份下,然后拷贝和还原到新的服务器上就好了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">搭建 Redis 一主两从的步骤如下:</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;"> 拷贝和还原 Redis 镜像到三台服务器上。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 其中一台服务器作为主节点,配置文件为主节点的,用 docker 启动 Redis 主节点。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> 另外两台服务器作为从节点,配置文件为从节点的,用 docker 启动两个 Redis 从节点。 </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;">1.1 备份和还原 Redis 镜像</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">打包测试环境的 Redis 镜像,这个命令会将服务器上 redis 镜像打包成 tar 包,这样我们就方便拷贝到其他服务器上了。执行打包镜像命令:</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/ibKHP1TZZeXLuuibODqFs5MiaUIib2BoVmW8cic806jF6uTMlP4eMXMHvwD2ms3A4zI5gZQBgvHqW6PdCKjhWgia9vcYDUP7QiasECO/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">sudo&nbsp;docker&nbsp;save&nbsp;-o&nbsp;redis.tar&nbsp;redis:0.1<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">因为保存的 tar 包权限不够,所以设置下权限为 777。执行修改权限的命令:</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/ibKHP1TZZeXLuuibODqFs5MiaUIib2BoVmW8cic806jF6uTMlP4eMXMHvwD2ms3A4zI5gZQBgvHqW6PdCKjhWgia9vcYDUP7QiasECO/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">sudo&nbsp;chmod&nbsp;777&nbsp;redis.tar<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">将这个 tar 包拷贝新环境的三台服务器上。执行导入镜像的命令:</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/ibKHP1TZZeXLuuibODqFs5MiaUIib2BoVmW8cic806jF6uTMlP4eMXMHvwD2ms3A4zI5gZQBgvHqW6PdCKjhWgia9vcYDUP7QiasECO/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">sudo&nbsp;docker&nbsp;load&nbsp;-i&nbsp;redis.tar<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">添加配置文件 redis.conf 放在本地,作为 redis 容器的配置文件。这个文件也可以在 redis 官网下载 https://redis.io/。redis.conf 文件放到 /home/redis 目录下。</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/ibKHP1TZZeXLuuibODqFs5MiaUIib2BoVmW8cic806jF6uTMlP4eMXMHvwD2ms3A4zI5gZQBgvHqW6PdCKjhWgia9vcYDUP7QiasECO/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">sudo&nbsp;mkdir&nbsp;/home/redis<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;">1.2 主节点配置</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">修改本地的 redis.conf 文件:</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/ibKHP1TZZeXLuuibODqFs5MiaUIib2BoVmW8cic806jF6uTMlP4eMXMHvwD2ms3A4zI5gZQBgvHqW6PdCKjhWgia9vcYDUP7QiasECO/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">requirepass&nbsp;abc123<br>masterauth&nbsp;abc123<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><strong style="font-weight: 700;color: rgb(248, 57, 41);">requirepass</strong> 和 <strong style="font-weight: 700;color: rgb(248, 57, 41);">masterauth</strong>:对于数据比较重要的节点,主节点会通过设置requirepass参数进行密码 验证,这时所有的客户端访问必须使用auth命令实行校验。从节点与主节点 的复制连接是通过一个特殊标识的客户端来完成,因此需要配置从节点的 masterauth参数与主节点密码保持一致,这样从节点才可以正确地连接到主 节点并发起复制流程。</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;">1.3 从节点配置</span><span style="display: none;"></span></h3> <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/ibKHP1TZZeXLuuibODqFs5MiaUIib2BoVmW8cic806jF6uTMlP4eMXMHvwD2ms3A4zI5gZQBgvHqW6PdCKjhWgia9vcYDUP7QiasECO/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">slave-read-only&nbsp;yes<br>requirepass&nbsp;abc123<br>masterauth&nbsp;abc123<br>slaveof&nbsp;10.2.1.61&nbsp;6379<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;">1.4 启动容器</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;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/ibKHP1TZZeXLuuibODqFs5MiaUIib2BoVmW8cic806jF6uTMlP4eMXMHvwD2ms3A4zI5gZQBgvHqW6PdCKjhWgia9vcYDUP7QiasECO/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">sudo&nbsp;docker&nbsp;run&nbsp;-p&nbsp;6379:6379&nbsp;--restart=always&nbsp;--name&nbsp;redis&nbsp;\<br>-v&nbsp;/home/redis/redis.conf:/usr/<span style="color: #e6c07b;line-height: 26px;">local</span>/etc/redis/redis.conf&nbsp;\<br>-v&nbsp;/home/redisdata:/data/&nbsp;\<br>-d&nbsp;301<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">-v 代表映射的文件或文件夹,这里映射了 redis.conf 文件和 data 目录。data 目录会存放 Redis 的 <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);">AOF</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);">RDB</code> 持久化文件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">-d 表示后台运行,46b 代表镜像 id。因为我们服务器是没有外网的,所以用的是本地镜像启动的,如果你的服务器有外网,完全可以用官网的 redis 镜像启动。</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;">1.5 查看 Redis 状态</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">进入容器,连接 redis,node1的 redis 密码是 abc123</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/ibKHP1TZZeXLuuibO

Mybatis-Plus官方发布分库分表神器,一个依赖轻松搞定!

作者:微信小助手

<p style="margin: 0px 0px 8px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;line-height: 27.2px;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: normal;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration: none;outline: 0px;caret-color: rgb(34, 34, 34);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;text-size-adjust: auto;text-align: center;visibility: visible;overflow-wrap: break-word !important;box-sizing: border-box !important;" data-mpa-powered-by="yiban.io"><img class="rich_pages wxw-img" data-backh="326" data-backw="578" data-ratio="0.5633333333333334" src="/upload/87e6fa88778520e861a693fc93eaeece.jpg" data-type="jpeg" data-w="1200" style="width: 100%;height: auto;"></p> <section powered-by="xiumi.us" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 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: none;outline: 0px;caret-color: rgb(34, 34, 34);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;text-size-adjust: auto;visibility: visible;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section powered-by="xiumi.us" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;letter-spacing: 0.544px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section powered-by="xiumi.us" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;letter-spacing: 0.612px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section powered-by="xiumi.us" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section powered-by="xiumi.us" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section powered-by="xiumi.us" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section powered-by="xiumi.us" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section powered-by="xiumi.us" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px 0em;padding: 0.5em 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;border-style: none;background-color: rgb(235, 235, 235);visibility: visible;font-size: 17px;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="25.5" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;text-align: left;line-height: 25.5px;visibility: visible;font-size: 17px;"> <span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(136, 136, 136);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: 14px;letter-spacing: 0.612px;text-align: justify;">导读:</span> <span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(136, 136, 136);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: 14px;letter-spacing: 0.612px;text-align: justify;">今天介绍一个 MyBatis - Plus 官方发布的神器:mybatis-mate 为 mp 企业级模块,支持分库分表,数据审计、数据敏感词过滤(AC算法),字段加密,字典回写(数据绑定),数据权限,表结构自动生成 SQL 维护等,旨在更敏捷优雅处理数据。</span> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;line-height: 26.1px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: normal;orphans: 2;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;caret-color: rgba(0, 0, 0, 0);text-decoration: none;outline: none 0px;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;text-align: left;text-size-adjust: auto;font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;visibility: visible;"><br></p> <section data-role="paragraph" data-color="#ef7060" data-id="86516" data-tools="135编辑器" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(34, 34, 34);font-family: -apple-system, &quot;system-ui&quot;, &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-align: justify;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;caret-color: rgb(34, 34, 34);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;outline: 0px;visibility: visible;line-height: 27.2px;"> <section data-tools="135编辑器" data-id="86516" data-color="#ef7060" mp-original-font-size="17" mp-original-line-height="27.200000762939453" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 17px;line-height: 27.2px;"> <section mp-original-font-size="17" mp-original-line-height="29.75" style="margin: 0px auto 0.5em;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;border-bottom: 1px solid rgb(221, 221, 221);visibility: visible;line-height: 29.75px;font-size: 17px;"> <section mp-original-font-size="18" mp-original-line-height="19.799999237060547" style="margin: 0.5em 0px -1px;padding: 0px 5px 6px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;border-bottom: 2px solid rgb(255, 128, 0);display: inline-block;line-height: 19.8px;font-size: 18px;visibility: visible;"> <strong mp-original-font-size="18" mp-original-line-height="19.799999237060547" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;font-size: 18px;line-height: 19.8px;"><span mp-original-font-size="18" mp-original-line-height="19.799999237060547" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;letter-spacing: 1px;font-size: 18px;line-height: 19.8px;">主要功能</span></strong> </section> <span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-indent: 0em;text-align: left;"></span> </section> </section> </section> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <li style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p></li> <li style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p></li> <li style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p></li> <li style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p></li> <li style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p></li> <li style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p></li> <li style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p></li> </ul> <p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p> <section data-role="paragraph" data-color="#ef7060" data-id="86516" data-tools="135编辑器" style="margin: 0px;padding: 0px;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, &quot;system-ui&quot;, &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-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"> <section data-tools="135编辑器" data-id="86516" data-color="#ef7060" style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;"> <section style="margin: 0px auto 0.5em;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;border-bottom: 1px solid rgb(221, 221, 221);visibility: visible;line-height: 1.75em;"> <section style="margin: 0.5em 0px -1px;padding: 0px 5px 6px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;border-bottom: 2px solid rgb(255, 128, 0);display: inline-block;line-height: 1.1;font-size: 18px;visibility: visible;"> <strong style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;letter-spacing: 1px;">使用</span></strong> <span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;letter-spacing: 1px;"></span> </section> </section> </section> </section> <p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;line-height: 1.6em;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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;">由于前几天定位一个问题的时候发现Spring Boot 在v2.7.0版本之后才修复的问题</span><br style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"></p> <h4 data-lake-id="ca6fa186228ff7efaa653334195896c8" data-wording="true" style="margin: 16px 0px 8px;padding: 0px;font-weight: 400;font-size: 16px;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, &quot;system-ui&quot;, &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;letter-spacing: normal;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;text-align: left;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;color: rgb(255, 104, 39);visibility: visible;letter-spacing: 1px;"><strong style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;font-family: Optima-Regular, PingFangTC-light;visibility: visible;">▐</span></strong><strong style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;font-family: Optima-Regular, PingFangTC-light;visibility: visible;">&nbsp; 导入依赖</span></strong></span></h4> <p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;line-height: 1.6em;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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;">Spring Boot 引入自动依赖注解包</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding: 0 10px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"> <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/0T8yO33zeegPBqRhTxbOR3iaAqB7RrLKic4dGfJcrDvkW31czsDteicDbghSfPqicMF6wjZBngSCryxjqOF4XNxOe4RgbVOMCHgia/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">&lt;dependency&gt;<br>&nbsp;&nbsp;&lt;groupId&gt;com.baomidou&lt;/groupId&gt;<br>&nbsp;&nbsp;&lt;artifactId&gt;mybatis-mate-starter&lt;/artifactId&gt;<br>&nbsp;&nbsp;&lt;version&gt;<span style="color: #d19a66;line-height: 26px;">1.0</span><span style="color: #d19a66;line-height: 26px;">.8</span>&lt;/version&gt;<br>&lt;/dependency&gt;<br></code></pre> </section> <p style="margin: 16px 0px 0px;padding: 0px;clear: both;min-height: 1em;max-width: 100%;line-height: 1.6em;color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, &quot;system-ui&quot;, &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-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;text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 15px;letter-spacing: 1px;text-indent: 0em;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></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding: 0 10px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"> <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/0T8yO33zeegPBqRhTxbOR3iaAqB7RrLKic4dGfJcrDvkW31czsDteicDbghSfPqicMF6wjZBngSCryxjqOF4XNxOe4RgbVOMCHgia/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">&lt;dependency&gt;<br>&nbsp;&nbsp;&lt;groupId&gt;com.baomidou&lt;/groupId&gt;<br>&nbsp;&nbsp;&lt;artifactId&gt;mybatis-mate-annotation&lt;/artifactId&gt;<br>&nbsp;&nbsp;&lt;version&gt;<span style="color: #d19a66;line-height: 26px;">1.0</span><span style="color: #d19a66;line-height: 26px;">.8</span>&lt;/version&gt;<br>&lt;/dependency&gt;<br></code></pre> </section> <h4 data-lake-id="ca6fa186228ff7efaa653334195896c8" data-wording="true" style="margin: 16px 0px 8px;padding: 0px;font-weight: 400;font-size: 16px;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, &quot;system-ui&quot;, &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;letter-spacing: normal;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;text-align: left;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;color: rgb(255, 104, 39);visibility: visible;letter-spacing: 1px;"><strong style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;visibility: visible;"><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;outline: 0px;font-family: Optima-Regular, PingFangTC-light;visibility: visible;"></span></strong></span></h4> <h4 da

详解分布式系统的缓存设计

作者:微信小助手

<section style="font-size: 15px;line-height: 1.9;letter-spacing: 0.75px;box-sizing: border-box;" data-mpa-powered-by="yiban.io"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="25" data-source-title="" data-text="作者:vivo互联网服务器团队-Zhang Peng" data-editid="i96t8lqfx7clgxughs"> <section class="js_blockquote_digest"> <section> 作者:vivo互联网服务器团队-Zhang Peng </section> </section> </blockquote> <p><br></p>​ </section> <section style="margin-top: 10px;margin-bottom: 10px;text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding: 3px;display: inline-block;border-bottom: 1px solid rgb(65, 94, 255);font-size: 17px;color: rgb(65, 94, 255);box-sizing: border-box;"> <p style="box-sizing: border-box;">一、缓存简介</p> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">1.1 什么是缓存</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">缓存就是数据交换的缓冲区。缓存的本质是一个内存 Hash。缓存是一种利用空间换时间的设计,其目标就是更快、更近:极大的提高。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">将数据写入/读取速度更快的存储(设备);</p></li> <li><p style="white-space: normal;box-sizing: border-box;">将数据缓存到离应用最近的位置;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">将数据缓存到离用户最近的位置。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">缓存是用于存储数据的硬件或软件的组成部分,以使得后续更快访问相应的数据。缓存中的数据可能是提前计算好的结果、数据的副本等。典型的应用场景:有 cpu cache, 磁盘 cache 等。本文中提及到缓存主要是指互联网应用中所使用的缓存组件。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">缓存命中率是缓存的重要度量指标,命中率越高越好。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="24" data-source-title="" data-text="缓存命中率 = 从缓存中读取次数 / 总读取次数" data-editid="39doa6w6levseih5hc"> <section class="js_blockquote_digest"> <section> 缓存命中率 = 从缓存中读取次数 / 总读取次数 </section> </section> </blockquote> <p><br></p>​ </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">1.2 何时需要缓存</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">引入缓存,会增加系统的复杂度。所以,引入缓存前,需要先权衡是否值得,考量点如下:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">CPU 开销</strong> - 如果应用某个计算需要消耗大量 CPU,可以考虑缓存其计算结果。典型场景:复杂的、频繁调用的正则计算;分布式计算中间状态等。</p></li> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">IO 开销</strong> - 如果数据库连接池比较繁忙,可以考虑缓存其查询结果。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">在数据层引入缓存,有以下几个好处:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">提升数据读取速度。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">提升系统扩展能力,通过扩展缓存,提升系统承载能力。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">降低存储成本,Cache+DB 的方式可以承担原有需要多台 DB 才能承担的请求量,节省机器成本。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">1.3 缓存的基本原理</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">根据业务场景,通常缓存有以下几种使用方式:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">懒汉式(读时触发):先查询 DB 里的数据, 然后把相关的数据写入 Cache。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">饥饿式(写时触发):写入 DB 后, 然后把相关的数据也写入 Cache。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">定期刷新:适合周期性的跑数据的任务,或者列表型的数据,而且不要求绝对实时性。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">1.4 缓存淘汰策略</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">缓存淘汰的类型:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong>1)基于空间</strong>:设置缓存空间大小。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>2)基于容量</strong>:设置缓存存储记录数。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>3)基于时间</strong></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">TTL(Time To Live,即存活期)缓存数据从创建到过期的时间。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">TTI(Time To Idle,即空闲期)缓存数据多久没被访问的时间。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">缓存淘汰算法:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">1)FIFO:先进先出</strong>。在这种淘汰算法中,先进入缓存的会先被淘汰。这种可谓是最简单的了,但是会导致我们命中率很低。试想一下我们如果有个访问频率很高的数据是所有数据第一个访问的,而那些不是很高的是后面再访问的,那这样就会把我们的首个数据但是他的访问频率很高给挤出。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">2)LRU:最近最少使用算法</strong>。在这种算法中避免了上面的问题,每次访问数据都会将其放在我们的队尾,如果需要淘汰数据,就只需要淘汰队首即可。但是这个依然有个问题,如果有个数据在 1 个小时的前 59 分钟访问了 1 万次(可见这是个热点数据),再后一分钟没有访问这个数据,但是有其他的数据访问,就导致了我们这个热点数据被淘汰。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">3)LFU:最近最少频率使用</strong>。在这种算法中又对上面进行了优化,利用额外的空间记录每个数据的使用频率,然后选出频率最低进行淘汰。这样就避免了 LRU 不能处理时间段的问题。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">这三种缓存淘汰算法,实现复杂度一个比一个高,同样的命中率也是一个比一个好。而我们一般来说选择的方案居中即可,即实现成本不是太高,而命中率也还行的 LRU。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="margin-top: 10px;margin-bottom: 10px;text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding: 3px;display: inline-block;border-bottom: 1px solid rgb(65, 94, 255);font-size: 17px;color: rgb(65, 94, 255);box-sizing: border-box;"> <p style="box-sizing: border-box;">二、缓存的分类</p> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">缓存从部署角度,可以分为客户端缓存和服务端缓存。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">客户端缓存</strong></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">HTTP 缓存</p></li> <li><p style="white-space: normal;box-sizing: border-box;">浏览器缓存</p></li> <li><p style="white-space: normal;box-sizing: border-box;">APP 缓存(1、<span style="box-sizing: border-box;">Android&nbsp; 2、</span><span style="box-sizing: border-box;">IOS)</span></p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">服务端缓存</strong></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">CDN 缓存:存放 HTML、CSS、JS 等静态资源。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">反向代理缓存:动静分离,只缓存用户请求的静态资源。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">数据库缓存:数据库(如 MySQL)自身一般也有缓存,但因为命中率和更新频率问题,不推荐使用。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">进程内缓存:缓存应用字典等常用数据。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">分布式缓存:缓存数据库中的热点数据。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">其中,CDN 缓存、反向代理缓存、数据库缓存一般由专职人员维护(运维、DBA)。<span style="box-sizing: border-box;">后端开发一般聚焦于进程内缓存、分布式缓存。</span></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">2.1 HTTP 缓存</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">2.2 CDN 缓存</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">CDN 将数据缓存到离用户物理距离最近的服务器,使得用户可以就近获取请求内容。CDN 一般缓存静态资源文件(页面,脚本,图片,视频,文件等)。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">国内网络异常复杂,跨运营商的网络访问会很慢。为了解决跨运营商或各地用户访问问题,可以在重要的城市,部署 CDN 应用。使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-backh="321" data-backw="578" data-ratio="0.555" data-s="300,640" data-type="png" data-w="1000" style="width: 100%;height: auto !important;" src="/upload/247e743d029289a30b219cd4a3a82e46.png"></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> <p style="white-space: normal;box-sizing: border-box;text-align: center;"><span style="font-size: 14px;">图片引用自:</span><span style="font-size: 14px;">Why use a CDN</span><br></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">2.1.1 CDN 原理</strong></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">CDN 的基本原理是广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">1)未部署 CDN 应用前的网络路径:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">请求</strong>:本机网络(局域网)=&gt; 运营商网络 =&gt; 应用服务器机房</p></li> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">响应</strong>:应用服务器机房 =&gt; 运营商网络 =&gt; 本机网络(局域网)</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">在不考虑复杂网络的情况下,从请求到响应需要经过 3 个节点,6 个步骤完成一次用户访问操作。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">2)部署 CDN 应用后网络路径:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">请求</strong>:本机网络(局域网) =&gt; 运营商网络</p></li> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">响应</strong>:运营商网络 =&gt; 本机网络(局域网)</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br></p> <p style="white-space: normal;box-sizing: border-box;">在不考虑复杂网络的情况下,从请求到响应需要经过 2 个节点,2 个步骤完成一次用户访问操作。与不部署 CDN 服务相比,减少了 1 个节点,4 个步骤的访问。极大的提高了系统的响应速度。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">2.1.2 CDN 特点</strong></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">优点</strong></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">本地 Cache 加速</strong>:提升访问速度,尤其含有大量图片和静态页面站点;</p></li> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">实现跨运营商的网络加速</strong>:消除了不同运营商之间互联的瓶颈造成的影响,实现了跨运营商的网络加速,保证不同网络中的用户都能得到良好的访问质量;</p></li> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">远程加速</strong>:远程访问用户根据 DNS 负载均衡技术智能自动选择 Cache 服务器,选择最快的 Cache 服务器,加快远程访问的速度;</p></li> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">带宽优化</strong>:自动生成服务器的远程 Mirror(镜像)cache 服务器,远程用户访问时从 cache 服务器上读取数据,减少远程访问的带宽、分担网络流量、减轻原站点 WEB 服务器负载等功能。</p></li> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">集群抗攻击</strong>:广泛分布的 CDN 节点加上节点之间的智能冗余机制,可以有效地预防黑客入侵以及降低各种 D.D.o.S 攻击对网站的影响,同时保证较好的服务质量。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">缺点</strong></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">不适宜缓存动态资源</strong></p></li> </ul> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="31" data-source-title="" data-text="解决方案:主要缓存静态资源,动态资源建立多级缓存或准实时同步;" data-editid="g83cdwz26gr602zzeo"> <section class="js_blockquote_digest"> <section> 解决方案:主要缓存静态资源,动态资源建立多级缓存或准实时同步; </section> </section> </blockquote> <p><br></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">存在数据的一致性问题</strong></p></li> </ul> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="67" data-source-title="" data-text="1.解决方案(主要是在性能和数据一致性二者间寻找一个平衡)。2.设置缓存失效时间(1 个小时,过期后同步数据)。3.针对资源设置版本号。" data-editid="2iadhcf3w7gy1t47i8"> <section class="js_blockquote_digest"> <section> <p style="white-space: normal;box-sizing: border-box;">1.解决方案(主要是在性能和数据一致性二者间寻找一个平衡)。</p> <p style="white-space: normal;box-sizing: border-box;">2.设置缓存失效时间(1 个小时,过期后同步数据)。</p> <p style="white-space: normal;box-sizing: border-box;">3.针对资源设置版本号。</p> </section> </section> </blockquote>​​ </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">2.2 反向代理缓存</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-backh="340" data-backw="578" data-ratio="0.5885558583106267" data-s="300,640" data-type="png" data-w="1101" style="width: 100%;height: auto !important;" src="/upload/725f290a6b675ad529959202e88ef4b7.png"></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">2.2.1 反向代理缓存原理</strong></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">反向代理位于应用服务器同一网络,处理所有对 WEB 服务器的请求。反向代理缓存的原理:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">如果用户请求的页面在代理服务器上有缓存的话,代理服务器直接将缓存内容发送给用户。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">如果没有缓存则先向 WEB 服务器发出请求,取回数据,本地缓存后再发送给用户。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">这种方式通过降低向 WEB 服务器的请求数,从而降低了 WEB 服务器的负载。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">反向代理缓存一般针对的是静态资源,而将动态资源请求转发到应用服务器处理。常用的缓存应用服务器有 Varnish,Ngnix,Squid。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">2.2.2 反向代理缓存比较</strong></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">常用的代理缓存有 Varnish,Squid,Ngnix,简单比较如下:</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">Varnish 和 Squid 是专业的 cache 服务,Ngnix 需要第三方模块支持;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">Varnish 采用内存型缓存,避免了频繁在内存、磁盘中交换文件,性能比 Squid 高;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">Varnish 由于是内存 cache,所以对小文件如 css、js、小图片的支持很棒,后端的持久化缓存可以采用的是 Squid 或 ATS;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">Squid 功能全而大,适合于各种静态的文件缓存,一般会在前端挂一个 HAProxy 或 Ngnix 做负载均衡跑多个实例;</p></li> <li> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">Nginx 采用第三方模块 ncache 做的缓冲,性能基本达到 Varnish,一般作为反向代理使用,可以实现简单的缓存。</p> </section></li> </ul> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="margin-top: 10px;margin-bottom: 10px;text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding: 3px;display: inline-block;border-bottom: 1px solid rgb(65, 94, 255);font-size: 17px;color: rgb(65, 94, 255);box-sizing: border-box;"> <p style="box-sizing: border-box;">三、进程内缓存</p> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">进程内缓存是指应用内部的缓存,标准的分布式系统,一般有多级缓存构成。本地缓存是离应用最近的缓存,一般可以将数据缓存到硬盘或内存。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">硬盘缓存</strong>:将数据缓存到硬盘中,读取时从硬盘读取。原理是直接读取本机文件,减少了网络传输消耗,比通过网络读取数据库速度更快。可以应用在对速度要求不是很高,但需要大量缓存存储的场景。</p></li> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">内存缓存</strong>:直接将数据存储到本机内存中,通过程序直接维护缓存对象,是访问速度最快的方式。</p></li> </ul> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">常见的本地缓存实现方案:HashMap、Guava Cache、Caffeine、Ehcache。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><span style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;">3.1 ConcurrentHashMap</span></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">最简单的进程内缓存可以通过 JDK 自带的 HashMap 或 ConcurrentHashMap 实现。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">适用场景:不需要淘汰的缓存数据。</p></li> <li> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">缺点:无法进行缓存淘汰,内存会无限制的增长。</p> </section></li> </ul> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">3.2&nbsp;LRUHashMap</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">可以通过继承 LinkedHashMap 来实现一个简单的 LRUHashMap。重写 removeEldestEntry 方法,即可完成一个简单的最近最少使用算法。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">缺点:</p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">锁竞争严重,性能比较低。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">不支持过期时间。</p></li> <li> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">不支持自动刷新。</p> </section></li> </ul> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">3.3&nbsp; Guava Cache</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">解决了LRUHashMap 中的几个缺点。Guava Cache 采用了类似 ConcurrentHashMap 的思想,分段加锁,减少锁竞争。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">Guava Cache 对于过期的 Entry 并没有马上过期(也就是并没有后台线程一直在扫),而是通过进行读写操作的时候进行过期处理,这样做的好处是避免后台线程扫描的时候进行全局加锁。直接通过查询,判断其是否满足刷新条件,进行刷新。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">3.4&nbsp; Caffeine</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">Caffeine 实现了 W-TinyLFU(LFU + LRU 算法的变种),其命中率和读写吞吐量大大优于 Guava Cache。其实现原理较复杂,可以参考你应该知道的缓存进化史。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">3.5 Ehcache</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">优点</strong></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">快速、简单;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">支持多种缓存策略:LRU、LFU、FIFO 淘汰算法;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">缓存数据有两级:内存和磁盘,因此无需担心容量问题;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">缓存数据会在虚拟机重启的过程中写入磁盘;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">可以通过 RMI、可插入 API 等方式进行分布式缓存;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">具有缓存和缓存管理器的侦听接口;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">支持多缓存管理器实例,以及一个实例的多个缓存区域;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">提供 Hibernate 的缓存实现。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">缺点</strong></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">使用磁盘 Cache 的时候非常占用磁盘空间;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">不保证数据的安全;</p></li> <li><p style="white-space: normal;box-sizing: border-box;">虽然支持分布式缓存,但效率不高(通过组播方式,在不同节点之间同步数据)。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">3.6 进程内缓存对比</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">常用进程内缓存技术对比:</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-backh="340" data-backw="578" data-ratio="0.5877502944640753" data-s="300,640" data-type="png" data-w="849" style="width: 100%;height: auto !important;" src="/upload/4e1c728059aff9612a61fe25b1ec8b08.png"></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> </section> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">ConcurrentHashMap</strong>:比较适合缓存比较固定不变的元素,且缓存的数量较小的。虽然从上面表格中比起来有点逊色,但是其由于是 JDK 自带的类,在各种框架中依然有大量的使用,比如我们可以用来缓存我们反射的 Method,Field 等等;也可以缓存一些链接,防止其重复建立。在 Caffeine 中也是使用的 ConcurrentHashMap 来存储元素。</p></li> </ul> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">LRUMap</strong>:如果不想引入第三方包,又想使用淘汰算法淘汰数据,可以使用这个。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">Ehcache</strong>:由于其 jar 包很大,较重量级。对于需要持久化和集群的一些功能的,可以选择 Ehcache。需要注意的是,虽然 Ehcache 也支持分布式缓存,但是由于其节点间通信方式为 rmi,表现不如 Redis,所以一般不建议用它来作为分布式缓存。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">Guava Cache</strong>:Guava 这个 jar 包在很多 Java 应用程序中都有大量的引入,所以很多时候其实是直接用就好了,并且其本身是轻量级的而且功能较为丰富,在不了解 Caffeine 的情况下可以选择 Guava Cache。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">Caffeine</strong>:其在命中率,读写性能上都比 Guava Cache 好很多,并且其 API 和 Guava cache 基本一致,甚至会多一点。在真实环境中使用 Caffeine,取得过不错的效果。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">总结一下:如果不需要淘汰算法则选择 ConcurrentHashMap,如果需要淘汰算法和一些丰富的 API,推荐选择。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="margin-top: 10px;margin-bottom: 10px;text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding: 3px;display: inline-block;border-bottom: 1px solid rgb(65, 94, 255);font-size: 17px;color: rgb(65, 94, 255);box-sizing: border-box;"> <p style="box-sizing: border-box;">四、分布式缓存</p> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">分布式缓存解决了进程内缓存最大的问题:如果应用是分布式系统,节点之间无法共享彼此的进程内缓存。<span style="box-sizing: border-box;">分布式缓存的应用场景:</span></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li><p style="white-space: normal;box-sizing: border-box;">缓存经过复杂计算得到的数据。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">缓存系统中频繁访问的热点数据,减轻数据库压力。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">不同分布式缓存的实现原理往往有比较大的差异。本文主要针对 Memcached 和 Redis 进行说明。</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="font-size: 16px;color: rgb(70, 97, 246);box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;box-sizing: border-box;">4.1 Memcached</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="wh