作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;margin: 10px 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">之前已经分享过Elasticsearch的使用和原理的知识,由于近期在公司内部做了一次分享,所以本篇主要是基于之前的博文的一个总结,希望通过这篇文章能让读者大致了解Elasticsearch是做什么的以及它的使用和基本原理。</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-family: STHeitiSC-Light;font-size: 22px;color: #0e88eb;font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid #0e88eb;"><a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247487551&idx=1&sn=18f64ba49f3f0f9d8be9d1fdef8857d9&scene=21#wechat_redirect" style="text-decoration: none;word-wrap: break-word;font-weight: bold;color: #0e88eb;border-bottom: 0px solid #ff3502;font-family: STHeitiSC-Light;" data-linktype="2">生活中的数据</a></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;margin: 10px 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">搜索引擎是对数据的检索,所以我们先从生活中的数据说起。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;margin: 10px 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">我们生活中的数据总体分为两种:<strong style="font-weight: border;color: #0e88eb;">结构化数据</strong> 和 <strong style="font-weight: border;color: #0e88eb;">非结构化数据</strong> 。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;margin: 10px 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><strong style="font-weight: border;color: #0e88eb;">结构化数据</strong> :也称作行数据,是由二维表结构来�
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-size: 15px;margin-top: -1em;padding: 0px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;margin-bottom: 0px;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;"><span style="font-size: inherit;letter-spacing: 0px;">上周看到一篇因为在金额计算中没有使用</span><code style="letter-spacing: 0px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(228, 105, 24);background-color: rgb(239, 239, 239);font-size: 0.875em;line-height: 1.8 !important;">BigDecimal</code><span style="font-size: inherit;letter-spacing: 0px;">而导致故障的文章,但是除非在一些非常简单的场景,结算汇金类的业务也不会直接用</span><code style="letter-spacing: 0px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(228, 105, 24);background-color: rgb(239, 239, 239);font-size: 0.875em;line-height: 1.8 !important;">BigDecimal</code><span style="font-size: inherit;letter-spacing: 0px;">来计算金额,原因有两点:</span><br></p> <ol data-tool="mdnice编辑器" style="color: black;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;line-height: 1.8 !important;" class="list-paddingleft-1"> <li style="line-height: 1.8 !important;"> <section style="margin: em 0;text-align: left;color: rgb(1,1,1);margin-top: .3em;margin-bottom: .3em;font-weight: normal;line-height: 1.8 !important;"> <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;line-height: 1.8 !important;">BigDecimal</code>里面还是有很多隐蔽的坑的 </section></li> <li style="line-height: 1.8 !important;"> <section style="margin: em 0;text-align: left;color: rgb(1,1,1);margin-top: .3em;margin-bottom: .3em;font-weight: normal;line-height: 1.8 !important;"> <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;line-height: 1.8 !important;">BigDecimal</code>没有提供金额的单位 </section></li> </ol> <h1 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.3em;margin-top: 0.3em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">1. <code style="line-height: 1.8 !important;">BigDecimal</code>中的五个容易踩的坑</span><span style="line-height: 1.8 !important;"></span></h1> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">1.1 <code style="line-height: 1.8 !important;">new BigDecimal()</code>还是<code style="line-height: 1.8 !important;">BigDecimal#valueOf()</code>?</span><span style="line-height: 1.8 !important;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">先看下面这段代码</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">BigDecimal bd1 = <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">new</span> BigDecimal(<span style="color: #008080;line-height: 1.8 !important;">0.01</span>);<br style="line-height: 1.8 !important;">BigDecimal bd2 = <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">BigDecimal.valueOf</span>(<span style="color: #d14;line-height: 1.8 !important;">0.01</span>);<br style="line-height: 1.8 !important;">System.out.println(<span style="color: #d14;line-height: 1.8 !important;">"bd1 = "</span> + bd1);<br style="line-height: 1.8 !important;">System.out.println(<span style="color: #d14;line-height: 1.8 !important;">"bd2 = "</span> + bd2);<br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">输出到控制台的结果是:</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">bd1 = <span style="color: #008080;line-height: 1.8 !important;">0.01000000000000000020816681711721685132943093776702880859375</span><br style="line-height: 1.8 !important;">bd2 = <span style="color: #008080;line-height: 1.8 !important;">0.01</span><br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">造成这种差异的原因是0.1这个数字计算机是无法精确表示的,送给<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">BigDecimal</code>的时候就已经丢精度了,而<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">BigDecimal#valueOf</code>的实现却完全不同</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;"><span style="line-height: 1.8 !important;"><span style="color: #333;font-weight: bold;line-height: 1.8 !important;">public</span> <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">static</span> BigDecimal <span style="color: #900;font-weight: bold;line-height: 1.8 !important;">valueOf</span><span style="line-height: 1.8 !important;">(<span style="color: #333;font-weight: bold;line-height: 1.8 !important;">double</span> val)</span> </span>{<br style="line-height: 1.8 !important;"> <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// Reminder: a zero double returns '0.0', so we cannot fastpath</span><br style="line-height: 1.8 !important;"> <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// to use the constant ZERO. This might be important enough to</span><br style="line-height: 1.8 !important;"> <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// justify a factory approach, a cache, or a few private</span><br style="line-height: 1.8 !important;"> <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// constants, later.</span><br style="line-height: 1.8 !important;"> <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">return</span> <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">new</span> BigDecimal(Double.toString(val));<br style="line-height: 1.8 !important;">}<br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">它使用了浮点数相应的字符串来构造<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">BigDecimal</code>对象,因此避免了精度问题。所以大家要尽量要使用字符串而不是浮点数去构造<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">BigDecimal</code>对象,如果实在不行,就使用<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">BigDecimal#valueOf()</code>方法吧。</p> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">1.2 等值比较</span><span style="line-height: 1.8 !important;"></span></h2> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">BigDecimal bd1 = <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">new</span> BigDecimal(<span style="color: #d14;line-height: 1.8 !important;">"1.0"</span>);<br style="line-height: 1.8 !important;">BigDecimal bd2 = <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">new</span> BigDecimal(<span style="color: #d14;line-height: 1.8 !important;">"1.00"</span>);<br style="line-height: 1.8 !important;">System.out.println(bd1.equals(bd2));<br style="line-height: 1.8 !important;">System.out.println(bd1.compareTo(bd2));<br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">控制台的输出将会是:</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;"><span style="color: #333;font-weight: bold;line-height: 1.8 !important;">false</span><br style="line-height: 1.8 !important;"><span style="color: #008080;line-height: 1.8 !important;">0</span><br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">究其原因是,<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">BigDecimal</code>中<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">equals</code>方法的实现会比较两个数字的精度,而<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">compareTo</code>方法则只会比较数值的大小。</p> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">1.3 <code style="line-height: 1.8 !important;">BigDecimal</code>并不代表无限精度</span><span style="line-height: 1.8 !important;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">先看这段代码</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">BigDecimal a = <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">new</span> BigDecimal(<span style="color: #d14;line-height: 1.8 !important;">"1.0"</span>);<br style="line-height: 1.8 !important;">BigDecimal b = <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">new</span> BigDecimal(<span style="color: #d14;line-height: 1.8 !important;">"3.0"</span>);<br style="line-height: 1.8 !important;">a.divide(b) <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// results in the following exception.</span><br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">结果会抛出异常:</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.<br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">关于这个异常,Oracle的官方文档有具体说明</p> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">If the quotient has a nonterminating decimal expansion and the operation is specified to return an exact result, an ArithmeticException is thrown. Otherwise, the exact result of the division is returned, as done for other operations.</p> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">大意是,如果除法的商的结果是一个无限小数但是我们期望返回精确的结果,那程序就会抛出异常。回到我们的这个例子,我们需要告诉<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">JVM</code>我们不需要返回精确的结果就好了</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">BigDecimal a = <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">new</span> BigDecimal(<span style="color: #d14;line-height: 1.8 !important;">"1.0"</span>);<br style="line-height: 1.8 !important;">BigDecimal b = <span style="color: #333;font-weight: bold;line-height: 1.8 !important;">new</span> BigDecimal(<span style="color: #d14;line-height: 1.8 !important;">"3.0"</span>);<br style="line-height: 1.8 !important;">a.divide(b, <span style="color: #008080;line-height: 1.8 !important;">2</span>, RoundingMode.HALF_UP)<span style="color: #998;font-style: italic;line-height: 1.8 !important;">// 0.33</span><br style="line-height: 1.8 !important;"></code></pre> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">1.4 <code style="line-height: 1.8 !important;">BigDecimal</code>转回<code style="line-height: 1.8 !important;">String</code>要小心</span><span style="line-height: 1.8 !important;"></span></h2> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">BigDecimal d = BigDecimal.valueOf(<span style="color: #008080;line-height: 1.8 !important;">12334535345456700.12345634534534578901</span>);<br style="line-height: 1.8 !important;">String out = d.toString(); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// Or perform any formatting that needs to be done</span><br style="line-height: 1.8 !important;">System.out.println(out); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// 1.23345353454567E+16</span><br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">可以看到结果已经被转换成了科学计数法,可能这个并不是预期的结果<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">BigDecimal</code>有三个方法可以转为相应的字符串类型,切记不要用错:</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;"><span style="line-height: 1.8 !important;">String <span style="color: #900;font-weight: bold;line-height: 1.8 !important;">toString</span><span style="line-height: 1.8 !important;">()</span></span>; <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// 有必要时使用科学计数法</span><br style="line-height: 1.8 !important;"><span style="line-height: 1.8 !important;">String <span style="color: #900;font-weight: bold;line-height: 1.8 !important;">toPlainString</span><span style="line-height: 1.8 !important;">()</span></span>; <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// 不使用科学计数法</span><br style="line-height: 1.8 !important;"><span style="line-height: 1.8 !important;">String <span style="color: #900;font-weight: bold;line-height: 1.8 !important;">toEngineeringString</span><span style="line-height: 1.8 !important;">()</span></span>; <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// 工程计算中经常使用的记录数字的方法,与科学计数法类似,但要求10的幂必须是3的倍数</span><br style="line-height: 1.8 !important;"></code></pre> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">1.5 执行顺序不能调换(乘法交换律失效)</span><span style="line-height: 1.8 !important;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">乘法满足交换律是一个常识,但是在计算机的世界里,会出现不满足乘法交换律的情况</p> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">BigDecimal a = BigDecimal.valueOf(<span style="color: #008080;line-height: 1.8 !important;">1.0</span>);<br style="line-height: 1.8 !important;">BigDecimal b = BigDecimal.valueOf(<span style="color: #008080;line-height: 1.8 !important;">3.0</span>);<br style="line-height: 1.8 !important;">BigDecimal c = BigDecimal.valueOf(<span style="color: #008080;line-height: 1.8 !important;">3.0</span>);<br style="line-height: 1.8 !important;">System.out.println(a.divide(b, <span style="color: #008080;line-height: 1.8 !important;">2</span>, RoundingMode.HALF_UP).multiply(c)); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// 0.990</span><br style="line-height: 1.8 !important;">System.out.println(a.multiply(c).divide(b, <span style="color: #008080;line-height: 1.8 !important;">2</span>, RoundingMode.HALF_UP)); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// 1.00</span><br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">别小看这这0.01的差别,在汇金领域,会产生非常大的金额差异。</p> <h1 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.3em;margin-top: 0.3em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">2. 最佳实践</span><span style="line-height: 1.8 !important;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">关于金额计算,很多业务团队会基于<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">BigDecimal</code>再封装一个<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">Money</code>类,其实我们直接可以用一个半官方的<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">Money</code>类:JSR 354 ,虽然没能在<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">Java 9</code>中成为<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">Java</code>标准,很有可能集成到后续的<code style="word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #e46918;background-color: #efefef;font-size: .875em;line-height: 1.8 !important;">Java</code>版本中成为官方库。</p> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">2.1 <code style="line-height: 1.8 !important;">maven</code>坐标</span><span style="line-height: 1.8 !important;"></span></h2> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;"><dependency><br style="line-height: 1.8 !important;"> <groupId>org.javamoney</groupId><br style="line-height: 1.8 !important;"> <artifactId>moneta</artifactId><br style="line-height: 1.8 !important;"> <version><span style="color: #008080;line-height: 1.8 !important;">1.1</span></version><br style="line-height: 1.8 !important;"></dependency><br style="line-height: 1.8 !important;"></code></pre> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">2.2 新建<code style="line-height: 1.8 !important;">Money</code>类</span><span style="line-height: 1.8 !important;"></span></h2> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">CurrencyUnit cny = Monetary.getCurrency(<span style="color: #d14;line-height: 1.8 !important;">"CNY"</span>);<br style="line-height: 1.8 !important;">Money money = Money.of(<span style="color: #008080;line-height: 1.8 !important;">1.0</span>, cny); <br style="line-height: 1.8 !important;"><span style="color: #998;font-style: italic;line-height: 1.8 !important;">// 或者 Money money = Money.of(1.0, "CNY");</span><br style="line-height: 1.8 !important;"><span style="color: #998;font-style: italic;line-height: 1.8 !important;">//System.out.println(money);</span><br style="line-height: 1.8 !important;"></code></pre> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">2.3 金额运算</span><span style="line-height: 1.8 !important;"></span></h2> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">CurrencyUnit cny = Monetary.getCurrency(<span style="color: #d14;line-height: 1.8 !important;">"CNY"</span>);<br style="line-height: 1.8 !important;">Money oneYuan = Money.of(<span style="color: #008080;line-height: 1.8 !important;">1.0</span>, cny);<br style="line-height: 1.8 !important;">Money threeYuan = oneYuan.add(Money.of(<span style="color: #008080;line-height: 1.8 !important;">2.0</span>, <span style="color: #d14;line-height: 1.8 !important;">"CNY"</span>)); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">//CNY 3</span><br style="line-height: 1.8 !important;">Money tenYuan = oneYuan.multiply(<span style="color: #008080;line-height: 1.8 !important;">10</span>); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// CNY 10</span><br style="line-height: 1.8 !important;">Money fiveFen = oneYuan.divide(<span style="color: #008080;line-height: 1.8 !important;">2</span>); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">//CNY 0.5</span><br style="line-height: 1.8 !important;"></code></pre> <h2 data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-bottom: 15px;padding: 0px 0px 0.2em;font-weight: bold;font-size: 1.2em;margin-top: 0em;border-bottom: 1px solid rgb(223, 226, 229);line-height: 1.8 !important;"><span style="display: none;line-height: 1.8 !important;"></span><span style="line-height: 1.8 !important;">2.4 比较相等</span><span style="line-height: 1.8 !important;"></span></h2> <pre data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;line-height: 1.8 !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/6mXOeYa4HUic5v3730mmicXWL62ytWvKdxib8S3jUjNHjQ4SoO3pFw0qRiceHIicWibNB6qQe2QoWgvY4iageqgWNJZZibcvNp0nAcjF/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;-webkit-overflow-scrolling: touch;font-size: .875em;padding-top: 15px;background: #f8f8f8;border-radius: 5px;line-height: 1.8 !important;">Money fiveFen = Money.of(<span style="color: #008080;line-height: 1.8 !important;">0.5</span>, <span style="color: #d14;line-height: 1.8 !important;">"CNY"</span>); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">//CNY 0.5</span><br style="line-height: 1.8 !important;">Money anotherFiveFen = Money.of(<span style="color: #008080;line-height: 1.8 !important;">0.50</span>, <span style="color: #d14;line-height: 1.8 !important;">"CNY"</span>); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// CNY 0.50</span><br style="line-height: 1.8 !important;">System.out.println(fiveFen.equals(anotherFiveFen)); <span style="color: #998;font-style: italic;line-height: 1.8 !important;">// true</span><br style="line-height: 1.8 !important;"></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(51, 51, 51);padding-top: 8px;padding-bottom: 8px;font-size: inherit;margin-bottom: 0.1em;margin-top: 0.1em;line-height: 1.8 !important;">可以看到,这个类对金额做了显性的抽象,增加了金额的单位,也避免了直接使用的一些坑。</p> </section>
作者:微信小助手
<section data-mpa-powered-by="yiban.io" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;margin-bottom: 0px;"> <section powered-by="xiumi.us" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section powered-by="xiumi.us" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">我在研究HikariCP(一个数据库连接池)时无意间在HikariCP的Github wiki上看到了一篇文章,这篇文章有力地消除了我一直以来的疑虑,看完之后感觉神清气爽。故在此做译文分享。</p> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;display: block;overflow: auto;background: rgb(255, 249, 249);visibility: visible;"> <p style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;font-size: 16px;color: black;line-height: 26px;visibility: visible;">文章链接:https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;visibility: visible;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;visibility: visible;">接下来是正文</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">数据库连接池的配置是开发者们常常搞出坑的地方,在配置数据库连接池时,有几个可以说是和直觉背道而驰的原则需要明确。</p> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;visibility: visible;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;visibility: visible;">1万并发用户访问</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">想象你有一个网站,压力虽然还没到Facebook那个级别,但也有个1万上下的并发访问——也就是说差不多2万左右的TPS。那么这个网站的数据库连接池应该设置成多大呢?结果可能会让你惊讶,因为这个问题的正确问法是:</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;visibility: visible;">“这个网站的数据库连接池应该设置成多小呢?”</strong></p> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;display: block;overflow: auto;background: rgb(255, 249, 249);visibility: visible;"> <p style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;font-size: 16px;color: black;line-height: 26px;visibility: visible;">下面这个视频是Oracle Real World Performance Group发布的,请先看完:http://www.dailymotion.com/video/x2s8uec</p> </blockquote> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;visibility: visible;">因为这视频是英文解说且没有字幕,我替大家做一下简单的概括:</strong></p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">视频中对Oracle数据库进行压力测试,9600并发线程进行数据库操作,每两次访问数据库的操作之间sleep 550ms,一开始设置的中间件线程池大小为2048:</p> <p style="white-space: normal;text-align: center;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"></span><span style="font-size: 13px;letter-spacing: 0.12px;color: rgb(255, 76, 65);"></span></p> </section> </section> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="max-width: 100%;margin-bottom: 0px;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section data-role="paragraph" mpa-from-tpl="t" style="max-width: 100%;white-space: normal;border-width: 0px;border-style: none;border-color: initial;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section data-mpa-template="t" mpa-from-tpl="t" style="max-width: 100%;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section data-role="paragraph" mpa-from-tpl="t" style="max-width: 100%;outline: 0px;border-width: 0px;border-style: none;border-color: initial;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;outline: 0px;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;outline: 0px;font-size: 32px;color: rgb(249, 110, 87);overflow-wrap: break-word !important;box-sizing: border-box !important;"></section> </section> </section> </section> </section> </section> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;visibility: visible;"> <img class="rich_pages wxw-img" data-ratio="0.983957219251337" src="/upload/8525b5d387728b74a85f75ffd61b0c99.jpg" data-type="jpeg" data-w="374" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;display: block;visibility: visible !important;width: 374px !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;visibility: visible;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">压测跑起来之后是这个样子的:</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;visibility: visible;"> <img data-type="jpeg" data-ratio="0.1806615776081425" data-w="393" src="/upload/bd73e145172e6538fabecb5fe7550f1f.jpg" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);display: block;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;background-color: rgb(238, 237, 235) !important;background-size: 22px !important;background-position: center center !important;background-repeat: no-repeat !important;height: 72.6387px !important;width: 393px !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;visibility: visible;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">每个请求要在连接池队列里等待33ms,获得连接后执行SQL需要77ms</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">此时数据库的等待事件是这个熊样的:</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.39185750636132316" src="/upload/42e6f0537836ef32418223718bb08fac.jpg" data-type="jpeg" data-w="393" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;display: block;width: 393px !important;visibility: visible !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">各种buffer busy waits,数据库CPU在95%左右(这张图里没截到CPU)</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">接下来,把中间件连接池减到1024(并发什么的都不变),性能数据变成了这样:</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.1590909090909091" src="/upload/3753574e70a8ad756ee397eaae0f1894.jpg" data-type="jpeg" data-w="396" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;height: auto !important;display: block;width: 396px !important;visibility: visible !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">获取链接等待时长没怎么变,但是执行SQL++++++++++++++++++++的耗时减少了。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">下面这张图,上半部分是wait,下半部分是吞吐量</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-type="jpeg" data-ratio="2.7657142857142856" data-w="175" src="/upload/79f92720a3f3f079a2102356741f4ebe.jpg" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;height: auto !important;display: block;width: 175px !important;visibility: visible !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">能看到,中间件连接池从2048减半之后,吐吞量没变,但wait事件减少了一半。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">接下来,把数据库连接池减到96,并发线程数仍然是9600不变。</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.1743295019157088" src="/upload/80e49481661236281897d5a59a6df3ee.jpg" data-type="jpeg" data-w="522" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;height: auto !important;display: block;width: 522px !important;visibility: visible !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">队列平均等待1ms,执行SQL平均耗时2ms。</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="2.206422018348624" src="/upload/6e39879ee0e49d763a10f44c0f97649b.jpg" data-type="jpeg" data-w="218" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;height: auto !important;display: block;width: 218px !important;visibility: visible !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">wait事件几乎没了,吞吐量上升。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">没有调整任何其他东西,仅仅只是缩小了中间件层的数据库连接池,就把请求响应时间从100ms左右缩短到了3ms。</strong></p> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">But why?</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">为什么nginx只用4个线程发挥出的性能就大大超越了100个进程的Apache HTTPD?回想一下计算机科学的基础知识,答案其实是很明显的。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">即使是单核CPU的计算机也能“同时”运行数百个线程。但我们都[应该]知道这只不过是操作系统用时间分片玩的一个小把戏。一颗CPU核心同一时刻只能执行一个线程,然后操作系统切换上下文,核心开始执行另一个线程的代码,以此类推。给定一颗CPU核心,其顺序执行A和B永远比通过时间分片“同时”执行A和B要快,这是一条计算机科学的基本法则。一旦线程的数量超过了CPU核心的数量,再增加线程数系统就只会更慢,而不是更快。这几乎就是真理了……</p> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">有限的资源</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">上面的说法只能说是接近真理,但还并没有这么简单,有一些其他的因素需要加入。当我们寻找数据库的性能瓶颈时,总是可以将其归为三类:CPU、磁盘、网络。把内存加进来也没有错,但比起磁盘和网络,内存的带宽要高出好几个数量级,所以就先不加了。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">如果我们无视磁盘和网络,那么结论就非常简单。在一个8核的服务器上,设定连接/线程数为8能够提供最优的性能,再增加连接数就会因上下文切换的损耗导致性能下降。数据库通常把数据存储在磁盘上,磁盘又通常是由一些旋转着的金属碟片和一个装在步进马达上的读写头组成的。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">读/写头同一时刻只能出现在一个地方,然后它必须“寻址”到另外一个位置来执行另一次读写操作。所以就有了寻址的耗时,此外还有旋回耗时,读写头需要等待碟片上的目标数据“旋转到位”才能进行操作。使用缓存当然是能够提升性能的,但上述原理仍然成立。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">在这一时间段(即"I/O等待")内,线程是在“阻塞”着等待磁盘,此时操作系统可以将那个空闲的CPU核心用于服务其他线程。所以,由于线程总是在I/O上阻塞,我们可以让线程/连接数比CPU核心多一些,这样能够在同样的时间内完成更多的工作。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">那么应该多多少呢?这要取决于磁盘。较新型的SSD不需要寻址,也没有旋转的碟片。可别想当然地认为“SSD速度更快,所以我们应该增加线程数”,恰恰相反,<strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">无需寻址和没有旋回耗时意味着更少的阻塞,所以更少的线程[更接近于CPU核心数]会发挥出更高的性能。只有当阻塞创造了更多的执行机会时,更多的线程数才能发挥出更好的性能。</strong></p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">网络和磁盘类似。通过以太网接口读写数据时也会形成阻塞,10G带宽会比1G带宽的阻塞少一些,1G带宽又会比100M带宽的阻塞少一些。不过网络通常是放在第三位考虑的,有些人会在性能计算中忽略它们。</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.7859375" src="/upload/652eb5daee30413414bf2108cb51e094.jpg" data-type="jpeg" data-w="640" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;display: block;width: 640px !important;visibility: visible !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">上图是PostgreSQL的benchmark数据,可以看到TPS增长率从50个连接数开始变缓。在上面Oracle的视频中,他们把连接数从2048降到了96,实际上96都太高了,除非服务器有16或32颗核心。</p> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">计算公式</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">下面的公式是由PostgreSQL提供的,不过我们认为可以广泛地应用于大多数数据库产品。你应该模拟预期的访问量,并从这一公式开始测试你的应用,寻找最合适的连接数值。</p> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;display: block;overflow: auto;background: rgb(255, 249, 249);"> <p style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;font-size: 16px;color: black;line-height: 26px;">连接数 = ((核心数 * 2) + 有效磁盘数)</p> </blockquote> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">核心数不应包含超线程(hyper thread),即使打开了hyperthreading也是。如果活跃数据全部被缓存了,那么有效磁盘数是0,随着缓存命中率的下降,有效磁盘数逐渐趋近于实际的磁盘数。这一公式作用于SSD时的效果如何尚未有分析。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">按这个公式,你的4核i7数据库服务器的连接池大小应该为((4 * 2) + 1) = 9。取个整就算是是10吧。是不是觉得太小了?跑个性能测试试一下,我们保证它能轻松搞定3000用户以6000TPS的速率并发执行简单查询的场景。如果连接池大小超过10,你会看到响应时长开始增加,TPS开始下降。</p> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;display: block;overflow: auto;background: rgb(255, 249, 249);"> <p style="margin: 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;font-size: 16px;color: black;line-height: 26px;">笔者注:这一公式其实不仅适用于数据库连接池的计算,大部分涉及计算和I/O的程序,线程数的设置都可以参考这一公式。我之前在对一个使用Netty编写的消息收发服务进行压力测试时,最终测出的最佳线程数就刚好是CPU核心数的一倍。</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">公理:你需要一个小连接池,和一个充满了等待连接的线程的队列</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">如果你有10000个并发用户,设置一个10000的连接池基本等于失了智。1000仍然很恐怖。即是100也太多了。你需要一个10来个连接的小连接池,然后让剩下的业务线程都在队列里等待。连接池中的连接数量应该等于你的数据库能够有效同时进行的查询任务数(通常不会高于2*CPU核心数)。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">我们经常见到一些小规模的web应用,应付着大约十来个的并发用户,却使用着一个100连接数的连接池。这会对你的数据库造成极其不必要的负担。</p> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">请注意</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">连接池的大小最终与系统特性相关。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">比如一个混合了长事务和短事务的系统,通常是任何连接池都难以进行调优的。最好的办法是创建两个连接池,一个服务于长事务,一个服务于短事务。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">再例如一个系统执行一个任务队列,只允许一定数量的任务同时执行,此时并发任务数应该去适应连接池连接数,而不是反过来。</p>
作者:微信小助手
<section class="channels_iframe_wrp" data-mpa-powered-by="yiban.io"> <mpvideosnap class="js_uneditable custom_select_card channels_iframe videosnap_video_iframe" data-pluginname="videosnap" data-id="export/UzFfAgtgekIEAQAAAAAAjEQGtobUAAAAAAstQy6ubaLX4KHWvLEZgBPEyKI0EUk-G4j8zNPgMIuboStNG2fE4dn-13QvcMQL" data-url="https://findermp.video.qq.com/251/20304/stodownload?encfilekey=rjD5jyTuFrIpZ2ibE8T7YmwgiahniaXswqzLnDApDFPicLUYFQyMZGibqnl1bouAwflejO2rPfgnedQpM40VjKeeTvt94icBTCdyL1dPI3xicXTw7e9YFtwW4AwLQ&adaptivelytrans=0&bizid=1023&dotrans=0&hy=SH&idx=1&m=&scene=0&token=x5Y29zUxcibCATicExnLmibdjoLluRs3ib2JLEtibwhibSUbviaF2icbjXW06fOsibTHA4OnHXkicJfoMicMmM" data-headimgurl="http://wx.qlogo.cn/finderhead/Q3auHgzwzM5nv7YHhmhvPsGGX04JCIgibK2x2Ru0TOY9HeZTGSIL1KQ/0" data-username="v2_060000231003b20faec8c5e08a1fc3d5c807ec30b07756771265bc6b6234fb9e05062ae69ab4@finder" data-nickname="儒猿IT" data-desc="一步一步带大家理解SpringCloudAlibaba都包含哪些技术组件,在系统里都是用来干什么的,以及这些技术底层的原理。#SpringCloud #SpringCloudAlibaba #Dubbo #Java面试 @微信时刻 " data-nonceid="17087319968872828207" data-type="video" data-width="2048" data-height="1080"></mpvideosnap> </section> <section powered-by="xmyeditor.com" style="margin-bottom: 0px;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" powered-by="xmyeditor.com"> <hr style="border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p style="outline: 0px;color: rgb(34, 34, 34);font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", 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/Y55Wh</span><br></p> <section style="outline: 0px;color: rgb(34, 34, 34);font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", 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;">为什么要用Istio?</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;">部署应用到 Istio</span></p></li> </ul> <p><br></p> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="text-align: center;justify-content: center;margin: 10px 0%;display: flex;flex-flow: row nowrap;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;flex: 0 0 auto;height: auto;border-bottom: 1px solid rgb(126, 169, 195);border-bottom-right-radius: 0px;line-height: 0;align-self: flex-start;box-sizing: border-box;"> <section style="margin: 0px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="letter-spacing: 0px;line-height: 1.8;font-size: 15px;color: rgb(126, 169, 195);padding: 0px 5px;box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;">背景</strong></p> </section> </section> <section style="margin: 0px 0% -3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 5px;height: 5px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 202px;border-style: none;border-color: rgb(62, 62, 62);background-color: rgb(126, 169, 195);box-sizing: border-box;"> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> <p><br></p> <p><span style="font-size: 15px;">大家好,搞微服务也有好几年时间,从 16 年开始就一直关注微服务,到现在一直在使用的还是 SpringCloud 原生那套。</span></p> <p><br></p> <p><span style="font-size: 15px;">虽然后来出现了 SpringCloud Alibaba,但由于前面的所有系统框架都已定,就没有在变化。</span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 15px;">而在微服务的实施过程,为了降运维的服务度,先后使用了 jenkins,docker, kubernetes 等,就还是没有使用过 Istio。</span><span style="font-size: 15px;">基于这个原因,一直想尝试下开发基</span><span style="font-size: 15px;">于 I</span><span style="font-size: 15px;">stio </span><span style="font-size: 15px;">的 ServiceMesh 的应用。</span></p> <p><br></p> <p><span style="font-size: 15px;">正好最近受够了 SpringCloud 的“折磨”,对 Kubernetes 也可以熟练使用了,而且网上几乎没有 SpringBoot 微服务部署到 Istio 的案例,我就开始考虑用 SpringBoot 写个微服务的 Demo 并且部署到 Istio。</span></p> <p><br></p> <p><span style="font-size: 15px;">项目本身不复杂,就是发送一个字符串并且返回一个字符串的最简单的 Demo。</span></p> <p><br></p> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="text-align: center;justify-content: center;margin: 10px 0%;display: flex;flex-flow: row nowrap;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: auto;vertical-align: top;min-width: 10%;max-width: 100%;flex: 0 0 auto;height: auto;border-bottom: 1px solid rgb(126, 169, 195);border-bottom-right-radius: 0px;line-height: 0;align-self: flex-start;box-sizing: border-box;"> <section style="margin: 0px 0%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="letter-spacing: 0px;line-height: 1.8;font-size: 15px;color: rgb(126, 169, 195);padding: 0px 5px;box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;">为什么要用 Istio?</strong></p> </section> </section> <section style="margin: 0px 0% -3px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;width: 5px;height: 5px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 202px;border-style: none;border-color: rgb(62, 62, 62);background-color: rgb(126, 169, 195);box-sizing: border-box;"> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> <p><br></p> <p><span style="font-size: 15px;">目前,对于 Java 技术栈来说,构建微服务的最佳选择是 SpringBoot 而 SpringBoot 一般搭配目前落地案例很多的微服务框架 SpringCloud 来使用。</span></p> <p><br></p> <p><span style="font-size: 15px;">SpringCloud 看似很完美,但是在实际上手开发后,很容易就会发现 SpringCloud 存在以下比较严重的问题。</span></p> <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;">服务治理相关的逻辑存在于 SpringCloud Netflix 等 SDK 中,与业务代码紧密耦合。</span></p></li> <li><p><span style="font-size: 15px;">SDK 对业务代码侵入太大,SDK 发生升级且无法向下兼容时,业务代码必须做出改变以适配 SDK 的升级——即使业务逻辑并没有发生任何变化。</span></p></li> <li><p><span style="font-size: 15px;">各种组件令人眼花缭乱,质量也参差不齐,学习成本太高,且组件之间代码很难完全复用,仅仅为了实现治理逻辑而学习 SDK 也并不是很好的选择。</span></p></li> <li><p><span style="font-size: 15px;">绑定于 Java 技术栈,虽然可以接入其他语言但要手动实现服务治理相关的逻辑,不符合微服务“可以用多种语言进行开发”的原则。</span></p></li> <li><p><span style="font-size: 15px;">SpringCloud 仅仅是一个开发框架,没有实现微服务所必须的服务调度、资源分配等功能,这些需求要借助 Kubernetes 等平台来完成。但 SpringCloud 与 Kubernetes 功能上有重合,且部分功能也存在冲突,二者很难完美配合。</span></p></li> </ul> <p><br></p> <p><span style="font-size: 15px;">替代 SpringCloud 的选择有没有呢?有!它就是 Istio。</span></p> <p><br></p> <p><span style="font-size: 15px;">Istio 彻底把治理逻辑从业务代码中剥离出来,成为了独立的进程(Sidecar)。部署时两者部署在一起,在一个 Pod 里共同运行,业务代码完全感知不到 Sidecar 的存在。</span></p> <p><br></p> <p><span style="font-size: 15px;">这就实现了治理逻辑对业务代码的零侵入——实际上不仅是代码没有侵入,在运行时两者也没有任何的耦合。</span></p> <p><br></p> <p><span style="font-size: 15px;">这使得不同的微服务完全可以使用不同语言、不同技术栈来开发,也不用担心服务治理问题,可以说这是一种很优雅的解决方案了。</span></p> <p><br></p> <p><span style="font-size: 15px;">所以,“为什么要使用 Istio”这个问题也就迎刃而解了——因为 Istio 解决了传统微服务诸如业务逻辑与服务治理逻辑耦合、不能很好地实现跨语言等痛点,而且非常容易使用。只要会用 Kubernetes,学习 Istio 的使用一点都不困难。</span></p> <p><br></p> <h4 data-tool="mdnice编辑器" style="margin: 0px 0px 15px;padding: 0px;outline: 0px;font-weight: 400;font-size: 16px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(34, 34, 34);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;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-style: initial;text-decoration-color: initial;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);line-height: 2em;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;color: rgb(0, 122, 170);">| 为什么要使用 gRPC 作为通信框架?</span></strong></h4> <p><span style="font-size: 15px;">在微服务架构中,服务之间的通信是一个比较大的问题,一般采用 RPC 或者 RESTful API 来实现。</span></p> <p><br></p> <p><span style="font-size: 15px;">SpringBoot 可以使用 RestTemplate 调用远程服务,但这种方式不直观,代码也比较复杂,进行跨语言通信也是个比较大的问题。</span></p> <p><br></p> <p><span style="font-size: 15px;">而 gRPC 相比 Dubbo 等常见的 Java RPC 框架更加轻量,使用起来也很方便,代码可读性高,</span><span style="font-size: 15px;">并且与 </span><span style="font-size: 15px;">Istio 和 </span><span style="font-size: 15px;">K</span><span style="font-size: 15px;">ubernetes 可以很好地进行整合,</span><span style="font-size: 15px;">在 Protobuf 和 HTTP2 的</span><span style="font-size: 15px;">加持下性能也还不错。</span></p> <p><br></p> <p><span style="font-size: 15px;">所以这次选择了 gRPC </span><span style="font-size: 15px;">来解决 Spring</span><span style="font-size: 15px;">Boot </span><span style="font-size: 15px;">微服务间通信的问题。</span><span style="font-size: 15px;">并且,虽然 gRPC 没有服务发现、负载均衡等能力,但是 Istio 在这方面就非常强大,两者形成了完美的互补关系。</span></p> <p><br></p> <p><span style="font-size: 15px;">由于考虑到各种 grpc-spring-boot-starter 可能会对 SpringBoot 与 Istio 的整合产生不可知的副作用。</span></p> <p><br></p> <p><span style="font-size: 15px;">所以这一次我没有用任何的 grpc-spring-boot-starter,而是直接手写了 gRPC 与 SpringBoot 的整合。不想借助第三方框架整合 gRPC 和 Spring Boot 的可以简单参考一下我的实现。</span></p> <p><br></p> <h4 data-tool="mdnice编辑器" style="margin: 0px 0px 15px;padding: 0px;outline: 0px;font-weight: 400;font-size: 16px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(34, 34, 34);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;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-style: initial;text-decoration-color: initial;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);line-height: 2em;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 15px;color: rgb(0, 122, 170);">| 编写业务代码</span></strong></h4> <p><span style="font-size: 15px;">首先使用 Spring Initializr 建立父级项目 spring-boot-istio,并引入 gRPC 的依赖。</span></p> <p><br></p> <section style="margin-bottom: 8px;"> <span style="font-size: 15px;">pom 文件如下:</span> </section> <section> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"><code style="white-space:pre-wrap;overflow-wrap: break-word;margin: 0px 2px;line-height: 18px;font-size: 14px;font-weight: normal;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);overflow-x: auto;padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(91, 218, 237);word-wrap: inherit !important;word-break: inherit !important;"><?xml version="1.0" encoding="UTF-8"?></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">project</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">xmlns</span>=<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"http://maven.apache.org/POM/4.0.0"</span> <br> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">xmlns:xsi</span>=<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"http://www.w3.org/2001/XMLSchema-instance"</span><br> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">xsi:schemaLocation</span>=<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">modelVersion</span>></span>4.0.0<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">modelVersion</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">modules</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">module</span>></span>spring-boot-istio-api<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">module</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">module</span>></span>spring-boot-istio-server<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">module</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">module</span>></span>spring-boot-istio-client<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">module</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">modules</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">parent</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span>org.springframework.boot<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span> <br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span>spring-boot-starter-parent<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span> <br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span>2.2.6.RELEASE<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">relativePath</span>/></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">parent</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span>site.wendev<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span>spring-boot-istio<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span>0.0.1-SNAPSHOT<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">name</span>></span>spring-boot-istio<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">name</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">description</span>></span>Demo project for Spring Boot With Istio.<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">description</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">packaging</span>></span>pom<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">packaging</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">properties</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">java.version</span>></span>1.8<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">java.version</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">properties</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependencyManagement</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependencies</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependency</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span>io.grpc<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span>grpc-all<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span>1.28.1<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependency</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependencies</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependencyManagement</span>></span><br><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">project</span>></span><br></code></pre> </section> <p><br></p> <section style="margin-bottom: 8px;"> <span style="font-size: 15px;">然后建立公共依赖模块 spring-boot-istio-api,pom 文件如下,主要就是 gRPC 的一些依赖:</span> </section> <section> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"><code style="white-space:pre-wrap;overflow-wrap: break-word;margin: 0px 2px;line-height: 18px;font-size: 14px;font-weight: normal;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);overflow-x: auto;padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(91, 218, 237);word-wrap: inherit !important;word-break: inherit !important;"><?xml version="1.0" encoding="UTF-8"?></span><br><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">project</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">xmlns</span>=<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"http://maven.apache.org/POM/4.0.0"</span><br> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">xmlns:xsi</span>=<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"http://www.w3.org/2001/XMLSchema-instance"</span><br> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">xsi:schemaLocation</span>=<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">parent</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span>spring-boot-istio<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span>site.wendev<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span>0.0.1-SNAPSHOT<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">parent</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">modelVersion</span>></span>4.0.0<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">modelVersion</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span>spring-boot-istio-api<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependencies</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependency</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span>io.grpc<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span>grpc-all<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependency</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependency</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span>javax.annotation<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span>javax.annotation-api<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span>1.3.2<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span> <br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependency</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">dependencies</span>></span> <br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">build</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">extensions</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">extension</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span>kr.motd.maven<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">groupId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span>os-maven-plugin<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">artifactId</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"><<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span>1.6.2<span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">version</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">extension</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit !important;"></<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">extensions</span>></span><br> <span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;word-wrap: inherit !important;word-break: inherit
作者:微信小助手
<section data-mpa-powered-by="yiban.io" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;margin-bottom: 0px;"> <section powered-by="xiumi.us" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section powered-by="xiumi.us" style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;visibility: visible;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;visibility: visible;">| 疑虑描述</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">最近,在进行开发的过程中,发现之前的一个写法,类似如下:</p> <p><br></p> </section> </section> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="max-width: 100%;margin-bottom: 0px;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section data-role="paragraph" mpa-from-tpl="t" style="max-width: 100%;white-space: normal;border-width: 0px;border-style: none;border-color: initial;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section data-mpa-template="t" mpa-from-tpl="t" style="max-width: 100%;outline: 0px;color: rgb(0, 0, 0);font-family: PingFangSC-Light;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section data-role="paragraph" mpa-from-tpl="t" style="max-width: 100%;outline: 0px;border-width: 0px;border-style: none;border-color: initial;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="max-width: 100%;outline: 0px;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <section style="margin-right: 8px;margin-left: 8px;max-width: 100%;outline: 0px;font-size: 32px;color: rgb(249, 110, 87);overflow-wrap: break-word !important;box-sizing: border-box !important;"></section> </section> </section> </section> </section> </section> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;visibility: visible;"> <img class="rich_pages wxw-img" data-ratio="1.5036231884057971" src="/upload/352f230a8d9813216a6c9b62db412f1d.png" data-type="png" data-w="552" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;display: block;visibility: visible !important;width: 552px !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;visibility: visible;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;">以我的理解,@Configuration 加 @Bean 会创建一个 userName 不为 null 的 UserManager 对象,而 @Component 也会创建一个 userName 为 null 的 UserManager 对象。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;visibility: visible;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;visibility: visible;">那么我们在其他对象中注入 UserManager 对象时,到底注入的是哪个对象?</strong></p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">因为项目已经上线了很长一段时间了,所以这种写法没有编译报错,运行也没有出问题。后面去找同事了解下,实际是想让:</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.3215686274509804" src="/upload/afbf67a963ee0246214bc6e6ae2fe5be.png" data-type="png" data-w="510" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;display: block;width: 510px !important;visibility: visible !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">生效,而实际也确实是它生效了。那么问题来了:<strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">Spring 容器中到底有几个 UserManager 类型的对象?</strong></p> <h3 data-tool="mdnice编辑器" style="margin: 30px 0px 15px;padding: 0px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">| Spring Boot 版本</strong></h3> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">项目中用的 Spring Boot 版本是:2.0.3.RELEASE。对象的 scope 是默认值,也就是 singleton。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: bold;color: black;">结果验证</strong></p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">验证方式有很多,可以 debug 跟源码,看看 Spring 容器中到底有几个 UserManager 对象,也可以直接从 UserManager 构造方法下手,看看哪几个构造方法被调用,等等。</p> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">我们从构造方法下手,看看 UserManager 到底实例化了几次。</p> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img __bg_gif" data-ratio="0.7272727272727273" src="/upload/39fec46a566ef8966dbdbbc725d2a016.png" data-type="gif" data-w="990" style="margin: 0px auto;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;display: block;width: 677px !important;visibility: visible !important;"> <figcaption style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1px 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 26px;">只有有参构造方法被调用了,无参构造方法岿然不动(根本没被调用)。如果想了解的更深一点,可以读读:Spring 的循环依赖,源码详细分析 → 真的非要三级缓存吗?</p> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-li
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">最近写了一个服务:根据优惠券的类型<code style="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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">resourceType</code>和编码<code style="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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">resourceId</code>来 查询 发放方式grantType和领取规则</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">实现方式:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 根据优惠券类型resourceType -> 确定查询哪个数据表 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 根据编码resourceId -> 到对应的数据表里边查询优惠券的派发方式grantType和领取规则 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">优惠券有多种类型,分别对应了不同的数据库表:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" 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);"> QQ会员 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 外卖会员 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">实际的优惠券远不止这些,这个需求是要我们写一个业务分派的逻辑</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">第一个能想到的思路就是if-else或者switch case:</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;">switch</span>(resourceType){<br> <span style="color: #a626a4;line-height: 26px;">case</span> <span style="color: #50a14f;line-height: 26px;">"红包"</span>: <br> 查询红包的派发方式 <br> <span style="color: #a626a4;line-height: 26px;">break</span>;<br> <span style="color: #a626a4;line-height: 26px;">case</span> <span style="color: #50a14f;line-height: 26px;">"购物券"</span>: <br> 查询购物券的派发方式<br> <span style="color: #a626a4;line-height: 26px;">break</span>;<br> <span style="color: #a626a4;line-height: 26px;">case</span> <span style="color: #50a14f;line-height: 26px;">"QQ会员"</span> :<br> <span style="color: #a626a4;line-height: 26px;">break</span>;<br> <span style="color: #a626a4;line-height: 26px;">case</span> <span style="color: #50a14f;line-height: 26px;">"外卖会员"</span> :<br> <span style="color: #a626a4;line-height: 26px;">break</span>;<br> ......<br> <span style="color: #a626a4;line-height: 26px;">default</span> : logger.info(<span style="color: #50a14f;line-height: 26px;">"查找不到该优惠券类型resourceType以及对应的派发方式"</span>);<br> <span style="color: #a626a4;line-height: 26px;">break</span>;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">如果要这么写的话, 一个方法的代码可就太长了,影响了可读性。(别看着上面case里面只有一句话,但实际情况是有很多行的)</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">而且由于 整个 if-else的代码有很多行,也不方便修改,可维护性低。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><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: 0.8em;margin-bottom: 0.8em;">策略模式是把 if语句里面的逻辑抽出来写成一个类,如果要修改某个逻辑的话,仅修改一个具体的实现类的逻辑即可,可维护性会好不少。</p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.3175925925925926" data-s="300,640" src="/upload/cb0de794f6c82b04fd0fdaf10a63fe7b.png" data-type="png" data-w="1080" style=""></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;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 策略模式 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">策略模式在业务逻辑分派的时候还是if-else</span> ,只是说比第一种思路的if-else 更好维护一点。。。</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;">switch</span>(resourceType){<br> <span style="color: #a626a4;line-height: 26px;">case</span> <span style="color: #50a14f;line-height: 26px;">"红包"</span>: <br> String grantType=<span style="color: #a626a4;line-height: 26px;">new</span> Context(<span style="color: #a626a4;line-height: 26px;">new</span> RedPaper()).ContextInterface();<br> <span style="color: #a626a4;line-height: 26px;">break</span>;<br> <span style="color: #a626a4;line-height: 26px;">case</span> <span style="color: #50a14f;line-height: 26px;">"购物券"</span>: <br> String grantType=<span style="color: #a626a4;line-height: 26px;">new</span> Context(<span style="color: #a626a4;line-height: 26px;">new</span> Shopping()).ContextInterface();<br> <span style="color: #a626a4;line-height: 26px;">break</span>;<br> <br> ......<br> <span style="color: #a626a4;line-height: 26px;">default</span> : logger.info(<span style="color: #50a14f;line-height: 26px;">"查找不到该优惠券类型resourceType以及对应的派发方式"</span>);<br> <span style="color: #a626a4;line-height: 26px;">break</span>;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">但缺点也明显:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" 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: 0.8em;margin-bottom: 0.8em;">如果 if-else的判断情况很多,那么对应的具体策略实现类也会很多,上边的具体的策略实现类还只是2个,查询红包发放方式写在类RedPaper里边,购物券写在另一个类Shopping里边;那资源类型多个QQ会员和外卖会员,不就得再多写两个类?有点麻烦了</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: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">没法俯视整个分派的业务逻辑</span></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="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);display: inline-block;padding-left: 10px;border-left: 5px solid rgb(248, 57, 41);">Map+函数式接口</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">用上了Java8的新特性lambda表达式</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 判断条件放在key中 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 对应的业务逻辑放在value中 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这样子写的好处是非常直观,能直接看到<span style="font-weight: 700;color: rgb(248, 57, 41);">判断条件对应的业务逻辑</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">需求:根据优惠券(资源)类型 <span style="font-weight: 700;color: rgb(248, 57, 41);">resourceType</span> 和编码 <span style="font-weight: 700;color: rgb(248, 57, 41);">resourceId</span> 查询派发方式<span style="font-weight: 700;color: rgb(248, 57, 41);">grantType</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">上代码:</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;">@Service</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">QueryGrantTypeService</span> </span>{<br> <br> <span style="color: #4078f2;line-height: 26px;">@Autowired</span><br> <span style="color: #a626a4;line-height: 26px;">private</span> GrantTypeSerive grantTypeSerive;<br> <span style="color: #a626a4;line-height: 26px;">private</span> Map<String, Function<String,String>> grantTypeMap=<span style="color: #a626a4;line-height: 26px;">new</span> HashMap<>();<br><br> <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">/**<br> * 初始化业务分派逻辑,代替了if-else部分<br> * key: 优惠券类型<br> * value: lambda表达式,最终会获得该优惠券的发放方式<br> */</span><br> <span style="color: #4078f2;line-height: 26px;">@PostConstruct</span><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">dispatcherInit</span><span style="line-height: 26px;">()</span></span>{<br> grantTypeMap.put(<span style="color: #50a14f;line-height: 26px;">"红包"</span>,resourceId->grantTypeSerive.redPaper(resourceId));<br> grantTypeMap.put(<span style="color: #50a14f;line-height: 26px;">"购物券"</span>,resourceId->grantTypeSerive.shopping(resourceId));<br> grantTypeMap.put(<span style="color: #50a14f;line-height: 26px;">"qq会员"</span>,resourceId->grantTypeSerive.QQVip(resourceId));<br> }<br> <br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> String <span style="color: #4078f2;line-height: 26px;">getResult</span><span style="line-height: 26px;">(String resourceType)</span></span>{<br> <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//Controller根据 优惠券类型resourceType、编码resourceId 去查询 发放方式grantType</span><br> Function<String,String> result=getGrantTypeMap.get(resourceType);<br> <span style="color: #a626a4;line-height: 26px;">if</span>(result!=<span style="color: #a626a4;line-height: 26px;">null</span>){<br> <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//传入resourceId 执行这段表达式获得String型的grantType</span><br> <span style="color: #a626a4;line-height: 26px;">return</span> result.apply(resourceId);<br> }<br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #50a14f;line-height: 26px;">"查询不到该优惠券的发放方式"</span>;<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">如果单个 if 语句块的业务逻辑有很多行的话,我们可以把这些 业务操作抽出来,写成一个单独的Service,即:</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: #a0a1a7;font-style: italic;line-height: 26px;">//具体的逻辑操作</span><br><br><span style="color: #4078f2;line-height: 26px;">@Service</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">GrantTypeSerive</span> </span>{<br><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> String <span style="color: #4078f2;line-height: 26px;">redPaper</span><span style="line-height: 26px;">(String resourceId)</span></span>{<br> <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//红包的发放方式</span><br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #50a14f;line-height: 26px;">"每周末9点发放"</span>;<br> }<br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> String <span style="color: #4078f2;line-height: 26px;">shopping</span><span style="line-height: 26px;">(String resourceId)</span></span>{<br> <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//购物券的发放方式</span><br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #50a14f;line-height: 26px;">"每周三9点发放"</span>;<br> }<br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> String <span style="color: #4078f2;line-height: 26px;">QQVip</span><span style="line-height: 26px;">(String resourceId)</span></span>{<br> <span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//qq会员的发放方式</span><br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #50a14f;line-height: 26px;">"每周一0点开始秒杀"</span>;<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">入参 <code style="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: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">String resourceId</code>是用来查数据库的,这里简化了,传参之后不做处理。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">用http调用的结果:</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;">@RestController</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">GrantTypeController</span> </span>{<br><br> <span style="color: #4078f2;line-height: 26px;">@Autowired</span><br> <span style="color: #a626a4;line-height: 26px;">private</span> QueryGrantTypeService queryGrantTypeService;<br><br> <span style="color: #4078f2;line-height: 26px;">@PostMapping</span>(<span style="color: #50a14f;line-height: 26px;">"/grantType"</span>)<br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> String <span style="color: #4078f2;line-height: 26px;">test</span><span style="line-height: 26px;">(String resourceName)</span></span>{<br> <span style="color: #a626a4;line-height: 26px;">return</span> queryGrantTypeService.getResult(resourceName);<br> }<br>}<br></code></pre> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.33611111111111114" data-s="300,640" src="/upload/1daff377e7419c47a0729c055db12700.png" data-type="png" data-w="1080" style=""></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;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> http调用的结果 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">用Map+函数式接口也有弊端:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">你的队友得会lambda表达式才行啊,当然他不会的让他自己百度去!</p> </section>
作者:微信小助手
<section style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"> <br> </section> <h1 data-tool="mdnice编辑器" style="margin: 0px 0px 4px;padding: 16px 0px 10px;outline: 0px;font-weight: bold;font-size: 2.1em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.1em;border-bottom: 1px solid rgb(201, 152, 51);text-align: justify;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;color: rgb(81, 81, 81);visibility: visible;font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;">一、首先我们要了解 Websocket 握手的原理</span></h1> <figure data-tool="mdnice编辑器" style="margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5540752351097179" src="/upload/77e6db4bfe814e34a077c2db284885d.png" data-type="png" data-w="1276" style="margin: 0px auto 15px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;vertical-align: bottom;height: auto !important;border-radius: 5px;display: block;width: 558px !important;visibility: visible !important;"> </figure> <h2 data-tool="mdnice编辑器" style="margin: 8px 0px 35px;padding: 0px;outline: 0px;font-weight: bold;font-size: 22px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.5em;text-align: justify;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin: 0px 3px 0px 0px;padding: 2px 13px;outline: 0px;max-width: 100%;display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);height: 33px;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">请求头特征</span></h2> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> HTTP 必须是 1.1 GET 请求 </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> HTTP Header 中 Connection 字段的值必须为 Upgrade </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> HTTP Header 中 Upgrade 字段必须为 websocket </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> Sec-WebSocket-Key 字段的值是采用 base64 编码的随机 16 字节字符串 </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> Sec-WebSocket-Protocol 字段的值记录使用的子协议,比如 binary base64 </section></li> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="margin: 5px 0px 0px;padding: 0px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;box-sizing: border-box !important;overflow-wrap: break-word !important;">Origin 表示请求来源</p></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"></ul> <h2 data-tool="mdnice编辑器" style="margin: 24px 0px 35px;padding: 0px;outline: 0px;font-weight: bold;font-size: 22px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.5em;text-align: justify;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin: 0px 3px 0px 0px;padding: 2px 13px;outline: 0px;max-width: 100%;display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);height: 33px;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">响应头特征</span></h2> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> 状态码是 101 表示 Switching Protocols </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> Upgrade / Connection / Sec-WebSocket-Protocol 和请求头一致 </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> Sec-WebSocket-Accept 是通过请求头的 Sec-WebSocket-Key 生成 </section></li> </ul> <h1 data-tool="mdnice编辑器" style="margin: 30px 0px 8px;padding: 16px 0px 10px;outline: 0px;font-weight: bold;font-size: 2.1em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.1em;border-bottom: 1px solid rgb(201, 152, 51);text-align: justify;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;color: rgb(81, 81, 81);font-size: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;">二、短连接轮询、长连接、Websocket 横向对比</span></h1> <h2 data-tool="mdnice编辑器" style="margin: 24px 0px 16px;padding: 0px;outline: 0px;font-weight: bold;font-size: 22px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.5em;text-align: justify;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin: 0px 3px 0px 0px;padding: 2px 13px;outline: 0px;max-width: 100%;display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);height: 33px;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. 短连接轮询</span></h2> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> 很耗费 TCP 连接 </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> 而且 Header 重复发送 </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> 且通过宏任务发起,受限于 Event Loop,无法保证及时性 </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> 同时无效请求会很多 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin: 24px 0px 35px;padding: 0px;outline: 0px;font-weight: bold;font-size: 22px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.5em;text-align: justify;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin: 0px 3px 0px 0px;padding: 2px 13px;outline: 0px;max-width: 100%;display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);height: 33px;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. 长连接</span></h2> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> HTTP keep-alive 开启后虽然 TCP 可以复用,但是 Header 重复的问题并没有解决 </section></li> </ul> <ul data-tool="mdnice编辑器" class="list-paddingleft-1" style="margin: 8px 0px;padding: 0px 0px 0px 25px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: 557.438px;"> <li style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 5px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;line-height: 26px;color: rgb(1, 1, 1);text-align: justify;"> 同时 HTTP keep-alive 还有一个有效期,有效期结束后服务端会发侦查帧探查 TCP 是否有效 </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(255, 177, 27);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgb(255, 245, 227);"> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);text-align: justify;">题外话:</p> </blockquote> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(255, 177, 27);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgb(255, 245, 227);"> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);text-align: justify;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;">HTTP keep-alive 的作用是,告知服务端持久化当前的</strong> <strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;">TCP</strong> <strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: black;">连接,不要立即断开,以便后续的 HTTP 请求复用它,也就是我们所说的「长连接」</strong></p> </blockquote> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;padding: 10px 10px 10px 20px;outline: 0px;border-left: 3px solid rgb(255, 177, 27);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgb(255, 245, 227);"> <p style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);text-align: justify;">HTTP 的 keep-alive 是为了让 TCP 活久一点,而 TCP
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="color: black;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-size: 16px;padding: 10px;font-family: Optima-Regular, Optima, PingFangSC-regular, PingFangTC-regular, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">我们应该从 Redis 是如何保存数据的原理展开,分析键值对的存储结构和原理。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">从而继续延展出每种数据类型底层的数据结构,针对不同场景使用更恰当的数据结构和编码实现更少的内存占用。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">为了保存数据, Redis 需要先申请内存,数据过期或者内存淘汰需要回收内存,从而拓展出内存碎片优化。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">最后,说下 key、value 使用规范和技巧、 Bitmap 等高阶数据类型,运用这些技巧巧妙解决有限内存去存储更多数据难题……</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这一套组合拳下来直接封神。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">具体详情,且看「码哥」一一道来。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">主要优化神技如下:</p> <ul data-tool="mdnice编辑器" style="list-style-type: disc;font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: #ffbf52;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> 键值对优化; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> 小数据集合的编码优化; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> 使用对象共享池; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> 使用 Bit 比特位或 byte 级别操作 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> 使用 hash 类型优化; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> 内存碎片优化; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> 使用 32 位的 Redis。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">在优化之前,我们先掌握 Redis 是如何存储数据的。</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 0px 0px 0px;"><span style="font-size: 20px;color: #f48a00;display: inline-block;padding-left: 10px;border-left: 8px solid #ffbf52;">Redis 如何存储键值对</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">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: #f48a00;">redisDb</code>为中心存储,redis 7.0 源码在 <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: #f48a00;">https://github.com/redis/redis/blob/7.0/src/server.h</code>:</p> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.38470873786407767" src="/upload/e7c18b4b90d6ac6cd2687bba422a619d.png" data-type="png" data-w="1648" style="max-width: 100%;border-radius: 5px 5px 5px 5px;display: block;margin: 0px 10px auto;width: 100%;height: 100%;object-fit: contain;"> <figcaption style="margin-top: 5px;display: block;font-size: 13px;color: rgba(0,0,0,0.55);text-align: right;font-family: PingFangSC-Light;"> redisDb </figcaption> </figure> <ul data-tool="mdnice编辑器" style="list-style-type: disc;font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: #ffbf52;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">dict:</strong>最重要的属性之一,就是靠这个定义了保存了对象数据键值对,dcit 的底层结构是一个哈希表。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">expires:</strong>保存着所有 key 的过期信息. </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> blocking_keys 和 ready_keys 主要为了 <em style="font-style: italic;color: rgba(0, 0, 0, 0.85);letter-spacing: 0.1em;">实现 BLPOP 等阻塞命令</em> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> watched_keys用于实现watch命令, <em style="font-style: italic;color: rgba(0, 0, 0, 0.85);letter-spacing: 0.1em;">记录正在被watch的一些key</em>,与事务相关。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> id 为 <em style="font-style: italic;color: rgba(0, 0, 0, 0.85);letter-spacing: 0.1em;">当前数据库的id</em>,redis 支持单个服务多数据库,默认有16个; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> clusterSlotToKeyMapping:cluster 模式下,存储key 与哈希槽映射关系的数组。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">Redis 使用「dict」结构来保存所有的键值对(key-value)数据,这是一个全局哈希表,所以对 key 的查询能以 O(1) 时间得到。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">所谓哈希表,我们可以类比 Java 中的 <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: #f48a00;">HashMap</code>,其实就是一个数组,数组的每个元素叫做哈希桶。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">dict 结构如下,源码在 <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: #f48a00;">https://github.com/redis/redis/blob/7.0/src/dict.h</code>:</strong></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">struct</span> <span style="font-weight: bold;color: white;line-height: 26px;">dict</span> {</span><br> <span style="color: #75715e;line-height: 26px;">// 特定类型的处理函数</span><br> dictType *type;<br> <span style="color: #75715e;line-height: 26px;">// 两个全局哈希表指针数组,与渐进式 rehash 有关</span><br> dictEntry **ht_table[<span style="line-height: 26px;">2</span>];<br> <span style="color: #75715e;line-height: 26px;">// 记录 dict 中现有的数据个数。</span><br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">unsigned</span> <span style="color: #f92672;font-weight: bold;line-height: 26px;">long</span> ht_used[<span style="line-height: 26px;">2</span>];<br> <span style="color: #75715e;line-height: 26px;">// 记录渐进式 rehash 进度的标志, -1 表示当前没有执行 rehash </span><br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">long</span> rehashidx;<br><br> <span style="color: #75715e;line-height: 26px;">// 小于 0 表示 rehash 暂停</span><br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">int16_t</span> pauserehash;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">signed</span> <span style="color: #f92672;font-weight: bold;line-height: 26px;">char</span> ht_size_exp[<span style="line-height: 26px;">2</span>];<br>};<br></code></pre> <ul data-tool="mdnice编辑器" style="list-style-type: disc;font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: #ffbf52;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> dictType:存储了hash函数,key和value的复制等函数; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> ht_table:长度为 2 的 数组,正常情况使用 ht_table[0] 存储数据,当执行 rehash 的时候,使用 ht_table[1] 配合完成 。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">key 的哈希值最终会映射到 ht_table 的一个位置,如果发生哈希冲突,则拉出一个哈希链表。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">大家重点关注 <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: #f48a00;">dictEntry</code> 类型的 ht_table,ht_table 数组每个位置我们也叫做<strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">哈希桶</strong>,就是这玩意保存了所有键值对。</p> <blockquote data-tool="mdnice编辑器" style="display: block;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;font-weight: 400;border-radius: 5px;font-style: normal;text-align: left;box-sizing: inherit;border-width: 1px;border-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;margin: 0px;line-height: 26px;margin-top: -15px;color: rgb(0,0,0,0.85);">码哥,Redis 支持那么多的数据类型,哈希桶咋保存?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">哈希桶的每个元素的结构由 dictEntry 定义:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">typedef</span> <span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">struct</span> <span style="font-weight: bold;color: white;line-height: 26px;">dictEntry</span> {</span><br> <span style="color: #75715e;line-height: 26px;">// 指向 key 的指针</span><br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span> *key;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">union</span> {<br> <span style="color: #75715e;line-height: 26px;">// 指向实际 value 的指针</span><br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span> *val;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">uint64_t</span> u64;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">int64_t</span> s64;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">double</span> d;<br> } v;<br> <span style="color: #75715e;line-height: 26px;">// 哈希冲突拉出的链表</span><br> <span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">struct</span> <span style="font-weight: bold;color: white;line-height: 26px;">dictEntry</span> *<span style="font-weight: bold;color: white;line-height: 26px;">next</span>;</span><br>} dictEntry;<br></code></pre> <ul data-tool="mdnice编辑器" style="list-style-type: disc;font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: #ffbf52;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> key 指向键值对的键的指针,key 都是 string 类型。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> <em style="font-style: italic;color: rgba(0, 0, 0, 0.85);letter-spacing: 0.1em;">value</em> 是个 union(联合体)当它的值是 uint64_t、int64_t 或 double 类型时,就不再需要额外的存储,这有利于减少内存碎片。(为了节省内存操碎了心)当然, <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">val 也可以是 void 指针,指向值的指针,以便能存储任何类型的数据。</strong> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> <em style="font-style: italic;color: rgba(0, 0, 0, 0.85);letter-spacing: 0.1em;">next</em> 指向另一个 dictEntry 结构, 多个 dictEntry 可以通过 next 指针串连成链表, 从这里可以看出, ht_table 使用链地址法来处理键碰撞: <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">当多个不同的键拥有相同的哈希值时,哈希表用一个链表将这些键连接起来。</strong> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">哈希桶并没有保存值本身,而是指向具体值的指针,从而实现了哈希桶能存不同数据类型的需求</strong>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">而哈希桶中,键值对的值都是由一个叫做 <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: #f48a00;">redisObject</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: #f48a00;">https://github.com/redis/redis/blob/7.0/src/server.h</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;"><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">typedef</span> <span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">struct</span> <span style="font-weight: bold;color: white;line-height: 26px;">redisObject</span> {</span><br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">unsigned</span> type:<span style="line-height: 26px;">4</span>;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">unsigned</span> encoding:<span style="line-height: 26px;">4</span>;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">unsigned</span> lru:LRU_BITS;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">int</span> refcount;<br> <span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span> *ptr;<br>} robj;<br></code></pre> <ul data-tool="mdnice编辑器" style="list-style-type: disc;font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: #ffbf52;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">type</strong>:记录了对象的类型,string、set、hash 、Lis、Sorted Set 等,根据该类型才可以确定是哪种数据类型,使用什么样的 API 操作。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">encoding</strong>:编码方式, <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">表示 ptr 指向的数据类型具体数据结构,即这个对象使用了什么数据结构作为底层实现</strong>保存数据。 <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">同一个对象使用不同编码实现内存占用存在明显差异,内部编码对内存优化非常重要。</strong> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> lru:LRU_BITS:LRU 策略下对象最后一次被访问的时间,如果是 LFU 策略,那么低 8 位表示访问频率,高 16 位表示访问时间。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> refcount :表示引用计数,由于 C 语言并不具备内存回收功能,所以 Redis 在自己的对象系统中添加了这个属性,当一个对象的引用计数为 0 时,则表示该对象已经不被任何对象引用,则可以进行垃圾回收了。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;letter-spacing: 0.1em;word-spacing: 0.1em;font-size: 15px;color: rgb(0,0,0,0.55);"> ptr 指针:指向对象的底层实现数据结构,指向 <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">值的指针</strong>。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">如下图是由 redisDb、dict、dictEntry、redisObejct 关系图:</p> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5667144906743186" src="/upload/c291c989074107b62b01f9d26696f356.png" data-type="png" data-w="1394" style="max-width: 100%;border-radius: 5px 5px 5px 5px;display: block;margin: 0px 10px auto;width: 100%;height: 100%;object-fit: contain;"> <figcaption style="margin-top: 5px;display: block;font-size: 13px;color: rgba(0,0,0,0.55);text-align: right;font-family: PingFangSC-Light;"> redis存储结构 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">「码哥」再唠叨几句,void *key 和 void *value 指针指向的是 <strong style="font-weight: bold;color: rgba(0, 0, 0, 0.85);">redisObject</strong>,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: #f48a00;">redisObject</code> 表示。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">知道了 Redis 存储原理以及不同数据类型的存储数据结构后,我们继续看如何做性能优化。</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 0px 0px 0px;"><span style="font-size: 20px;color: #f48a00;display: inline-block;padding-left: 10px;border-left: 8px solid #ffbf52;">1. 键值对优化</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 5px 0px;line-height: 1.75;letter-spacing
作者:微信小助手
<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, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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="line-height: 1.75;margin: 0em 0px;font-size: 15px;color: rgb(53, 53, 53);word-break: break-word;overflow-wrap: break-word;text-align: left;padding: 0px;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;">你好,我是悟空。</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;"> <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;">最近在搭一个基础版的项目框架,基于 SpringCloud 微服务框架。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">如果把 SpringCloud 这个框架当做 <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);">1</code>,那么现在已经有的基础组件比如 swagger/logback 等等就是 <span style="color: rgb(255, 104, 39);"><span style="color: rgb(255, 93, 108);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 14px;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;background-color: rgba(27, 31, 35, 0.05);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">0.5</span></span> <span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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>然后我在这 <span style="color: rgb(255, 93, 108);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 14px;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;background-color: rgba(27, 31, 35, 0.05);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">1.5</span> <span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;">为什么要造<span style="color: rgb(255, 104, 39);">二代轮子</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;">因为项目组不允许用外部的现成框架,比如 Ruoyi。另外因为我们的项目需求具有自身的特色,技术选型也会选择我们自己熟悉的框架,所以自己来造二代轮子也是一个不错的选择。</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: 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;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">多个微服务模块拆分,抽取出一个 demo 微服务模块供扩展,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">提取核心框架模块,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">注册中心 Eureka,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">远程调用 OpenFeign,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">日志 logback,包含 traceId 跟踪,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">Swagger API 文档,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">配置文件共享,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">日志检索,ELK Stack,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">自定义 Starter,待定</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">整合缓存 Redis,Redis 哨兵高可用,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">整合数据库 MySQL,MySQL 高可用,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">整合 MyBatis-Plus,已完成</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">链路追踪组件,待定</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">监控,待定</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">工具类,待开发</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">网关,技术选型待定</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">审计日志进入 ES,待定</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">分布式文件系统,待定</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">定时任务,待定</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">等等</p> </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;"><span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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> </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></h2> <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> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(255, 177, 27);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;margin: 0px;color: black;line-height: 26px;">一个请求调用,假设会调用后端十几个方法,打印十几次日志,无法将这些日志串联起来。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">如下图所示:客户端调用订单服务,订单服务中方法 A 调用方法 B,方法 B 调用方法 C。</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 打印第一条日志和第五条日志,方法 B 打印第二条日志,方法 C 打印第三条日志和第四条日志,但是这 5 条日志并没有任何联系,唯一的联系就是时间是按照时间循序打印的,但是如果有其他并发的请求调用,则会干扰日志的连续性。</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.9289667896678967" src="/upload/4dd94a807394e1dfa665ba1741f6d5ec.png" data-type="png" data-w="1084" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">痛点二:跨服务的日志如何进行关联</span><span style="display: none;"></span></h3> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(255, 177, 27);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;margin: 0px;color: black;line-height: 26px;">每个微服务都会记录自己这个进程的日志,跨进程的日志如何进行关联?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">如下图所示:订单服务和优惠券服务属于两个微服务,部署在两台机器上,订单服务的 A 方法远程调用优惠券服务的 D 方法。</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 将日志打印到日志文件 1 中,记录了 5 条日志,方法 D 将日志打印到日志文件 2 中,记录了 5 条日志。但是这 10 条日志是无法关联起来的。</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.8513761467889909" src="/upload/7dc57b0fc2d5e5838167973e7c799773.png" data-type="png" data-w="1090" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">痛点三:跨线程的日志如何关联</span><span style="display: none;"></span></h3> <blockquote data-tool="mdnice编辑器" style="margin: 20px 0px;border-top: none;border-right: none;border-bottom: none;display: block;font-size: 0.9em;overflow: auto;border-left: 3px solid rgb(255, 177, 27);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;background: rgb(255, 245, 227);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;margin: 0px;color: black;line-height: 26px;">主线程和子线程的日志如何关联?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">如下图所示:主线程的方法 A 启动了一个子线程,子线程执行方法 E。</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 打印了第一条日志,子线程 E 打印了第二条日志和第三条日志。</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.7695852534562212" src="/upload/2a126dcd86b748e3073fdbbacb01d722.png" data-type="png" data-w="1085" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">痛点四:第三方调用我们的服务,如何追踪?</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> <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></h3> <h2 data-tool="mdnice编辑器" style="margin: 20px 10px 0px 0px;padding: 0px;font-weight: bold;font-size: 22px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: 0.8px;orphans: 2;text-align: left;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: black;"><span style="margin: 0px;padding: 0px 0px 0px 10px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 18px;font-weight: 700;color: rgb(34, 34, 34);display: inline-block;border-left: 5px solid rgb(248, 57, 41);">二、方案</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="font-size: 16px;color: #222;">1.1 解决方案</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;">① 使用 Skywalking traceId 进行链路追踪</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">② 使用 Elastic APM 的 traceId 进行链路追踪</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">③ MDC 方案:自己生成 traceId 并 put 到 MDC 里面。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">项目初期,先不引入过多的中间件,用简单可行的方案先尝试,所以这里用第三种方案 MDC。</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.2 MDC 方案</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;">MDC(Mapped Diagnostic Context)用于存储运行上下文的特定线程的上下文数据。因此,如果使用 log4j 进行日志记录,则每个线程都可以拥有自己的MDC,该 MDC 对整个线程是全局的。属于该线程的任何代码都可以轻松访问线程的 MDC 中存在的值。</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> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2.1 追踪一个请求的多条日志</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> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;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" data-ratio="1.2840073529411764" src="/upload/c31c88cfd4d4e01133a6537bae3473f6.png" data-type="png" data-w="1088" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;font-weight: 500;color: #353535;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">(1)在 logback 日志配置文件中的日志格式中添加 %X{traceId} 配置。</p> <pre 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;display: -webkit-box;-webkit-overflow-scrolling: touch;font-size: 14px;word-wrap: break-word;padding: 2px 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);padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;"><<span style="color: #e06c75;line-height: 26px;">pattern</span>></span>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %X{traceId} %-5level %logger - %msg%n<span style="line-height: 26px;"></<span style="color: #e06c75;line-height: 26px;">pattern</span>></span><br></code></pre> </section> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">(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);">header</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);">traceId</code> ,如果存在则放到 MDC 中,否则直接用 UUID 当做 traceId,然后放到 MDC 中。</p> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">(3)配置拦截器。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">当我们打印日志的时候,会自动打印 traceId,如下所示,多条日志的 traceId 相同。</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.29731993299832493" src="/upload/41dbee9b0af06966ca924af93fece665.png" data-type="png" data-w="1194" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">示例代码</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("https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLuuibODqFs5MjmrCCh5nObRebyWjMHTP06Jib9VicBfP0JgW7iciavkSSuiaQbWlMaSL3am8UQFk49YCT4WWOmt1EnbC/640?wx_fmt=svg") 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;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br> * <span style="color: #c678dd;line-height: 26px;">@author</span> www.passjava.cn,公众号:悟空聊架构<br> * <span style="color: #c678dd;line-height: 26px;">@date</span> 2022-07-05 <br> */</span><br><span style="color: #61aeee;line-height: 26px;">@Service</span><br><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">LogInterceptor</span> <span style="color: #c678dd;line-height: 26px;">extends</span> <span style="color: #e6c07b;line-height: 26px;">HandlerInterceptorAdapter</span> </span>{<br><br> <span style="color: #c678dd;line-height: 26px;">private</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">final</span> String TRACE_ID = <span style="color: #98c379;line-height: 26px;">"traceId"</span>;<br><br> <span style="color: #61aeee;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">boolean</span> <span style="color: #61aeee;line-height: 26px;">preHandle</span><span style="line-height: 26px;">(HttpServletRequest request, HttpServletResponse response, Object handler)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br> String traceId = request.getHeader(TRACE_ID);<br> <span style="color: #c678dd;line-height: 26px;">if</span> (StringUtils.isEmpty(traceId)) {<br> MDC.put(<span style="color: #98c379;line-height: 26px;">"traceId"</span>, UUID.randomUUID().toString());<br> } <span style="color: #c678dd;line-height: 26px;">else</span> {<br> MDC.put(TRACE_ID, traceId);<br> }<br><br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">true</span>;<br> }<br><br> <span style="color: #61aeee;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">postHandle</span><span style="line-height: 26px;">(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)</span> <span style="color: #c678dd;line-height: 26px;">throws</span> Exception </span>{<br> <span style="color: #5c6370;font-style: italic;line-height: 26px;">//防止内存泄露</span><br> MDC.remove(<span style="color: #98c379;line-height: 26px;">"traceId"</span>);<br> }<br>}<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;">配置拦截器:</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("https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLuuibODqFs5MjmrCCh5nObRebyWjMHTP06Jib9VicBfP0JgW7iciavkSSuiaQbWlMaSL3am8UQFk49YCT4WWOmt1EnbC/640?wx_fmt=svg") 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;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br> * <span style="color: #c678dd;line-height: 26px;">@author</span> www.passjava.cn,公众号:悟空聊架构<br> * <span style="color: #c678dd;line-height: 26px;">@date</span> 2022-07-05 <br> */</span><br><span style="color: #61aeee;line-height: 26px;">@Configuration</span><br><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">InterceptorConfig</span> <span style="color: #c678dd;line-height: 26px;">implements</span> <span style="color: #e6c07b;line-height: 26px;">WebMvcConfigurer</span> </span>{<br><br> <span style="color: #61aeee;line-height: 26px;">@Resource</span><br> <span style="color: #c678dd;line-height: 26px;">private</span> LogInterceptor logInterceptor;<br><br> <span style="color: #61aeee;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">addInterceptors</span><span style="line-height: 26px;">(InterceptorRegistry registry)</span> </span>{<br> registry.addInterceptor(logInterceptor).addPathPatterns(<span style="color: #98c379;line-height: 26px;">"/**"</span>);<br> }<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;">2.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;">解决方案的原理图如下所示:</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.0876565295169947" src="/upload/be093772b28e3d8122c0a1283d6fe7e6.png" data-type="png" data-w="1118" 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: 0em 0;font-size: 15px;color: #353535;">订单服务远程调用优惠券服务,需要在订单服务中添加 OpenFeign 的拦截器,拦截器里面做的事就是往 请求的 header 中添加 traceId,这样调用到优惠券服务时,就能从 header 中拿到这次请求的 traceId。</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> <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("https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLuuibODqFs5MjmrCCh5nObRebyWjMHTP06Jib9VicBfP0JgW7iciavkSSuiaQbWlMaSL3am8UQFk49YCT4WWOmt1EnbC/640?wx_fmt=svg") 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;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br> * <span style="color: #c678dd;line-height: 26px;">@author</span> www.passjava.cn,公众号:悟空聊架构<br> * <span style="color: #c678dd;line-height: 26px;">@date</span> 2022-07-05 <br> */</span><br><span style="color: #61aeee;line-height: 26px;">@Configuration</span><br><span style="color: #c678dd;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">FeignInterceptor</span> <span style="color: #c678dd;line-height: 26px;">implements</span> <span style="color: #e6c07b;line-height: 26px;">RequestInterceptor</span> </span>{<br> <span style="color: #c678dd;line-height: 26px;">private</span> <span style="color: #c678dd;line-height: 26px;">static</span> <span style="color: #c678dd;line-height: 26px;">final</span> String TRACE_ID = <span style="color: #98c379;line-height: 26px;">"traceId"</span>;<br><br> <span style="color: #61aeee;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span> <span style="color: #c678dd;line-height: 26px;">void</span> <span style="color: #61aeee;line-height: 26px;">apply</span><span style="line-height: 26px;">(RequestTemplate requestTemplate)</span> </span>{<br> requestTemplate.header(TRACE_ID, (String) MDC.get(TRACE_ID));<br> }<br>}<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;">两个微服务打印的日志中,两条日志的 traceId 一致。</p> <p style="text-align: center;margin-bottom: 0em;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.2046728971962617" data-s="300,640" src="/upload/c85599d01dcd3e29720b13911ad7bdc2.png" data-type="png" data-w="1070" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">当然这些日志都会导入到 Elasticsearch 中的,然后通过 kibana 可视化界面搜索 traceId,就可以将整个调用链路串起来了!</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></h3> <h2 data-tool="mdnice编辑器" style="margin: 20px 10px 0px 0px;padding: 0px;font-weight: bold;font-size: 22px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: 0.8px;orphans: 2;text-align: left;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: black;"><span style="margin: 0px;padding: 0px 0px 0px 10px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 18px;font-weight: 700;color: rgb(34, 34, 34);display: inline-block;border-left: 5px solid rgb(248, 57, 41);">四、总结</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 20px;"><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: 0em 0;font-size: 15px;color: #353535;">本篇通过拦截器、MDC 功能,全链路加入了 traceId,然后将 traceId 输出到日志中,就可以通过日志来追踪调用链路。不论是进程内的方法级调用,还是跨进程间的服务调用,都可以进行追踪。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin: 0em 0;font-size: 15px;color: #353535;">另外日志还需要通过 ELK Stack 技术将日志导入到 Elasticsearch 中,然后就可以通过检索 traceId,将整个调用链路检索出来了。</p> </section> <section 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-bottom: 20px; background-color: rgb(255, 255, 255); color: rgb(0, 0, 0); font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif; font-size: 16px; white-space: normal; word-spacing: 0.8px; letter-spacing: 0.75px; text-align: center; visibility: visible;" class="js_darkmode__6" 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-bottom: 20px;white-space: normal;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);font-size: 16px;word-spacing: 0.8px;text-align: center;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span data-darkmode-color-15906764299112="rgb(178, 178, 178)" data-darkmode-original-color-15906764299112="rgb(178, 178, 178)" 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(178, 178, 178)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-style="color: rgb(178, 178, 178); font-size: 14px; visibility: visible;" class="js_darkmode__7" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(178, 178, 178)" 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(178, 178, 178)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(178, 178, 178)" 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(178, 178, 178)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;color: rgb(178, 178, 178);font-size: 14px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section> <p style="white-space: normal;box-sizing: border-box;text-align: center;margin-bottom: 0px;"><span style="color: rgb(2, 30, 170);font-family: monospace;font-size: 16px;letter-spacing: 0.544px;white-space: pre-wrap;background-color: rgb(255, 255, 255);">- END -</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;white-space: normal;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;"> <section powered-by="xiumi.us" style="text-align: center;box-sizing: border-box;"> <section data-role="outer" label="Powered by 135editor.com" style="color: rgb(255, 150, 155);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;max-width: 100%;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-role="paragraph" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;font-size: 16px;letter-spacing: 0.544px;line-height: 25.6px;border-width: 0px;border-style: none;border-top-color: rgb(189, 189, 189);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;display: inline-block;max-width: 100%;border-top: 3px solid rgb(70, 70, 70);border-bottom: 1px solid rgb(220, 220, 220);width: 556px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding-top: 5px;padding-bottom: 5px;max-width: 100%;clear: both;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <h2 data-tool="mdnice编辑器" style="margin: 20px 10px 0px 0px;padding: 0px;outline: 0px;font-weight: bold;font-size: 22px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: 0.8px;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0.8px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: black;"><span style="margin: 0px;padding: 0px 0px 0px 10px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-size: 18px;font-weight: 700;color: rgb(34, 34, 34);display: inline-block;border-left: 5px solid rgb(248, 57, 41);">关于我</span></h2> <p data-tool="mdnice编辑器" style="margin: 0em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;white-space: normal;widows: 2;word-spacing: 0.8px;-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.75;">8 年互联网开发经验,擅长微服务、分布式、架构设计。目前在一家大型上市公司从事基础架构和性能优化工作。</p> <p data-tool="mdnice编辑器" style="margin: 0em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;white-space: normal;widows: 2;word-spacing: 0.8px;-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.75;">InfoQ 签约作者、蓝桥签约作者、阿里云专家博主、51CTO 红人。</p> <p data-tool="mdnice编辑器" style="margin: 0em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;white-space: normal;widows: 2;word-spacing: 0.8px;-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.75;"><span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">加入知识星球,一起来卷,门票价目前全网最低~星球内有打卡赠书活动,请及时参加~</span><span style="color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"></span></p> <p style="text-align: center;margin-bottom: 0em;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="1.0808823529411764" data-s="300,640" src="/upload/d73408fe95ea606ffbe693a2dce039f6.png" data-type="png" data-w="272" style="width: 136px;height: 147px;"></p> <p data-tool="mdnice编辑器" style="margin: 0em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;white-space: normal;widows: 2;word-spacing: 0.8px;-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.75;"><strong style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-weight: 700;color: rgb(248, 57, 41);">悟空的多个技术专题</strong>:</p> <p data-tool="mdnice编辑器" style="margin: 0em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;white-space: normal;widows: 2;word-spacing: 0.8px;-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.75;">33 篇 SpringCloud 实战,回复<span style="color: rgb(255, 104, 39);">PDF</span>获取。</p> <p data-tool="mdnice编辑器" style="margin: 0em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;white-space: normal;widows: 2;word-spacing: 0.8px;-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.75;">8 篇分布式算法文章,回复<span style="color: rgb(255, 104, 39);">分布式</span>获取。</p> <p data-tool="mdnice编辑器" style="margin: 0em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;white-space: normal;widows: 2;word-spacing: 0.8px;-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.75;">7 篇JVM 专项训练,回复<span style="color: rgb(255, 104, 39);">JVM</span>获取。</p> <h1 style="margin: 0px 0px 14px;padding: 0px;outline: 0px;font-weight: 400;font-size: 22px;line-height: 1.4;color: rgb(34, 34, 34);font-family: system-ui, -apple-system, "system-ui", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: 0.544px;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"><span style="outline: 0px;max-width: 100%;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.75;">Elasticsearch 筋斗云版蓝皮书1.0,回复</span><span style="outline: 0px;max-width: 100%;clear: both;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.75;color: rgb(255, 104, 39);overflow-wrap: break-word !important;">ES</span><span style="outline: 0px;max-width: 100%;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', 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;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;line-height: 1.75;">获取</span></h1> <p data-tool="mdnice编辑器" style="margin: 0em 0px;padding: 8px 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", 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;white-space: normal;widows: 2;word-spacing: 0.8px;-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.75;">面试必备资料,关注即可获取。↓↓</p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzU3NzU5NTg5Mg==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/GfOyjHGwCoN5Ky9IZgsdyZgM3lbEC5Ixe3ZgxBu5MdzvjWFyC7uqrsffcyhtrD8r8t0qicxbGmNxKYr4l4mANKQ/0?wx_fmt=png" data-nickname="面试突击" data-alias="PassJava1" data-signature="大厂面试突击,专注分享面试题,如计算机基础、计算机网络、Java后端、前端Vue。" data-from="0"></mpprofile> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;max-width: 100%;font-size: 16px;letter-spacing: 0.034em;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;line-height: 1.6;color: rgb(63, 63, 63);overflow-wrap: break-word !important;box-sizing: border-box !important;"> <span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(0, 0, 0);overflow-wrap: break-word !important;box-sizing: border-box !important;"></span> </section> </section> </section> </section> </section> </section> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="display: flex;flex-flow: row nowrap;box-sizing: border-box;"> <section style="display: inline-block;vertical-align: bottom;width: auto;align-self: flex-end;flex: 2 2 0%;height: auto;box-sizing: border-box;"> <section powered-by="xiumi.us" style="margin-top: 10px;opacity: 0.5;box-sizing: border-box;"> <span style="text-decoration: underline;"><em><strong><span style="color: rgb(43, 43, 43);font-family: Optima-Regular, Optima, PingFangTC-Light, PingFangSC-light, PingFangTC-light;font-size: 14px;letter-spacing: 2px;text-align: left;word-spacing: 2px;background-color: rgb(255, 255, 255);">我是悟空,努力变强,变身超级赛亚人!</span></strong></em></span> </section> </section> </section> </section> </section> </figure>
作者:微信小助手
<section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;word-spacing: 1.5px;letter-spacing: 1.5px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.05) 5%, rgba(0, 0, 0, 0) 5%), linear-gradient(360deg, rgba(50, 0, 0, 0.05) 5%, rgba(0, 0, 0, 0) 5%);background-size: 20px 20px;background-position: center center;margin-bottom: 0px;" data-mpa-powered-by="yiban.io"> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.6133333333333333" src="/upload/36ce3411e4a91271ea8ae69441595a0a.png" data-type="gif" data-w="300" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">兄弟们。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">浅浅的<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">炫个富</strong>吧。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">说出来你们可能不信。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">手机你们有吗?我有。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">短信</strong>,知道吧?一条一毛钱,<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">我天天发</strong>。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">你敢想吗?</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">所以说,年轻人,有钱是真的好。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">今天,我们就以短信为话题聊起。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">短信,它又叫SMS。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">比如说,你有一张<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">短信表(sms)</strong>,里面放了各种需要发送的短信信息。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" src="/upload/fea4a7425189974279c430377d95d740.png" data-type="png" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="sms建表sql" data-ratio="0.33240740740740743" data-w="1080"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> sms建表sql </figcaption> </figure> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.45" src="/upload/6b36625add67ba1e8aed25355f630274.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="sms表.drawio"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> sms表 </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">需要注意的是<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">state字段,为0的时候说明这时候短信还未发送。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">此时还会有一个<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">异步线程</strong>不断的捞起<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">未发送(state=0)</strong>的短信数据,执行发短信操作,发送成功之后state字段会被<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">置为1(已发送)</strong>。也就是说<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">未发送的数据会不断变少</strong>。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.3287037037037037" src="/upload/56369e6ff2658d2c4555fd3e43dbb33d.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="异步线程发送短信"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> 异步线程发送短信 </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">假设由于某些原因,你现在需要做一些监控,比如监控的内容是,<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">你的sms数据表里还有没有state=0(未发送)的短信,方便判断一下堆积的未发送短信大概在什么样的一个量级。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">为了获取<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">满足某些条件的行数是多少</strong>,我们一般会使用<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">count()方法</strong>。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">这时候为了获取未发送的短信数据,我们很自然就想到了使用下面的sql语句进行查询。</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"><code style="white-space:pre-wrap;overflow-wrap: break-word;margin: 0px 2px;line-height: 18px;font-size: 14px;font-weight: normal;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 10px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);overflow-x: auto;padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">select</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">count</span>(*) <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">from</span> sms <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">where</span> state = <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">0</span>;<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">然后再把获得数据作为打点发给监控服务。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">当数据表小的时候,这是没问题的,但当数据量大的时候,比如未发送的短信到了<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">百万量级</strong>的时候,你就会发现,<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">上面的sql查询时间会变得很长,最后timeout报错,查不出结果了</strong>。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">为什么?</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">我们先从<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">count()方法的原理</strong>聊起。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h3 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(21, 101, 192);"><span style="font-size: inherit;line-height: inherit;margin: 0px;display: inline-block;font-weight: normal;background: rgb(21, 101, 192);color: rgb(255, 255, 255);padding: 3px 10px 0px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">count()的原理</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">count()方法的目的是计算当前sql语句查询得到的<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">非NULL的行数</strong>。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">我们知道mysql是分为<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">server层和存储引擎层的</strong>。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.916" src="/upload/360ddbc18ec374102a61a04b2dd616a.png" data-type="png" data-w="1000" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="Mysql架构"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> Mysql架构 </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">存储引擎层里可以选择各种引擎进行存储,最常见的是innodb、myisam。具体使用哪个存储引擎,可以通过建表sql里的<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0px 2px;color: rgb(255, 82, 82);background: rgb(248, 248, 248);">ENGINE</code>字段进行指定。比如这篇文章开头的建表sql里用了<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0px 2px;color: rgb(255, 82, 82);background: rgb(248, 248, 248);">ENGINE=InnoDB</code>,那这张表用的就是innodb引擎。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">虽然在server层都叫count()方法,但在不同的存储引擎下,它们的实现方式是有区别的。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">比如同样是<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">读全表数据</strong> <code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0px 2px;color: rgb(255, 82, 82);background: rgb(248, 248, 248);">select count(*) from sms;</code>语句。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">使用 <strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">myisam引擎</strong>的数据表里有个记录当前表里有几行数据的字段,直接读这个字段返回就好了,因此速度快得飞起。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">而使用<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">innodb引擎</strong>的数据表,则会选择<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">体积最小的索引树</strong>,然后通过遍历叶子节点的个数挨个加起来,这样也能得到全表数据。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">因此回到文章开头的问题里,当数据表行数变大后,<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">单次count就需要扫描大量的数据</strong>,因此很可能就会出现超时报错。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">那么问题就来了。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h4 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">为什么innodb不能像myisam那样实现count()方法</strong></span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">myisam和innodb这两个引擎,有几个比较明显的区别,这个是八股文常考了。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">其中<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">最大的区别在于myisam不支持事务,而innodb支持事务。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">而事务,有四层隔离级别,其中<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">默认隔离级别就是可重复读隔离级别(RR)</strong>。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.4166666666666667" src="/upload/cb2e612d2ca3e7d6dda1805895464d56.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="四层隔离级别"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> 四层隔离级别 </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">innodb引擎通过MVCC实现了<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">可重复隔离级别</strong>,事务开启后,多次执行同样的<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">select快照读</strong>,要能读到同样的数据。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">于是我们看个例子。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.44166666666666665" src="/upload/6e15713962115727610278bf90659cd1.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="为什么innodb不单独记录表行数"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> 为什么innodb不单独记录表行数 </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">对于两个事务A和B,一开始sms表假设就<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">2条</strong>数据,那事务A一开始确实是读到2条数据。事务B在这期间插入了1条数据,按道理数据库其实有3条数据了,但由于可重复读的隔离级别,事务A依然还是只能读到2条数据。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">因此由于事务隔离级别的存在,<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">不同的事务在同一时间下,看到的表内数据行数是不一致的</strong>,因此innodb,没办法,也没必要像myisam那样单纯的加个count字段信息在数据表上。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">那如果不可避免要使用count(),有没有办法让它快一点?</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h3 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(21, 101, 192);"><span style="font-size: inherit;line-height: inherit;margin: 0px;display: inline-block;font-weight: normal;background: rgb(21, 101, 192);color: rgb(255, 255, 255);padding: 3px 10px 0px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">各种count()方法的原理</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">count()的括号里,可以放各种奇奇怪怪的东西,想必大家应该看过,比如放个星号*,放个1,放个索引列啥的。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">我们来分析下他们的执行流程。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">count方法的大原则是server层会从innodb存储引擎里读来一行行数据,并且只累计非null的值</strong>。但这个过程,根据count()方法括号内的传参,有略有不同。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h4 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;">count(*)</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">server层拿到innodb返回的行数据,<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">不对里面的行数据做任何解析和判断</strong>,默认取出的值肯定都不是null,直接行数+1。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h4 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;">count(1)</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">server层拿到innodb返回的行数据,每行放个1进去,默认不可能为null,直接行数+1.</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h4 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;">count(某个列字段)</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">由于指明了要count某个字段,innodb在取数据的时候,会把这个字段<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">解析出来</strong>返回给server层,所以会<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">比count(1)和count(*)多了个解析字段出来的流程。</strong></p> <ul style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;padding-left: 32px;list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p>如果这个列字段是<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">主键id</strong>,主键是不可能为null的,所以server层也不用判断是否为null,innodb每返回一行,行数结果就+1.</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p>如果这个列是<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">普通索引字段</strong>,innodb一般会<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">走普通索引</strong>,每返回一行数据,server层就会判断这个字段是否为null,不是null的情况下+1。当然如果建表sql里字段定义为not null的话,那就不用做这一步判断直接+1。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p>如果这个列<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">没有加过索引</strong>,那innodb可能会全表扫描,返回的每一行数据,server层都会判断这个字段是否为null,不是null的情况下+1。同上面的情况一样,字段加了not null也就省下这一步判断了。</p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">理解了原理后我们大概可以知道他们的性能排序是</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"><code style="white-space:pre-wrap;overflow-wrap: break-word;margin: 0px 2px;line-height: 18px;font-size: 14px;font-weight: normal;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 10px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);overflow-x: auto;padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">count(*) ≈ count(1) > count(主键id) > count(普通索引列) > count(未加索引列)<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">所以说count(*),已经是最快的了。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">知道真相的我眼泪掉下来。<span style="color: inherit;font-size: inherit;"></span></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">那有没有其他更好的办法?</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h3 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(21, 101, 192);"><span style="font-size: inherit;line-height: inherit;margin: 0px;display: inline-block;font-weight: normal;background: rgb(21, 101, 192);color: rgb(255, 255, 255);padding: 3px 10px 0px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">允许粗略估计行数的场景</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">我们回过头来细品下文章开头的需求,我们只是希望知道数据库里还有多少短信是堆积在那没发的,具体是1k还是2k其实都是差不多量级,等到了百万以上,具体数值已经不重要了,我们知道它现在堆积得很离谱,就够了。因此这个场景,其实是允许使用<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">比较粗略</strong>的估计的。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">那怎么样才能获得粗略的数值呢?</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">还记得我们平时为了查看sql执行计划用的<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">explain命令</strong>不。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">其中有个<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">rows</strong>,会用来<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">估计</strong>接下来执行这条sql需要扫描和检查多少行。它是通过采样的方式计算出来的,虽然会有一定的偏差,但它能反映一定的数量级。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.6129629629629629" src="/upload/6964c6dc442268b83ea51df47836c23b.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="explain里的rows"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> explain里的rows </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">有些语言的orm里可能没有专门的explain语法,但是肯定有执行raw sql的功能,你<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">可以把explain语句当做raw sql传入,从返回的结果里将rows那一列读出来使用。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">一般情况下,explain的sql如果能走索引,那会比不走索引的情况更准 。单个字段的索引会比多个字段组成的复合索引要准。索引区分度越高,rows的值也会越准。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">这种情况几乎满足大部分的监控场景。但总有一些场景,它要求必须得到精确的行数,这种情况该怎么办呢?</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h3 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(21, 101, 192);"><span style="font-size: inherit;line-height: inherit;margin: 0px;display: inline-block;font-weight: normal;background: rgb(21, 101, 192);color: rgb(255, 255, 255);padding: 3px 10px 0px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">必须精确估计行数的场景</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">这种场景就比较头疼了,但也不是不能做。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">我们可以单独拉一张新的数据库表,只为保存各种场景下的count。</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"><code style="white-space:pre-wrap;overflow-wrap: break-word;margin: 0px 2px;line-height: 18px;font-size: 14px;font-weight: normal;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 10px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);overflow-x: auto;padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">CREATE</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">TABLE</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`count_table`</span> (<br> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`id`</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">int</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">NOT</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">NULL</span> AUTO_INCREMENT <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">COMMENT</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">'主键'</span>,<br> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`cnt_what`</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">char</span>(<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">20</span>) <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">NOT</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">NULL</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">DEFAULT</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">''</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">COMMENT</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">'各种需要计算的指标'</span>,<br> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`cnt`</span> tinyint <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">NOT</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">NULL</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">COMMENT</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">'cnt指标值'</span>,<br> PRIMARY <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">KEY</span> (<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`id`</span>),<br> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">KEY</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`idx_cnt_what`</span> (<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">`cnt_what`</span>)<br>) <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">ENGINE</span>=<span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">InnoDB</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">DEFAULT</span> <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">CHARSET</span>=utf8mb4;<br></code></pre> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.45" src="/upload/4e1fab83c7bff44cb1c66cceca044685.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="count_table表保存各种场景下的count"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> count_table表保存各种场景下的count </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">当需要获取某个场景下的cout值时,可以使用下面的sql进行直接读取,<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">快得飞起</strong>。</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"><code style="white-space:pre-wrap;overflow-wrap: break-word;margin: 0px 2px;line-height: 18px;font-size: 14px;font-weight: normal;word-spacing: 0px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 10px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);overflow-x: auto;padding: 0.5em;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">select</span> cnt <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">from</span> count_table <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">where</span> cnt_what = <span style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"未发送的短信数量"</span>; <br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">那这些count的结果值从哪来呢?</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">这里分成两种情况。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h4 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;">实时性要求较高的场景</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">如果你对这个cnt计算结果的实时性要求很高,那你需要<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">将更新cnt的sql加入到对应变更行数的事务中</strong>。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">比如我们有两个事务A和B,分别是增加未发送短信和减少未发送短信。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.44166666666666665" src="/upload/b8d6b242200cfae8342010a59e807aeb.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="将更改表行数的操作放入到事务里.drawio"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> 将更改表行数的操作放入到事务里 </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">这样做的<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">好处</strong>是事务内的cnt行数依然符合隔离级别,事务回滚的时候,cnt的值也会跟着回滚。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">坏处</strong>也比较明显,多个线程对同一个cnt进行写操作,会触发悲观锁,多个线程之间需要互相等待。对于<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">高频写的场景</strong>,性能会有折损。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h4 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;">实时性没那么高的场景</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">如果实时性要求不高的话,比如可以一天一次,那你可以通过全表扫描后做计算。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">举个例子,比如上面的短信表,可以<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">按id排序</strong>,每次取出1w条数据,<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">记下这一批里最大的id,然后下次从最大id开始再拿1w条数据出来,不断循环。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">对于未发送的短信,就只需要在捞出的那1w条数据里,筛选出state=0的条数。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.6" src="/upload/688292e9540c2f94f299a00829536b35.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="batch分批获取短信表"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> batch分批获取短信表 </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">当然如果有条件,这种场景最好的方式还是<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">消费binlog将数据导入到hive里</strong>,然后在hive里做查询,不少公司也已经有现成的组件可以做这种事情,不用自己写脚本,岂不美哉。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;"> <img class="rich_pages wxw-img" data-ratio="0.3055555555555556" src="/upload/1138e7c191cb074e78ba85456718298b.png" data-type="png" data-w="1080" style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;display: block;margin: 0px auto;max-width: 100%;" title="mysql同步hive.drawio"> <figcaption style="line-height: inherit;margin: 0px;padding: 0px;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> mysql同步hive </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h3 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(21, 101, 192);"><span style="font-size: inherit;line-height: inherit;margin: 0px;display: inline-block;font-weight: normal;background: rgb(21, 101, 192);color: rgb(255, 255, 255);padding: 3px 10px 0px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">总结</span></h3> <ul style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;padding-left: 32px;list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">mysql用count方法<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">查全表数据</strong>,在不同的存储引擎里实现不同,myisam有专门字段记录全表的行数,直接读这个字段就好了。而innodb则需要一行行去算。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">性能方面 <code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0px 2px;color: rgb(255, 82, 82);background: rgb(248, 248, 248);">count(*) ≈ count(1) > count(主键id) > count(普通索引列) > count(未加索引列)</code>,但哪怕是性能最好的count(*),由于实现上就需要一行行去算,所以数据量大的时候就是不给力。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">如果确实需要获取行数,且<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">可以接受不那么精确的行数(只需要判断大概的量级)</strong>的话,那可以用explain里的rows,这可以满足大部分的监控场景,实现简单。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">如果要求行数准确</strong>,可以建个新表,里面专门放表行数的信息。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">如果对<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">实时性要求比较高</strong>的话,可以将更新行数的sql放入到对应事务里,这样既能满足事务隔离性,还能快速读取到行数信息。</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;margin-bottom: 0.5em;"><p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">如果对<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">实时性要求不高</strong>,接受一小时或者一天的更新频率,那既可以自己写脚本遍历全表后更新行数信息。也可以将通过监听binlog将数据导入hive,需要数据时直接通过hive计算得出。</p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h3 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(21, 101, 192);"><span style="font-size: inherit;line-height: inherit;margin: 0px;display: inline-block;font-weight: normal;background: rgb(21, 101, 192);color: rgb(255, 255, 255);padding: 3px 10px 0px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">参考资料</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">《丁奇mysql45讲》</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <h3 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(21, 101, 192);"><span style="font-size: inherit;line-height: inherit;margin: 0px;display: inline-block;font-weight: normal;background: rgb(21, 101, 192);color: rgb(255, 255, 255);padding: 3px 10px 0px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">最后</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">兄弟们,最近有点没出息,沉迷在刘亦菲的新剧里,都快忘了写文这件事了。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">按照惯例,我应该在这里唯唯诺诺的求大家叫我两声<strong style="font-size: inherit;line-height: inherit;margin: 0px;padding: 0px;font-weight: bold;color: rgb(41, 98, 255);">靓仔</strong>的。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">但今天,我感觉我不配。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">所以先这样。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;"><br></p> <p style="font-size: inherit;color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;">但右下角的点赞和再看还是可以走一波的。</p> <h6 style="color: inherit;line-height: inherit;padding: 0px;margin: 1.5em 0px;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;margin: 0px;padding: 0px;">别说了,一起在知识的海洋里呛水吧</span></h6> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="Mzg5NDY2MDk4Mw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/AnAgeMhDIianpibeb1icaNfMQWI9DibKw3EcA2nvqMtwQ1GuX5bFuupzh6LaH1AkOZggtabj6t0mXvgIGibhwUYCz4w/0?wx_fmt=png" data-nickname="小白debug" data-alias="xiaobaidebug" data-signature="答应我,关注之后,好好学技术,别只是收藏我的表情包。。" data-from="1"></mpprofile> </section> </section>