文章列表

深入理解 ELK 中 Logstash 的底层原理 + 填坑指南

作者:微信小助手

<p style="white-space: normal;text-align: center;"><img class="rich_pages wxw-img" data-ratio="0.6925207756232687" src="/upload/3afecd9bcad8087524ef7db1f8f51abf.jpg" data-type="jpeg" data-w="722" style="display: inline;"></p> <p style="white-space: normal;text-align: center;"><br></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);">149</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;overflow-wrap: break-word;text-align: left;font-size: 15px;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;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(255, 104, 39);">你好,我是悟空呀,我被憧憬小哥催更了。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="color: rgb(255, 104, 39);"><span style="font-weight: 700;">儿童节、端午节前发一篇,祝大家双节快乐</span>~</span></p> <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-top: 0em;margin-bottom: 0em;">本文目录如下:</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li><p>前言</p></li> <li><p>一、部署架构图</p></li> <li><p>二、Logstash 用来做什么?</p></li> <li><p>三、Logstash 的原理</p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-1"> <li><p>3.1 从 Logstash 自带的配置说起</p></li> <li><p>3.2 Input 插件</p></li> <li><p>3.3 Filter 插件</p></li> <li><p>3.4 Output 插件</p></li> <li><p>3.5 完整配置</p></li> </ul> <li><p>四、Logstash 怎么跑起来的</p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-1"> <li><p>4.1 Logstash 如何运行的</p></li> <li><p>4.2 Logstash 的架构原理</p></li> </ul> <li><p>五、Logstash 宕机风险</p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-1"> <li><p>5.1 Logstash 单点部署的风险</p></li> <li><p>5.2 开机启动 Logstash</p></li> </ul> <li><p>六、总结</p></li> </ul> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="font-size: 18px;color: rgb(34, 34, 34);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-top: 0em;margin-bottom: 0em;">通过本篇内容,你可以学到如何解决 Logstash 的常见问题、理解 Logstash 的运行机制、集群环境下如何部署 ELK Stack。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">在使用 Logstash 遇到了很多坑,本篇也会讲解解决方案。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 日志记录的格式复杂,正则表达式非常磨人。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 服务日志有多种格式,如何匹配。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 错误日志打印了堆栈信息,包含很多行,如何合并。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 日志记录行数过多(100多行),被拆分到了其他的日志记录中。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 输出到 ES 的日志包含很多无意义字段。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 输出到 ES 的日志时间和本来的日志时间相差 8 小时。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 如何优化 Logstash 的性能 <br> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> Logstash 单点故障如何处理。 <span style="letter-spacing: 0.8px;word-spacing: 0.8px;"></span> </section></li> </ul> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="font-size: 18px;color: rgb(34, 34, 34);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-top: 0em;margin-bottom: 0em;">上次我们聊到了 ELK Stack 的搭建:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451962693&amp;idx=1&amp;sn=96530613aaadd8240d8a5c2ab7dff49d&amp;chksm=8d1c02daba6b8bcc2499861fd37aac5cfa88d616fc839cb6a7a3c003118457ac325c3dcbeb62&amp;scene=21#wechat_redirect" style="overflow-wrap: break-word;color: rgb(248, 57, 41);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-top: 0em;margin-bottom: 0em;">最近悟空正在我们的测试环境部署这一套 ELK,发现还是有很多内容需要再单独拎几篇出来详细讲讲的,这次我会带着大家一起来看下 ELK 中的 Logstash 组件的落地玩法和踩坑之路。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">测试环境目前有 <span style="font-weight: 700;color: rgb(248, 57, 41);">12</span> 台机器,其中 有 <span style="font-weight: 700;color: rgb(248, 57, 41);">4</span> 台给后端微服务、Filebeat、Logstash 使用,<span style="font-weight: 700;color: rgb(248, 57, 41);">3</span> 台给 ES 集群和 Kibana 使用。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">部署拓扑图如下:<img class="rich_pages wxw-img" data-ratio="0.46386946386946387" src="/upload/d9d3148e9b427f7375c7a6e245540c6f.png" data-type="png" data-w="2574" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">部署说明</span>:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">4 台服务器给业务微服务服务使用,微服务的日志会存放本机上。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">4 台服务器都安装 Filebeat 日志采集器,采集本机的微服务日志,</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">其中一台服务器安装 Logstash ,Filebeat 发送日志给 Logstash。Logstash 将日志输出到 Elasticsearch 集群中。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">3 台服务器都安装有 Elasticsearch 服务,组成 ES 集群。其中一台安装 Kibana 服务,查询 ES 集群中的日志信息。</p> </section></li> </ul> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">二、Logstash 用来做什么?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">你是否还在苦恼每次生产环境出现问题都需要远程到服务器查看日志文件?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">你是否还在为了没有统一的日志搜索入口而烦心?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">你是否还在为从几十万条日志中搜索关键信息而苦恼?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">没错,Logstash 它来啦,带着所有的日志记录来啦。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Logstash 它是帮助我们收集、解析和转换日志的。作为 ELK 中的一员,发挥着很大的作用。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">当然 Logstash 不仅仅用在收集日志方面,还可以收集其他内容,我们最熟悉的还是用在日志方面。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">三、Logstash 的原理</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="font-size: 16px;color: #222;">3.1 从 Logstash 自带的配置说起</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Logstash 的原理其实还比较简单,一个输入,一个输出,中间有个管道(不是必须的),这个管道用来收集、解析和转换日志的。如下图所示:</p> <figure data-tool="mdnice编辑器" style="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.4413793103448276" src="/upload/b3cfd951c123b81ecfb676fc41416048.png" data-type="png" data-w="870" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> Logstash 组件 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Logstash 运行时,会读取 Logstash 的配置文件,配置文件可以配置输入源、输出源、以及如何解析和转换的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">Logstash 配置项中有两个必需元素,输入(inputs)和输出(ouputs),以及一个可选元素 filters 过滤器插件。input 可以配置来源数据,过滤器插件在你指定时修改数据,output 将数据写入目标。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">我们来看下 Logstash 软件自带的一个示例配置,文件路径:\logstash-7.6.2\config\logstash-sample.conf</p> <figure data-tool="mdnice编辑器" style="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.4735169491525424" src="/upload/6134198cbb6e489454aad656c47cf11e.png" data-type="png" data-w="944" 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-top: 0em;margin-bottom: 0em;">是不是很简单,一个 input 和 一个 output 就搞定了。如下图所示:</p> <figure data-tool="mdnice编辑器" style="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.3762057877813505" src="/upload/b28ada46fb600238f27ac3e07f8664af.png" data-type="png" data-w="1244" 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-top: 0em;margin-bottom: 0em;">但是这种配置其实意义不大,没有对日志进行解析,传到 ES 中的数据是原始数据,也就是一个 message 字段包含一整条日志信息,不便于根据字段搜索。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="font-size: 16px;color: #222;">3.2 Input 插件</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">配置文件中 input 输入源指定了 beats,而 beats 是一个大家族,Filebeat 只是其中之一。对应的端口 port = 5044,表示 beats 插件可以往 5044 端口发送日志,logstash 可以接收到通过这个端口和 beats 插件通信。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">在部署架构图中,input 输入源是 Filebeat,它专门监控日志的变化,然后将日志传给 Logstash。在早期,Logstash 是自己来采集的日志文件的。所以早期的日志检索方案才叫做 ELK,Elasticsearch + Logstash + Kibana,而现在加入了 Filebeat 后,这套日志检索方案属于 ELK Stack,不是 ELKF,摒弃了用首字母缩写来命名。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">另外 input 其实有很多组件可以作为输入源,不限于 Filebeat,比如我们可以用 Kafka 作为输入源,将消息传给 Logstash。具体有哪些插件列表,可以参考这个 <span style="color: rgb(248, 57, 41);">input 插件列表</span><sup style="line-height: 0;color: rgb(248, 57, 41);">[1]</sup></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="font-size: 16px;color: #222;">3.3 Filter 插件</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">而对于 Logstash 的 Filter,这个才是 Logstash 最强大的地方。Filter 插件也非常多,我们常用到的 grok、date、mutate、mutiline 四个插件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">对于 filter 的各个插件执行流程,可以看下面这张图:</p> <figure data-tool="mdnice编辑器" style="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.4929906542056075" src="/upload/33d8e0e8b126d0c7e7763075fc35a81d.png" data-type="png" data-w="856" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 图片来自 Elasticsearch 官网 </figcaption> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;">3.3.1 日志示例</h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">我以我们后端服务打印的日志为例,看是如何用 filter 插件来解析和转换日志的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">logback.xml 配置的日志格式如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #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;">&lt;encoder&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;pattern&gt;%d{yyyy-MM-dd&nbsp;HH:mm:ss.SSS}&nbsp;[%thread]&nbsp;%-5level&nbsp;%logger&nbsp;-&nbsp;%msg%n&lt;/pattern&gt;<br>&lt;/encoder&gt;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">日志格式解释如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);font-size: 16px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">记录日志时间:%d{yyyy-MM-dd HH:mm:ss.SSS}</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">记录是哪个线程打印的日志:[%thread]</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">记录日志等级:%-5level</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">打印日志的类:%logger</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;font-size: 15px;">记录具体日志信息:%msg%n,这个 msg 的内容就是 log.info("abc") 中的 abc。</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">通过执行代码 log.info("xxx") 后,就会在本地的日志文件中追加一条日志。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;">3.3.2 打印的日志内容</h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">从服务器拷贝出了一条日志,看下长什么样,有部分敏感信息我已经去掉了。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #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;">2022-06-16&nbsp;15:50:00.070&nbsp;[XNIO-1&nbsp;task-1]&nbsp;INFO&nbsp;&nbsp;com.passjava.config&nbsp;-&nbsp;方法名为:MemberController-,请求参数:{省略}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">那么 Logstash 如何针对上面的信息解析出对应的字段呢?比如如何解析出打印日志的时间、日志等级、日志信息?</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;">3.3.3 grok 插件</h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">这里就要用到 logstash 的 filter 中的 grok 插件。filebeat 发送给 logstash 的日志内容会放到message 字段里面,logstash 匹配这个 message 字段就可以了。配置项如下所示:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #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;">filter&nbsp;{<br>&nbsp;grok&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;=&gt;&nbsp;[&nbsp;<span style="color: #986801;line-height: 26px;">"message"</span>,&nbsp;<span style="color: #986801;line-height: 26px;">"(?&lt;logTime&gt;\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}.\d{3})\s+\[(?&lt;thread&gt;.*)\]\s+(?&lt;level&gt;\w*)\s{1,2}+(?&lt;class&gt;\S*)\s+-\s+(?&lt;content&gt;.*)\s*"</span>]<br>&nbsp;&nbsp;}<br>}<br></code></pre> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: black;line-height: 26px;"><span style="font-weight: 700;color: rgb(248, 57, 41);">坑</span>:日志记录的格式复杂,正则表达式非常磨人。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">大家发现没,上面的 匹配 message 的正则表达式还是挺复杂的,这个是我一点一点试出来的。Kibana 自带 grok 的正则匹配的工具,路径如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #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;">http://&lt;your&nbsp;kibana&nbsp;IP&gt;:5601/app/kibana<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">#/dev_tools/grokdebugger</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">我们把日志和正则表达式分别粘贴到上面的输入框,点击 Simulate 就可以测试是否能正确匹配和解析出日志字段。如下图所示:</p> <figure data-tool="mdnice编辑器" style="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.6238993710691824" src="/upload/a79c4b6ae7106df2b619736668d7a1bb.png" data-type="png" data-w="1590" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> Grok Debugger 工具 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">有没有常用的正则表达式呢?有的,logstash 官方也给了一些常用的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">常量</code>来表达那些正则表达式,可以到这个 Github 地址查看有哪些常用的常量。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #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;">https://github.com/logstash-plugins/logstash-patterns-core/blob/main/patterns/ecs-v1/grok-patterns<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">比如可以用 IP 常量来代替正则表达式 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">IP (?:%{IPV6}|%{IPV4})</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">好了,经过正则表达式的匹配之后,grok 插件会将日志解析成多个字段,然后将多个字段存到了 ES 中,这样我们可以在 ES 通过字段来搜索,也可以在 kibana 的 Discover 界面添加列表展示的字段。<img class="rich_pages wxw-img" data-ratio="0.5024390243902439" src="/upload/d629caeab6735c5146551769645d1bfa.png" data-type="png" data-w="615" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"></p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: black;line-height: 26px;"><span style="font-weight: 700;color: rgb(248, 57, 41);">坑</span>:我们后端项目的不同服务打印了两种不同格式的日志,那这种如何匹配?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">再加一个 match 就可以了。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #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;">filter&nbsp;{<br>&nbsp;grok&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;=&gt;&nbsp;[&nbsp;<span style="color: #986801;line-height: 26px;">"message"</span>,&nbsp;<span style="color: #986801;line-height: 26px;">"(?&lt;logTime&gt;\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}.\d{3})\s+\[(?&lt;thread&gt;.*)\]\s+(?&lt;level&gt;\w*)\s{1,2}+(?&lt;class&gt;\S*)\s+-\s+(?&lt;content&gt;.*)\s*"</span>]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;match&nbsp;=&gt;&nbsp;[&nbsp;<span style="color: #986801;line-height: 26px;">"message"</span>,&nbsp;<span style="color: #986801;line-height: 26px;">"(?&lt;logTime&gt;\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}.\d{3})\s{1,2}+(?&lt;level&gt;\w*)\s{1,2}+.\s---+\s\[(?&lt;thread&gt;.*)\]+\s(?&lt;class&gt;\S*)\s*:+\s(?&lt;content&gt;.*)\s*"</span>]<br>&nbsp;&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;">当任意一个 message 匹配上了这个正则,则 grok 执行完毕。假如还有第三种格式的 message,那么虽然 grok 没有匹配上,但是 message 也会输出到 ES,只是这条日志在 ES 中不会展示 logTime、level 等字段。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 18px;">3.3.4 multiline 插件</h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0em;margin-bottom: 0em;"><span style="font-weight: 7

这类注解都不知道,还好意思说用过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