文章列表

MySQL的row 20000 was cut by group_concat()问题

作者:じ☆ve宝贝

``` SELECT b.* FROM ( SELECT SUBSTRING_INDEX(GROUP_CONCAT(id),',',1) AS id FROM news GROUP BY title HAVING COUNT(*) > 1 ) a JOIN choice_news b ON a.id = b.id; ``` SUBSTRING_INDEX(GROUP_CONCAT(id),',',1) 获取以“,”分割的第一个值,但是当group的数据超过1024后,就会出现row 20000 was cut by group_concat()的error #### 解决方法 ``` SET group_concat_max_len=200000; #此值大于你要分组的数量即可 ```

人人都是 API 设计者:我对 RESTful API、GraphQL、RPC API 的思考

作者:微信小助手

<section powered-by="xiumi.us" style="white-space: normal;"> <section> <section> <section> <p style="text-align: center;"><img class="" data-copyright="0" data-cropselx1="0" data-cropselx2="552" data-cropsely1="0" data-cropsely2="226" data-ratio="0.66640625" src="/upload/ec59923b4def40e0e617ae8c13eed987.jpg" data-type="jpeg" data-w="1280" style="color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;width: 552px;height: 368px;"></p> </section> </section> </section> </section> <section powered-by="xiumi.us" style="white-space: normal;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <section style="padding: 10px;display: inline-block;width: 556px;border-width: 0px 10px 0px 0px;border-style: solid;border-left-color: rgb(249, 110, 87);border-right-color: rgb(249, 110, 87);box-sizing: border-box;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="box-sizing: border-box;"> <section style="text-align: right;color: rgb(95, 156, 239);font-size: 12px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">梁桂钊 | 作者</span><br></p> </section> </section> </section> </section> </section> </section> <section powered-by="xiumi.us" style="white-space: normal;"> <section> <section> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">有一段时间没怎么写文章了,今天提笔写一篇自己对 API 设计的思考。首先,为什么写这个话题呢?其一,我阅读了《阿里研究员谷朴:API 设计最佳实践的思考》一文后受益良多,前两天并转载了这篇文章也引发了广大读者的兴趣,我觉得我应该把我自己的思考整理成文与大家一起分享与碰撞。其二,我觉得我针对这个话题,可以半个小时之内搞定,争取在 1 点前关灯睡觉,哈哈。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">现在,我们来一起探讨 API 的设计之道。我会抛出几个观点,欢迎探讨。</p> <h2 style="box-sizing: border-box;margin-top: 1.5rem;margin-bottom: 1rem;color: rgb(21, 153, 87);line-height: 1.35;font-size: 22px;text-align: start;white-space: normal;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">一、定义好的规范,已经成功了一大半</h2> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">通常情况下,规范就是大家约定俗成的标准,如果大家都遵守这套标准,那么自然沟通成本大大降低。例如,大家都希望从阿里的规范上面学习,在自己的业务中也定义几个领域模型:VO、BO、DO、DTO。其中,DO(Data Object)与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。而 DTO(Data Transfer Object)是远程调用对象,它是 RPC 服务提供的领域模型。对于 BO(Business Object),它是业务逻辑层封装业务逻辑的对象,一般情况下,它是聚合了多个数据源的复合对象。那么,VO(View Object) 通常是请求处理层传输的对象,它通过 Spring 框架的转换后,往往是一个 JSON 对象。<br style="box-sizing: border-box;"><br style="box-sizing: border-box;"><img class="" data-ratio="0.8446511627906976" src="/upload/e445c41d4a815373730505f422bed3cd.png" data-type="png" data-w="1075" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"><br style="box-sizing: border-box;">事实上,阿里这种复杂的业务中如果不划分清楚 &nbsp;DO、BO、DTO、VO 的领域模型,其内部代码很容易就混乱了,内部的 RPC 在 service 层的基础上又增加了 manager 层,从而实现内部的规范统一化。但是,如果只是单独的域又没有太多外部依赖,那么,完全不要设计这么复杂,除非预期到可能会变得庞大和复杂化。对此,设计过程中因地制宜就显得特别重要了。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">另外一个规范的例子是 RESTful API。在 REST 架构风格中,每一个 URI 代表一种资源。因此,URI 是每一个资源的地址的唯一资源定位符。所谓资源,实际上就是一个信息实体,它可以是服务器上的一段文本、一个文件、一张图片、一首歌曲,或者是一种服务。RESTful API 规定了通过 GET、 POST、 PUT、 PATCH、 DELETE 等方式对服务端的资源进行操作。</p> <pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;padding-top: 8px;padding-bottom: 6px;background: rgb(241, 239, 238);border-radius: 0px;overflow-y: auto;color: rgb(80, 97, 109);text-align: start;font-size: 10px;line-height: 12px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot;!important;border-width: 1px !important;border-style: solid !important;border-color: rgb(226, 226, 226) !important;"> <ol class="linenums list-paddingleft-2" style="list-style-type: none;"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">【</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">GET</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">】</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">users </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"># 查询用户信息列表</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">【</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">GET</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">】</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">users</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="lit" style="box-sizing: border-box;color: rgb(223, 83, 32);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">1001</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"># 查看某个用户信息</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">【</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">POST</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">】</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">users </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"># 新建用户信息</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">【</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">PUT</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">】</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">users</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="lit" style="box-sizing: border-box;color: rgb(223, 83, 32);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">1001</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"># 更新用户信息(全部字段)</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">【</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">PATCH</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">】</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">users</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="lit" style="box-sizing: border-box;color: rgb(223, 83, 32);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">1001</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"># 更新用户信息(部分字段)</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">【</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">DELETE</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">】</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">users</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="lit" style="box-sizing: border-box;color: rgb(223, 83, 32);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">1001</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"># 删除用户信息</span></code></span></span></p></li> </ol></pre> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">事实上,RESTful API 的实现分了四个层级。第一层次(Level 0)的 Web API 服务只是使用 HTTP 作为传输方式。第二层次(Level 1)的 Web API 服务引入了资源的概念。每个资源有对应的标识符和表达。第三层次(Level 2)的 Web API 服务使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。第四层次(Level 3)的 Web API 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。通常情况下,伪 RESTful API 都是基于第一层次与第二层次设计的。例如,我们的 Web API 中使用各种动词,例如&nbsp;<code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot;!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 14px;">get_menu</span></code>&nbsp;和&nbsp;<code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot;!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 14px;">save_menu</span></code>&nbsp;,而真正意义上的 RESTful API 需要满足第三层级以上。如果我们遵守了这套规范,我们就很可能就设计出通俗易懂的 API。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">注意的是,定义好的规范,我们已经成功了一大半。如果这套规范是业内标准,那么我们可以大胆实践,不要担心别人不会用,只要把业界标准丢给他好好学习一下就可以啦。例如,Spring 已经在 Java 的生态中举足轻重,如果一个新人不懂 Spring 就有点说不过去了。但是,很多时候因为业务的限制和公司的技术,我们可能使用基于第一层次与第二层次设计的伪 RESTful API,但是它不一定就是落后的,不好的,只要团队内部形成规范,降低大家的学习成本即可。很多时候,我们试图改变团队的习惯去学习一个新的规范,所带来的收益(投入产出比)甚微,那就得不偿失了。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">总结一下,定义好的规范的目的在于,降低学习成本,使得 API 尽可能通俗易懂。当然,设计的 API 通俗易懂还有其他方式,例如我们定义的 API 的名字易于理解,API 的实现尽可能通用等。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;"><span style="color: rgb(21, 153, 87);font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace;font-size: 22px;">二、探讨 API 接口的兼容性</span><br></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">API 接口都是不断演进的。因此,我们需要在一定程度上适应变化。在 RESTful API 中,API 接口应该尽量兼容之前的版本。但是,在实际业务开发场景中,可能随着业务需求的不断迭代,现有的 API 接口无法支持旧版本的适配,此时如果强制升级服务端的 API 接口将导致客户端旧有功能出现故障。实际上,Web 端是部署在服务器,因此它可以很容易为了适配服务端的新的 API 接口进行版本升级,然而像 Android 端、IOS 端、PC 端等其他客户端是运行在用户的机器上,因此当前产品很难做到适配新的服务端的 API 接口,从而出现功能故障,这种情况下,用户必须升级产品到最新的版本才能正常使用。为了解决这个版本不兼容问题,在设计 RESTful API 的一种实用的做法是使用版本号。一般情况下,我们会在 url 中保留版本号,并同时兼容多个版本。</p> <pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;padding-top: 8px;padding-bottom: 6px;background: rgb(241, 239, 238);border-radius: 0px;overflow-y: auto;color: rgb(80, 97, 109);text-align: start;font-size: 10px;line-height: 12px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot;!important;border-width: 1px !important;border-style: solid !important;border-color: rgb(226, 226, 226) !important;"> <ol class="linenums list-paddingleft-2" style="list-style-type: none;"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">【</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">GET</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">】</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">v1</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">users</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/{</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">user_id</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">}</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">// 版本 v1 的查询用户列表的 API 接口</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">【</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">GET</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">】</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">v2</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">users</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/{</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">user_id</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">}</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">// 版本 v2 的查询用户列表的 API 接口</span></code></span></span></p></li> </ol></pre> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">现在,我们可以不改变版本 v1 的查询用户列表的 API 接口的情况下,新增版本 v2 的查询用户列表的 API 接口以满足新的业务需求,此时,客户端的产品的新功能将请求新的服务端的 API 接口地址。虽然服务端会同时兼容多个版本,但是同时维护太多版本对于服务端而言是个不小的负担,因为服务端要维护多套代码。这种情况下,常见的做法不是维护所有的兼容版本,而是只维护最新的几个兼容版本,例如维护最新的三个兼容版本。在一段时间后,当绝大多数用户升级到较新的版本后,废弃一些使用量较少的服务端的老版本API 接口版本,并要求使用产品的非常旧的版本的用户强制升级。注意的是,“不改变版本 v1 的查询用户列表的 API 接口”主要指的是对于客户端的调用者而言它看起来是没有改变。而实际上,如果业务变化太大,服务端的开发人员需要对旧版本的 API 接口使用适配器模式将请求适配到新的API 接口上。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">有趣的是,GraphQL 提供不同的思路。GraphQL 为了解决服务 API 接口爆炸的问题,以及将多个 HTTP 请求聚合成了一个请求,提出只暴露单个服务 API 接口,并且在单个请求中可以进行多个查询。GraphQL 定义了 API 接口,我们可以在前端更加灵活调用,例如,我们可以根据不同的业务选择并加载需要渲染的字段。因此,服务端提供的全量字段,前端可以按需获取。GraphQL 可以通过增加新类型和基于这些类型的新字段添加新功能,而不会造成兼容性问题。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;"><img class="" data-ratio="0.5009765625" src="/upload/445aa001125078934a16b50bd942a780.png" data-type="png" data-w="1024" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">此外,在使用 RPC API 过程中,我们特别需要注意兼容性问题,二方库不能依赖 parent,此外,本地开发可以使用 SNAPSHOT,而线上环境禁止使用,避免发生变更,导致版本不兼容问题。我们需要为每个接口都应定义版本号,保证后续不兼容的情况下可以升级版本。例如,Dubbo 建议第三位版本号通常表示兼容升级,只有不兼容时才需要变更服务版本。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">关于规范的案例,我们可以看看 k8s 和 github,其中 k8s 采用了 RESTful API,而 github 部分采用了 GraphQL。</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">https://developer.github.com/v4/</span></span></p></li> </ul> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;"><span style="color: rgb(21, 153, 87);font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace;font-size: 22px;">三、提供清晰的思维模型</span><br></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">所谓思维模型,我的理解是针对问题域抽象模型,对域模型的功能有统一认知,构建某个问题的现实映射,并划分好模型的边界,而域模型的价值之一就是统一思想,明确边界。假设,大家没有清晰的思维模型,那么也不存在对 API 的统一认知,那么就很可能出现下面图片中的现实问题。<br style="box-sizing: border-box;"><img class="" data-ratio="0.7214912280701754" src="/upload/27359ddd8ff8440884dbf9724426bb45.png" data-type="png" data-w="1368" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;"><span style="color: rgb(21, 153, 87);font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace;font-size: 22px;">四、以抽象的方式屏蔽业务实现</span><br></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">我认为好的 API 接口具有抽象性,因此需要尽可能的屏蔽业务实现。那么,问题来了,我们怎么理解抽象性?对此,我们可以思考 java.sql.Driver 的设计。这里,java.sql.Driver 是一个规范接口,而 com.mysql.jdbc.Driver<br style="box-sizing: border-box;">则是 mysql-connector-java-xxx.jar 对这个规范的实现接口。那么,切换成 Oracle 的成本就非常低了。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">一般情况下,我们会通过 API 对外提供服务。这里,API 提供服务的接口的逻辑是固定的,换句话说,它具有通用性。但是,但我们遇到具有类似的业务逻辑的场景时,即核心的主干逻辑相同,而细节的实现略有不同,那我们该何去何从?很多时候,我们会选择提供多个 API 接口给不同的业务方使用。事实上,我们可以通过 SPI 扩展点来实现的更加优雅。什么是 SPI?SPI 的英文全称是 Serivce Provider Interface,即服务提供者接口,它是一种动态发现机制,可以在程序执行的过程中去动态的发现某个扩展点的实现类。因此,当 API 被调用时会动态加载并调用 SPI 的特定实现方法。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">此时,你是不是联想到了模版方法模式。模板方法模式的核心思想是定义骨架,转移实现,换句话说,它通过定义一个流程的框架,而将一些步骤的具体实现延迟到子类中。事实上,在微服务的落地过程中,这种思想也给我们提供了非常好的理论基础。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;"><img class="" data-ratio="0.5124508519003932" src="/upload/ec25057e10820de4c5908548a7b08a2a.png" data-type="png" data-w="763" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">现在,我们来看一个案例:电商业务场景中的未发货仅退款。这种情况在电商业务中非常场景,用户下单付款后由于各种原因可能就申请退款了。此时,因为不涉及退货,所以只需要用户申请退款并填写退款原因,然后让卖家审核退款。那么,由于不同平台的退款原因可能不同,我们可以考虑通过 SPI 扩展点来实现。<br style="box-sizing: border-box;"><img class="" data-ratio="0.6408912188728703" src="/upload/c838c8b458e91a5661d6a09f35f48c0d.png" data-type="png" data-w="763" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">此外,我们还经常使用工厂方法+策略模式来屏蔽内部的复杂性。例如,我们对外暴露一个 API 接口 getTask(int operation),那么我们就可以通过工厂方法来创建实例,通过策略方法来定义不同的实现。其中,<span style="color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;">operation</span> 就是具体的指令。</p> <pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;padding-top: 8px;padding-bottom: 6px;background: rgb(241, 239, 238);border-radius: 0px;overflow-y: auto;color: rgb(80, 97, 109);text-align: start;font-size: 10px;line-height: 12px;font-family: consolas, menlo, courier, monospace, &quot;Microsoft Yahei&quot;!important;border-width: 1px !important;border-style: solid !important;border-color: rgb(226, 226, 226) !important;"> <ol class="linenums list-paddingleft-2" style="list-style-type: none;"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="lit" style="box-sizing: border-box;color: rgb(223, 83, 32);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">@Component</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">public</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">class</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">TaskManager</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">{</span></code></span></span></p></li> <li><p><br></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">private</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">static</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">final</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">Logger</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> logger </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">=</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">LoggerFactory</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">.</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">getLogger</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">(</span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">TaskManager</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">.</span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">class</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">);</span></code></span></span></p></li> <li><p><br></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">private</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">static</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">TaskManager</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> instance</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">;</span></code></span></span></p></li> <li><p><br></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">public</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">Map</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">&lt;</span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">Integer</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">,</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">ITask</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">&gt;</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> taskMap </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">=</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">new</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">HashMap</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">&lt;</span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">Integer</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">,</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">ITask</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">&gt;();</span></code></span></span></p></li> <li><p><br></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">public</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">static</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">TaskManager</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> getInstance</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">()</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">{</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">return</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> instance</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">;</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">}</span></code></span></span></p></li> <li><p><br></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">public</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="typ" style="box-sizing: border-box;color: rgb(64, 126, 231);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">ITask</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> getTask</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">(</span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">int</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> operation</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">)</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">{</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">return</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> taskMap</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">.</span><span class="kwd" style="box-sizing: border-box;color: rgb(102, 102, 234);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">get</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">(</span><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">operation</span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">);</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="pun" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">}</span></code></span></span></p></li> <li><p><br></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="pln" style="box-sizing: border-box;color: rgb(27, 25, 24);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> </span><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;">/**</span></code></span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);display: block;font-size: 14px !important;word-break: inherit !important;"><span style="box-sizing: border-box;display: block;word-break: inherit !important;"><code style="box-sizing: border-box;margin-left: -20px;display: flex;overflow: initial;line-height: 12px;word-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;font-size: 10px;font-family: inherit !important;white-space: pre !important;"><span class="com" style="box-sizing: border-box;color: rgb(156, 148, 145);line-height: 20px;font-size: 13px !important;white-space: inherit !important;"> * 初始化

如何写出让同事无法维护的代码?

作者:微信小助手

<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <section data-mpa-powered-by="yiban.io"> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.6082779009608278" data-s="300,640" src="/upload/52d8a4b11048bff43e6b5ff3433b8065.png" data-type="png" data-w="1353" style=""></p> <section style="box-sizing: border-box;text-align: left;" powered-by="xiumi.us"> <br> </section> <section style="box-sizing: border-box;text-align: left;" powered-by="xiumi.us"> <span style="font-size: 12px;line-height: 22.4px;white-space: pre-wrap;color: rgb(136, 136, 136);">原文:http://mindprod.com/jgloss/unmain.html</span> </section> <section style="box-sizing: border-box;text-align: left;" powered-by="xiumi.us"> <span style="color: rgb(136, 136, 136);"><span style="color: rgb(136, 136, 136);line-height: 22.4px;font-size: 12px;white-space: pre-wrap;">译者:</span><span style="color: rgb(136, 136, 136);line-height: 1rem;font-size: 12px;">陈皓 (@左耳朵耗子)</span></span> <p style="line-height: 25.6px;"><span style="line-height: 1rem;font-size: 12px;color: rgb(136, 136, 136);">译文:http://coolshell.cn/articles/4758.html</span></p> <p style="font-size: 16px;font-weight: 400;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="font-weight: 700;font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;font-size: 15px;text-align: start;color: rgb(0, 0, 0);"></span><br></p> <p style="font-size: 16px;font-weight: 400;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><strong><span style="color: rgb(0, 0, 0);">对,你没看错,本文就是教你怎么写出让同事无法维护的代码。</span></strong><br></p> <p style="font-size: 16px;font-weight: 400;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="font-weight: 700;font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;font-size: 15px;text-align: start;color: rgb(0, 0, 0);"><br></span></p> <p style="text-align: start;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="font-size: 18px;font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(255, 76, 65);"><strong>一、程序命名</strong></span></p> <p style="text-align: start;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="font-size: 18px;font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;color: rgb(61, 167, 66);"><strong><br></strong></span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 0px;margin-right: 0px;"> <li><p style="text-align: start;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><strong><span style="font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;color: rgb(0, 0, 0);">容易输入的变量名</span></strong><span style="color: rgb(0, 0, 0);font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;"><strong><span style="font-size: 16px;font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: left;background-color: rgb(255, 255, 255);">。</span></strong><span style="font-size: 16px;font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: left;background-color: rgb(255, 255, 255);">比如:Fred,asdf</span></span></p></li> <li><p style="line-height: 2em;"><span style="font-weight: 700;font-size: 16px;color: rgb(0, 0, 0);">单字母的变量名</span><span style="font-size: 16px;">。比如:a,b,c, x,y,z(如果不够用,可以考虑a1,a2,a3,a4,….)</span></p></li> <li><p style="line-height: 2em;"><span style="font-weight: 700;font-size: 16px;color: rgb(0, 0, 0);">有创意地拼写错误</span><span style="font-size: 16px;">。比如:SetPintleOpening, SetPintalClosing。这样可以让人很难搜索代码。</span></p></li> <li><p style="line-height: 2em;"><span style="font-weight: 700;font-size: 16px;color: rgb(0, 0, 0);">抽象</span><span style="font-size: 16px;">。比如:ProcessData, DoIt, GetData… 抽象到就跟什么都没说一样。</span></p></li> <li><p style="line-height: 2em;"><span style="font-weight: 700;font-size: 16px;color: rgb(0, 0, 0);">缩写</span><span style="font-size: 16px;">。比如:WTF,RTFSC …… (使用拼音缩写也同样给力,比如: BT,TMD,TJJTDS)</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>随机大写字母</strong></span><span style="font-size: 16px;">。比如:gEtnuMbER..</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>重用命名</strong></span><span style="font-size: 16px;">。在内嵌的语句块中使用相同的变量名有奇效。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用重音字母</strong></span><span style="font-size: 16px;">。比如:int &nbsp;ínt(第二个 ínt不是int)</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用下划线</strong></span><span style="font-size: 16px;">。比如:_, __, ___。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用不同的语言</strong></span><span style="font-size: 16px;">。比如混用英语,德语,或是中文拼音。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用字符命名</strong></span><span style="font-size: 16px;">。比如:slash, asterix, comma…</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用无关的单词</strong></span><span style="font-size: 16px;">。比如:god, superman, iloveu….</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>混淆l和1</strong></span><span style="font-size: 16px;">。字母l和数字1有时候是看不出来的。</span></p><p><br></p></li> </ul> <p style="text-align: start;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="color: rgb(255, 76, 65);"><strong><span style="font-size: 18px;">二、伪装欺诈</span></strong></span></p> <p style="text-align: start;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="color: rgb(61, 167, 66);"><strong><span style="font-size: 18px;"><br></span></strong></span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 0px;margin-right: 0px;"> <li><p style="line-height: 2em;"><span style="font-weight: 700;font-size: 16px;color: rgb(0, 0, 0);">把注释和代码交织在一起。</span></p></li> </ul> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <pre class="code-snippet__js" data-lang="xml"><p style="margin-left: 0px;margin-right: 0px;"><code><span class="code-snippet_outer">for(j=0; j<span class="code-snippet__tag">&lt;<span class="code-snippet__name">array_len;</span> <span class="code-snippet__attr">j</span>+ =<span class="code-snippet__string">8)</span></span></span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">total</span> += <span class="code-snippet__string">array[j+0</span> ];</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">total</span> += <span class="code-snippet__string">array[j+1</span> ];</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">total</span> += <span class="code-snippet__string">array[j+2</span> ]; /* <span class="code-snippet__attr">Main</span> <span class="code-snippet__attr">body</span> <span class="code-snippet__attr">of</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">total</span> += <span class="code-snippet__string">array[j+3];</span> * <span class="code-snippet__attr">loop</span> <span class="code-snippet__attr">is</span> <span class="code-snippet__attr">unrolled</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">total</span> += <span class="code-snippet__string">array[j+4];</span> * <span class="code-snippet__attr">for</span> <span class="code-snippet__attr">greater</span> <span class="code-snippet__attr">speed.</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">total</span> += <span class="code-snippet__string">array[j+5];</span> */</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">total</span> += <span class="code-snippet__string">array[j+6</span> ];</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">total</span> += <span class="code-snippet__string">array[j+7</span> ];</span></code><code><span class="code-snippet_outer">}</span></code></p></pre> </section> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 0px;margin-right: 0px;"> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>代码和显示不一致</strong></span><span style="font-size: 16px;">。比如,你的界面显示叫postal code,但是代码里确叫 zipcode.</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>隐藏全局变量</strong></span><span style="font-size: 16px;">。把使用全局变量以函数参数的方式传递给函数,这样可以让人觉得那个变量不是全局变量。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用相似的变量名</strong></span><span style="font-size: 16px;">。如:单词相似,swimmer 和 swimner,字母相似:ilI1| 或 oO08。parselnt 和 parseInt, D0Calc 和 DOCalc。还有这一组:xy_Z, xy__z, _xy_z, _xyz, XY_Z, xY_z, Xy_z。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>重载函数</strong></span><span style="font-size: 16px;">。使用相同的函数名,但是其功能和具体实现完全没有关系。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>操作符重载</strong></span><span style="font-size: 16px;">。重载操作符可以让你的代码变得诡异,感谢CCTV,感谢C++。这个东西是可以把混乱代码提高到一种艺术的形式。比如:重载一个类的 ! 操作符,但实际功能并不是取反,让其返回一个整数。于是,如果你使用 ! ! 操作符,那么,有意思的事就发生了—— 先是调用类的重载 ! 操作符,然后把其返回的整数给 ! 成了 布尔变量,如果是 !!! 呢?呵呵。</span></p><p><br></p></li> </ul> <p><br></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><span style="color: rgb(255, 76, 65);"><strong><span style="font-size: 18px;">三、文档和注释</span></strong></span></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><strong><span style="font-size: 18px;color: rgb(61, 167, 66);"><br></span></strong></p> <ul class=" list-paddingleft-2" style="margin-left: 0px;margin-right: 0px;"> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>在注释中撒谎</strong></span><span style="font-size: 16px;">。你不用真的去撒谎,只需在改代码的时候不要更新注释就可以了。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>注释里面写废话</strong></span><span style="font-size: 16px;">。比如:/* add 1 to i */</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>只注释是什么,而不是为什么</strong></span><span style="font-size: 16px;">。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>不要注释秘密</strong></span><span style="font-size: 16px;">。如果你开发一个航班系统,请你一定要保证每有一个新的航班被加入,就得要修改25个以上的位置的程序。千万别把这个事写在文档中。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>注重细节</strong></span><span style="font-size: 16px;">。当你设计一个很复杂的算法的时候,你一定要把所有的详细细设计都写下来,没有100页不能罢休,段落要有5级以上,段落编号要有500个以上,例如:1.2.4.6.3.13 – Display all impacts for activity where selected mitigations can apply (short pseudocode omitted). 这样,当你写代码的时候,你就可以让你的代码和文档一致,如:Act1_2_4_6_3_13()千万不要注释度衡单位。比如时间用的是秒还是毫秒,尺寸用的是像素还是英寸,大小是MB还是KB。等等。另外,在你的代码里,你可以混用不同的度衡单位,但也不要注释。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>Gotchas。陷阱</strong></span><span style="font-size: 16px;">,千万不要注释代码中的陷阱。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>在注释和文档中发泄不满</strong></span><span style="font-size: 16px;">。</span></p></li> </ul> <p><br></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><span style="color: rgb(255, 76, 65);"><strong><span style="font-size: 18px;">四、程序设计</span></strong></span></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><strong><span style="font-size: 18px;color: rgb(61, 167, 66);"><br></span></strong></p> <ul class=" list-paddingleft-2" style="margin-left: 0px;margin-right: 0px;"> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>Java Casts</strong></span><span style="font-size: 16px;">。Java的类型转型是天赐之物。每一次当你从Collection里取到一个object的时候,你都需要把其转回原来的类型。因些,这些转型操作会出现在N多的地方。如果你改变了类型,那么你不一定能改变所有的地方。而编译器可能能检查到,也可能检查不到。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>利用Java的冗余</strong></span><span style="font-size: 16px;">。比如:Bubblegum b = new Bubblegom(); 和 swimmer = swimner + 1; 注意变量间的细微差别。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>从不验证</strong></span><span style="font-size: 16px;">。从不验证输入的数据,从不验证函数的返回值。这样做可以向大家展示你是多么的信任公司的设备和其它程序员</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>不要封装</strong></span><span style="font-size: 16px;">。调用者需要知道被调用的所有的细节。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>克隆和拷贝</strong></span><span style="font-size: 16px;">。为了效率,你要学会使用copy + paste。你几乎都不用理解别人的代码,你就可以高效地编程了。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>巨大的listener</strong></span><span style="font-size: 16px;">。写一个listener,然后让你的所有的button类都使用这个listener,这样你可以在这个listener中整出一大堆if…else…语句,相当的刺激。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用三维数组</strong></span><span style="font-size: 16px;">。如果你觉得三维还不足够,你可以试试四维。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>混用</strong></span><span style="font-size: 16px;">。同时使用类的get/set方法和直接访问那个public变量。这样做的好处是可以极大的挫败维护人员。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>包装,包装,包装</strong></span><span style="font-size: 16px;">。把你所有的API都包装上6到8遍,包装深度多达4层以上。然后包装出相似的功能。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>没有秘密</strong></span><span style="font-size: 16px;">。把所有的成员都声明成public的。这样,你以后就很难限制其被人使用,而且这样可以和别的代码造成更多的耦合度,可以让你的代码存活得更久。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;letter-spacing: normal;color: rgb(0, 0, 0);"><strong>排列和阻碍</strong></span><span style="font-size: 16px;letter-spacing: normal;">。把drawRectangle(height, width) 改成 drawRectangle(width, height),等release了几个版本后,再把其改回去。这样维护程序的程序员们很快就不明白哪一个是对的。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>把变量改在名字上</strong></span><span style="font-size: 16px;">。例如,把setAlignment(int alignment)改成,setLeftAlignment, setRightAlignment, setCenterAlignment。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>保留你所有的没有使用的和陈旧的变量,方法和代码</strong>。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>Final你所有的子结点的类</strong></span><span style="font-size: 16px;">,这样,当你做完这个项目后,没有人可以通过继承来扩展你的类。java.lang.String不也是这样吗?</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>避免使用layout</strong></span><span style="font-size: 16px;">。这样就使得我们只能使用绝对坐标。如果你的老大强制你使用layout,你可以考虑使用GridBagLayout,然后把grid坐标hard code.</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>环境变量</strong></span><span style="font-size: 16px;">。如果你的代码需要使用环境变量。那么,你应该把你的类的成员的初始化使用环境变量,而不是构造函数。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用全局变量</strong></span><span style="font-size: 16px;">。1)把全局变量的初始化放在不同的函数中,就算这个函数和这个变量没有任何关系,这样能够让我们的维护人员就像做侦探工作一样。2)使用全局变量可以让你的函数的参数变得少一些。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>配置文件</strong></span><span style="font-size: 16px;">。配置文件主要用于一些参数的初始化。在编程中,我们可以让配置文件中的参数名和实际程序中的名字不一样。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>膨胀你的类</strong></span><span style="font-size: 16px;">。让你的类尽可能地拥有各种臃肿和晦涩的方法。比如,你的类只实现一种可能性,但是你要提供所有可能性的方法。不要定义其它的类,把所有的功能都放在一个类中。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>使用子类</strong></span><span style="font-size: 16px;">。面向对象是写出无法维护代码的天赐之物。如果你有一个类有十个成为(变量和方法)你可以考虑写10个层次的继承,然后把这十个属性分别放在这十个层次中。如果可能的话,把这十个类分别放在十个不同的文件中。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>混乱你的代码。</strong></span><span style="font-size: 16px;">使用XML。XML的强大是无人能及的。使用XML你可以把本来只要10行的代码变成100行。而且,还要逼着别人也有XML。(参看,信XML得永生,信XML得自信)</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>分解条件表达式</strong></span><span style="font-size: 16px;">。如:把 a==100分解成,a&gt;99 &amp;&amp; a&lt;101</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>学会利用分号</strong></span><span style="font-size: 16px;">。如:if ( a );else;{ &nbsp; int d; &nbsp; d = c;}</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>间接转型</strong></span><span style="font-size: 16px;">。如:把double转string,写成new Double(d).toString() 而不是 Double.toString(d)</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>大量使用嵌套</strong></span><span style="font-size: 16px;">。一个NB的程序员可以在一行代码上使用超过10层的小括号(),或是在一个函数里使用超过20层的语句嵌套{},把嵌套的if else 转成 [? :] 也是一件很NB的事。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>长代码行</strong></span><span style="font-size: 16px;">。一行的代码越长越好。这样别人阅读时就需要来来回回的</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>不要过早的return</strong></span><span style="font-size: 16px;">。不要使用break,这样,你就需要至少5层以上的if-else来处理错误。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>不要使用{}。不要在if else使用{}</strong></span><span style="font-size: 16px;">,尤其是在你重量地使用if-else嵌套时,你甚至可以在其中乱缩进代码,这样一来,就算是最有经验的程序员也会踩上陷阱。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>琐碎的封装</strong></span><span style="font-size: 16px;">。比较封装一个bool类,类里面什么都做,就是一个bool.</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>循环</strong></span><span style="font-size: 16px;">。千万不可用for(int i=0; i&lt;n; i++)使用while代替for,交换n和i,把&lt;改成&lt;=,使用 i–调整步伐 。</span></p></li> </ul> <p><br></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><strong><span style="font-size: 18px;color: rgb(61, 167, 66);"><br></span></strong></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><span style="color: rgb(255, 76, 65);"><strong><span style="font-size: 18px;">五、测试</span></strong></span></p> <p><br></p> <ul class=" list-paddingleft-2" style="margin-left: 0px;margin-right: 0px;"> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>从不测试</strong></span><span style="font-size: 16px;">。千万不要测试任何的出错处理,从来也不检测系统调用的返回值。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>永远不做性能测试</strong></span><span style="font-size: 16px;">。如果不够快就告诉用户换一个更快的机器。如果你一做测试,那么就可能会要改你的算法,甚至重设计,重新架构。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>不要写测试案例</strong></span><span style="font-size: 16px;">。不要做什么代码覆盖率测试,自动化测试。</span></p></li> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>测试是懦夫行为</strong></span><span style="font-size: 16px;">。一个勇敢的程序员是根本不需要这一步的。太多的程序太害怕他们的老板,害怕失去工作,害怕用户抱怨,甚至被起诉。这种担心害怕直接影响了生产力。如果你对你的代码有强大的信心,那还要什么测试呢?真正的程序员是不需要测试自己的代码的。</span></p></li> </ul> <p><br></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><span style="color: rgb(255, 76, 65);"><strong><span style="font-size: 18px;">六、其他</span></strong></span></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><strong><span style="font-size: 18px;color: rgb(61, 167, 66);"><br></span></strong></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 0px;margin-right: 0px;"> <li><p style="line-height: 2em;"><span style="font-size: 16px;color: rgb(0, 0, 0);"><strong>你的老板什么都知道</strong></span><span style="font-size: 16px;">。无论你的老板有多SB,你都要严格地遵照他的旨意办事,这样一来,你会学到更多的知识以及如何写出更加无法维护的代码。</span></p></li> <li><p style="line-height: 2em;"><span style="color: rgb(0, 0, 0);"><strong style="font-size: 16px;">颠覆Help Desk</strong></span><span style="font-size: 16px;">。你要确保你那满是bug的程序永远不要被维护团队知道。当用户打电话和写邮件给你的时候,你就不要理会,就算要理会,让用户重做系统或是告诉用户其帐号有问题,是标准的回答。</span></p></li> <li><p style="line-height: 2em;"><span style="color: rgb(0, 0, 0);"><strong style="font-size: 16px;">闭嘴</strong></span><span style="font-size: 16px;">。对于一些像y2k这样的大bug,你要学会守口如瓶,不要告诉任何人,包括你的亲人好友以及公司的同事和管理层,这样当到那一天的时候,你就可以用这个bug挣钱了。</span></p></li> <li><p style="line-height: 2em;"><span style="color: rgb(0, 0, 0);"><strong style="font-size: 16px;">忽悠</strong></span><span style="font-size: 16px;">。你会学会忽悠,就算你的代码写得很烂,你也要为其挂上GoF设计模式的标签,就算你的项目做得再烂,你也要为其挂上敏捷的标签,让整个团队和公司,甚至整个业界都开始躁动,这样才能真正为难维护的代码铺平道路。</span></p></li> </ul> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><span style="font-size: 16px;"></span></p> <p style="line-height: 2em;margin-left: 0px;margin-right: 0px;"><span style="font-size: 16px;">总之,我们的口号是—— <strong>Write Everywhere, Read Nowhere</strong></span></p> <p><br></p> <p><br></p> <section data-role="paragraph" class="_135editor"> <p style="max-width: 100%;min-height: 1em;white-space: normal;text-align: left;line-height: 2em;margin-left: 0px;margin-right: 0px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 15px;overflow-wrap: break-word !important;box-sizing: border-box !important;"></span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;color: rgb(62, 62, 62);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 28.4444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 18px;line-height: 1.6;box-sizing: border-box !important;overflow-wrap: break-word !important;">—————END—————</span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;color: rgb(62, 62, 62);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 28.4444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;color: rgb(62, 62, 62);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 28.4444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;color: rgb(62, 62, 62);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 28.4444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;color: rgb(62, 62, 62);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 25.6px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 18px;line-height: 28.8px;box-sizing: border-box !important;overflow-wrap: break-word !important;">喜欢本文的朋友们,欢迎长按下图关注订阅号</span><span style="max-width: 100%;font-size: 18px;line-height: 28.8px;color: rgb(255, 76, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">程序员小灰</strong></span><span style="max-width: 100%;font-size: 18px;line-height: 28.8px;box-sizing: border-box !important;overflow-wrap: break-word !important;">,收看更多精彩内容</span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;color: rgb(62, 62, 62);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 25.6px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;color: rgb(62, 62, 62);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 25.6px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-copyright="0" data-ratio="1" data-s="300,640" src="/upload/37f513ecb7627cdbb355876dab88096.jpg" data-type="jpeg" data-w="344" style="color: rgb(51, 51, 51);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 333px !important;"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: center;color: rgb(62, 62, 62);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;widows: 1;line-height: 25.6px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 27.2px;widows: 1;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 82, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">欢迎扫码关注公众号&nbsp;</span></strong><span style="max-width: 100%;color: rgb(255, 76, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">程序员内推圈</strong></span><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 82, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">,优秀的内推机会等着你!</span></strong></span></p> <p style="max-width: 100%;min-height: 1em;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 27.2px;widows: 1;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-variant-numeric: normal;font-variant-east-asian: normal;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 27.2px;widows: 1;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-ratio="1" data-s="300,640" src="/upload/94873a54b9f44e5ee4f5ec91d264b597.png" data-type="png" data-w="344" style="letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 344px !important;"></p> </section> </section> </section>

Redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比

作者:微信小助手

<p style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);font-size: 16px;text-align: center;" data-mpa-powered-by="yiban.io"><br></p> <section class="" style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"> <section> <section> <section class=""> <section> <section class=""> <section> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="45" data-source-title=""> <section class="js_blockquote_digest"> <section> <p><span style="font-size: 13px;color: rgb(0, 0, 0);">作者:爱宝贝丶</span></p> <p><span style="font-size: 13px;color: rgb(0, 0, 0);">my.oschina.net/zhangxufeng/blog/905611</span></p> </section> </section> </blockquote> </section> </section> </section> </section> </section> </section> </section> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">redis作为一种高效的缓存框架,使用是非常广泛的,在数据存储上,在运行时其将数据存储在内存中,以实现数据的高效读写,并且根据定制的持久化规则不同,其会不定期的将数据持久化到硬盘中。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">另外相较于其他的NoSql数据库,redis提供了非常丰富的数据结构,如<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">dict</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">sds</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">linkedlist</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">ziplist</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">set</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">quicklist</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">geometry</code>。在这些存储结构的基础上,redis为用户提供了非常丰富的操作选择,如通过<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">zskiplist</code>来达到对某种类型的数据的排序目的,而排序在数据库中是一个非常耗时的操作。</p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">1.redis单例的安装和使用</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">redis相对于其他的缓存框架安装非常的方便,只需要从<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">https://redis.io/download</code>下载后解压,进入redis目录之后执行如下命令即安装完成:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs nginx" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span class="hljs-attribute" style="font-size: inherit;color: rgb(255, 255, 170);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">make</span>&nbsp;install<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">这里需要注意的是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">make</code>是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">gcc</code>中的一个命令,安装之前请确保机器安装了<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">gcc</code>。redis中所有的命令都在redis安装目录中的<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">src</code>子目录下,其中比较重要的是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-server,redis-sentinel,redis-cli</code>。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">编译完成之后在<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">src</code>目录下执行<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">./redis-server</code>启动redis(启动后可关闭该窗口),然后新开一个窗口,在命令行中执行<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">./redis-cli</code>即可连接启动的redis服务。在其中执行如下命令即可看到编译安装成功了:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6379</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">set</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">hello</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">world</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">OK</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6379</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">get</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">hello</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">"<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">world</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">这里需要说明的是,按照上述方式启动redis,其使用的ip为本机ip&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">127.0.0.1</code>,端口为<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">6379</code>,并且其余的配置采用的都是默认配置,相关配置可在redis安装目录下的<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis.conf</code>文件中查看。如果需要按照指定的配置文件来启动,可在<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-server</code>后接上配置文件名,如:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs vbscript" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">./src/redis-<span class="hljs-built_in" style="font-size: inherit;color: rgb(255, 255, 170);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">server</span>&nbsp;redis.conf<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">另外,上述使用<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-cli</code>连接redis客户端时如果不带任何参数,那么其连接的默认ip和端口为<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">127.0.0.1:6379</code>。如果需要连接指定ip和端口的客户端,可以使用如下方式:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">./src/redis-cli&nbsp;-h&nbsp;127.0.0.1&nbsp;-p&nbsp;6379<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">这里-h参数表示连接的ip,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">-p</code>则表示连接的端口。配置好redis之后,我们就可以在redis中执行相关命令来操作数据。</p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">2.redis主从模式的配置</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">redis单例提供了一种数据缓存方式和丰富的数据操作<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">api</code>,但是将数据完全存储在单个redis中主要存在两个问题:数据备份和数据体量较大造成的性能降低。这里redis的<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">主从模式</code>为这两个问题提供了一个较好的解决方案。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">主从模式指的是使用一个redis实例作为主机,其余的实例作为备份机。主机和从机的数据完全一致,主机支持数据的写入和读取等各项操作,而从机则只支持与主机数据的同步和读取,也就是说,客户端可以将数据写入到主机,由主机自动将数据的写入操作同步到从机。</p> <blockquote style="padding: 10px 15px 10px 1rem;color: rgb(62, 62, 62);border-left-width: 6px;border-left-color: rgb(220, 230, 240);font-size: 0.8em;line-height: inherit;background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">主从模式很好的解决了数据备份问题,并且由于主从服务数据几乎是一致的,因而可以将写入数据的命令发送给主机执行,而读取数据的命令发送给不同的从机执行,从而达到读写分离的目的。如下所示主机<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-A</code>分别有<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-B</code>、<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-C</code>、<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-D</code>、<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-E</code>四个从机:</p> </blockquote> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><img class="" data-ratio="0.36425648021828105" data-type="jpeg" data-w="733" src="/upload/293469885164fdbf01464fd3b820eced.jpg"></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">前面第1点中我们已经介绍了redis单例的配置方式,而上面我们也介绍了主从模式其实也是多个redis实例组成的,因而redis主从模式的配置可以理解为多个不同的redis实例通过一定的配置告知其相互之间的主从关系。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">而前面已经介绍,每个redis实例都会占用一个本机的端口号,主从模式的配置主要的配置点有两个:当前实例端口号和当前实例是主机还是从机,是从机的话其主机的ip和端口是什么。一般的redis目录下的<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis.conf</code>保存的是默认配置,尽量不要对其进行修改,这里我们复制三份<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis.conf</code>文件,分别命名为<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">6379.conf</code>,<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">6380.conf</code>和<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">6381.conf</code>,如下是端口为<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">6379</code>的主机的主要配置:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">bind</span>&nbsp;127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">port</span>&nbsp;6379<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">logfile</span>&nbsp;"6379<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.log</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">dbfilename</span>&nbsp;"<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">dump-6379</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.rdb</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">如下是端口为6380和6381的从机的配置:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">bind</span>&nbsp;127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">port</span>&nbsp;6380<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">logfile</span>&nbsp;"6380<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.log</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">dbfilename</span>&nbsp;"<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">dump-6380</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.rdb</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">slaveof</span>&nbsp;127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span>&nbsp;6379<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p><br></p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">bind</span>&nbsp;127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">port</span>&nbsp;6381<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">logfile</span>&nbsp;"6381<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.log</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">dbfilename</span>&nbsp;"<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">dump-6381</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.rdb</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">slaveof</span>&nbsp;127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span>&nbsp;6379<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">可以看到,端口为6380和6381的实例被配置为端口为6379的实例的从机。配置完成后使用<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">redis-server</code>分别执行如下命令启动三个实例:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs vbscript" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">./src/redis-<span class="hljs-built_in" style="font-size: inherit;color: rgb(255, 255, 170);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">server</span>&nbsp;<span class="hljs-number" style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">6379.</span>conf<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">./src/redis-<span class="hljs-built_in" style="font-size: inherit;color: rgb(255, 255, 170);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">server</span>&nbsp;<span class="hljs-number" style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">6380.</span>conf<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">./src/redis-<span class="hljs-built_in" style="font-size: inherit;color: rgb(255, 255, 170);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">server</span>&nbsp;<span class="hljs-number" style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">6381.</span>conf<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">启动之后分别开启开启三个命令行工具分别执行以下命令连接redis实例:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">./src/redis-cli&nbsp;-p&nbsp;6379<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">./src/redis-cli&nbsp;-p&nbsp;6380<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">./src/redis-cli&nbsp;-p&nbsp;6381<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">分别在三个命令行工具中执行一个get命令,获取键名为msg的数据,如下所示:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6379</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">get</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">msg</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">(<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">nil</span>)<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p><br></p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6380</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">get</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">msg</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">(<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">nil</span>)<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p><br></p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6381</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">get</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">msg</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">(<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">nil</span>)<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">可以看到,在三个redis实例中都不存在键为msg的数据,现在我们在主机6379上设置一个键为msg的数据,如下所示:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6379</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">set</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">msg</span>&nbsp;"<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">hello</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">OK</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">可以看到设置成功了,此时我们在6380和6381的实例上执行<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">get msg</code>的命令,如下所示:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6380</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">get</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">msg</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">"<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">hello</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p><br></p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6381</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">get</span>&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">msg</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">"<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">hello</span>"<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">可以看到,虽然我们只是在6379的实例上设置了msg这条数据,但是在6380和6381的实例上也存有了相应的数据,说明我们成功配置了redis的主从模式。另外,如果不在配置文件中指定主从节点的关系,也可以在启动相关redis实例之后使用<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">slaveof</code>命令来指定当前节点称为某个节点的从节点,如:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);font-family: Consolas, Inconsolata, Courier, monospace;display: block;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.1</span><span class="hljs-selector-pseudo" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:6380</span>&gt;&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">slaveof</span>&nbsp;127<span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><span class="hljs-selector-class" style="font-size: inherit;color: rgb(173, 229, 252);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">.

jquery $(document).ready() 与window.onload的区别

作者:じ☆ve宝贝

1.执行时间 window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。 $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。 2.编写个数不同 window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个 $(document).ready()可以同时编写多个,并且都可以得到执行 3.简化写法 window.onload 没有简化写法 $(document).ready(function(){})可以简写成$(function(){});

58到家MySQL军规升级版

作者:微信小助手

<p><strong><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">一、基础规范</span></strong><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">表存储引擎必须使用</span>InnoDB</span></p></li> </ul> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">表字符集默认使用</span>utf8<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,必要时候使用</span>utf8mb4</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:</span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>1<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)通用,无乱码风险,汉字</span>3<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">字节,英文</span>1<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">字节</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>2<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)</span>utf8mb4<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">是</span>utf8<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">的超集,有存储</span>4<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">字节例如表情符号时,使用它</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">禁止使用存储过程,视图,触发器,</span>Event</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:</span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>1<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)对数据库性能影响较大,互联网业务,能让站点层和服务层干的事情,不要交到数据库层</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>2<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)调试,排错,迁移都比较困难,扩展性较差</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">禁止在数据库中存储大文件,例如照片,可以将大文件存储在对象存储系统,数据库中存储路径</span></p></li> <li><p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">禁止在线上环境做数据库压力测试</span></p></li> <li><p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">测试,开发,线上数据库环境必须隔离</span></p></li> </ul> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <p><strong><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">二、命名规范</span></strong></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">库名,表名,列名必须用小写,采用下划线分隔</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">解读:</span>abc<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,</span>Abc<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,</span>ABC<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">都是给自己埋坑</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">库名,表名,列名必须见名知义,长度不要超过</span>32<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">字符</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">解读:</span>tmp<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,</span>wushan<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">谁TM知道这些库是干嘛的</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">库备份必须以</span>bak<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">为前缀,以日期为后缀</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">从库必须以</span>-s<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">为后缀</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">备库必须以</span>-ss<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">为后缀</span></span></p></li> </ul> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <p><strong><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">三、表设计规范</span></strong></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">单实例表个数必须控制在</span>2000<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">个以内</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">单表分表个数必须控制在</span>1024<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">个以内</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">表必须有主键,推荐使用</span>UNSIGNED<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">整数为主键</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">潜在坑:删除无主键的表,如果是</span>row<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">模式的主从架构,从库会挂住</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">禁止使用外键,如果要保证完整性,应由应用程式实现</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">解读:外键使得表之间相互耦合,影响</span>update/delete<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">等</span>SQL<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">性能,有可能造成死锁,高并发情况下容易成为数据库瓶颈</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">建议将大字段,访问频度低的字段拆分到单独的表中存储,分离冷热数据</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:具体参加《<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&amp;mid=2651959773&amp;idx=1&amp;sn=7e4ad0dcd050f6662dfaf39d9de36f2c&amp;chksm=bd2d04018a5a8d17b92098b4840aac23982e32d179cdd957e4c55011f6a08f6bd31f9ba5cfee&amp;scene=21#wechat_redirect" target="_blank">如何实施数据库垂直拆分</a>》</span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <p><strong><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">四、列设计规范</span></strong></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">根据业务区分使用</span>tinyint/int/bigint<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,分别会占用</span>1/4/8<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">字节</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">根据业务区分使用</span>char/varchar</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:</span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>1<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)字段长度固定,或者长度近似的业务场景,适合使用</span>char<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,能够减少碎片,查询性能高</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>2<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)字段长度相差较大,或者更新较少的业务场景,适合使用</span>varchar<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,能够减少空间</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">根据业务区分使用</span>datetime/timestamp</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">解读:前者占用</span>5<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">个字节,后者占用</span>4<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">个字节,存储年使用</span>YEAR<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,存储日期使用</span>DATE<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,存储时间使用</span>datetime</span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">必须把字段定义为</span>NOT NULL<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">并设默认值</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:</span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>1<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)</span>NULL<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">的列使用索引,索引统计,值都更加复杂,</span>MySQL<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">更难优化</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>2<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)</span>NULL<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">需要更多的存储空间</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>3<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)</span>NULL<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">只能采用</span>IS NULL<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">或者</span>IS NOT NULL<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,而在</span>=/!=/in/not in<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">时有大坑</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">使用</span>INT UNSIGNED<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">存储</span>IPv4<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,不要用</span>char(15)</span></p></li> </ul> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">使用</span>varchar(20)<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">存储手机号,不要使用整数</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:</span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>1<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)牵扯到国家代号,可能出现</span>+/-/()<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">等字符,例如</span>+86</span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>2<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)手机号不会用来做数学运算</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>3<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)</span>varchar<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">可以模糊查询,例如</span>like ‘138%’</span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">使用</span>TINYINT<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">来代替</span>ENUM</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">解读:</span>ENUM<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">增加新值要进行</span>DDL<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">操作</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <p><strong><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">五、索引规范</span></strong></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">唯一索引使用</span>uniq_[<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">字段名</span>]<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">来命名</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">非唯一索引使用</span>idx_[<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">字段名</span>]<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">来命名</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">单张表索引数量建议控制在</span>5<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">个以内</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:</span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>1<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)互联网高并发业务,太多索引会影响写性能</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>2<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)生成执行计划时,如果索引太多,会降低性能,并可能导致</span>MySQL<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">选择不到最优索引</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>3<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)异常复杂的查询需求,可以选择</span>ES<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">等更为适合的方式存储</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">组合索引字段数不建议超过</span>5<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">个</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">解读:如果</span>5<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">个字段还不能极大缩小</span>row<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">范围,八成是设计有问题</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">不建议在频繁更新的字段上建立索引</span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">非必要不要进行</span>JOIN<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">查询,如果要进行</span>JOIN<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">查询,被</span>JOIN<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">的字段必须类型相同,并建立索引</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:踩过因为JOIN字段类型不一致,而导致全表扫描的坑么?</span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">理解组合索引最左前缀原则,避免重复建设索引,如果建立了</span>(a,b,c)<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,相当于建立了</span>(a), (a,b), (a,b,c)</span></p></li> </ul> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <p><strong><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">六、</span>SQL<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">规范</span></span></strong></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">禁止使用</span>select *<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,只获取必要字段</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:</span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>1<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)</span>select *<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">会增加</span>cpu/io/<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">内存</span>/<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">带宽的消耗</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>2<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)指定字段能有效利用索引覆盖</span></span></em></span></p> <p><span style="color: rgb(0, 82, 255);"><em><span style="color: rgb(0, 82, 255);font-size: 14px;letter-spacing: 1px;"><span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">(</span>3<span style="color: rgb(0, 82, 255);letter-spacing: 1px;font-size: 14px;font-family: 宋体;">)指定字段查询,在表结构变更时,能保证对应用程序无影响</span></span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;">insert<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">必须指定字段,禁止使用</span>insert into T values()</span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:指定字段插入,在表结构变更时,能保证对应用程序无影响</span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">隐式类型转换会使索引失效,导致全表扫描</span></p></li> </ul> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">禁止在</span>where<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">条件列使用函数或者表达式</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:导致不能命中索引,全表扫描</span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">禁止负向查询以及</span>%<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">开头的模糊查询</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:导致不能命中索引,全表扫描</span></em></span></p> <p><span style="font-size: 14px;letter-spacing: 1px;">&nbsp;</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">禁止大表</span>JOIN<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">和子查询</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">同一个字段上的</span>OR<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">必须改写问</span>IN<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">,</span>IN<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">的值必须少于</span>50<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">个</span></span></p></li> <li><p><span style="font-size: 14px;letter-spacing: 1px;"><span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">应用程序必须捕获</span>SQL<span style="letter-spacing: 1px;font-size: 14px;font-family: 宋体;">异常</span></span></p></li> </ul> <p><span style="color: rgb(0, 82, 255);"><em><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">解读:方便定位线上问题</span></em></span></p> <p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;"><br></span></p> <p><strong><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">说明</span></strong><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">:本军规适用于</span><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;color: rgb(255, 76, 0);">并发量大,数据量大</span><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">的典型</span><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;color: rgb(255, 76, 0);">互联网业务</span><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">,可直接带走参考,不谢。</span></p> <p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;"><br></span></p> <p><span style="font-family: 宋体;font-size: 14px;letter-spacing: 1px;">军规练习:为什么下列SQL不能命中phone索引?</span></p> <p><span style="font-family: 宋体;letter-spacing: 1px;font-size: 12px;">select uid from user where phone=13811223344</span></p>

大型网站系统架构演化之路

作者:じ☆ve宝贝

## 前言 一个成熟的大型网站(如淘宝、京东等)的系统架构并不是开始设计就具备完整的高性能、高可用、安全等特性,它总是随着用户量的增加,业务功能的扩展逐渐演变完善的,在这个过程中,开发模式、技术架构、设计思想也发生了很大的变化,就连技术人员也从几个人发展到一个部门甚至一条产品线。所以成熟的系统架构是随业务扩展而完善出来的,并不是一蹴而就;不同业务特征的系统,会有各自的侧重点,例如淘宝,要解决海量的商品信息的搜索、下单、支付,例如腾讯,要解决数亿的用户实时消息传输,百度它要处理海量的搜索请求,他们都有各自的业务特性,系统架构也有所不同。尽管如此我们也可以从这些不同的网站背景下,找出其中共用的技术,这些技术和手段可以广泛运行在大型网站系统的架构中,下面就通过介绍大型网站系统的演化过程,来认识这些技术和手段。 ## 一、最开始的网站架构 最初的架构,应用程序、数据库、文件都部署在一台服务器上,如图: ![网站架构](/upload/251844423268454.png "网站架构") ## 二、应用、数据、文件分离 随着业务的扩展,一台服务器已经不能满足性能需求,故将应用程序、数据库、文件各自部署在独立的服务器上,并且根据服务器的用途配置不同的硬件,达到最佳的性能效果。 ![网站架构](/upload/251844436545725.png "网站架构") ## 三、利用缓存改善网站性能 在硬件优化性能的同时,同时也通过软件进行性能优化,在大部分的网站系统中,都会利用缓存技术改善系统的性能,使用缓存主要源于热点数据的存在,大部分网站访问都遵循28原则(即80%的访问请求,最终落在20%的数据上),所以我们可以对热点数据进行缓存,减少这些数据的访问路径,提高用户体验。 ![网站架构](/upload/251844460767600.png "网站架构") 缓存实现常见的方式是本地缓存、分布式缓存。当然还有CDN、反向代理等,这个后面再讲。本地缓存,顾名思义是将数据缓存在应用服务器本地,可以存在内存中,也可以存在文件,OSCache就是常用的本地缓存组件。本地缓存的特点是速度快,但因为本地空间有限所以缓存数据量也有限。分布式缓存的特点是,可以缓存海量的数据,并且扩展非常容易,在门户类网站中常常被使用,速度按理没有本地缓存快,常用的分布式缓存是Membercache、Redis。 ## 四、使用集群改善应用服务器性能 应用服务器作为网站的入口,会承担大量的请求,我们往往通过应用服务器集群来分担请求数。应用服务器前面部署负载均衡服务器调度用户请求,根据分发策略将请求分发到多个应用服务器节点。 ![网站架构](/upload/251844471702801.png "网站架构") 常用的负载均衡技术硬件的有F5,价格比较贵,软件的有LVS、Nginx、HAProxy。LVS是四层负载均衡,根据目标地址和端口选择内部服务器,Nginx和HAProxy是七层负载均衡,可以根据报文内容选择内部服务器,因此LVS分发路径优于Nginx和HAProxy,性能要高些,而Nginx和HAProxy则更具配置性,如可以用来做动静分离(根据请求报文特征,选择静态资源服务器还是应用服务器)。 ## 五、数据库读写分离和分库分表 随着用户量的增加,数据库成为最大的瓶颈,改善数据库性能常用的手段是进行读写分离以及分表,读写分离顾名思义就是将数据库分为读库和写库,通过主备功能实现数据同步。分库分表则分为水平切分和垂直切分,水平切换则是对一个数据库特大的表进行拆分,例如用户表。垂直切分则是根据业务不同来切换,如用户业务、商品业务相关的表放在不同的数据库中。 ![网站架构](/upload/260851219209749.png "网站架构") ## 六、使用CDN和反向代理提高网站性能 假如我们的服务器都部署在成都的机房,对于四川的用户来说访问是较快的,而对于北京的用户访问是较慢的,这是由于四川和北京分别属于电信和联通的不同发达地区,北京用户访问需要通过互联路由器经过较长的路径才能访问到成都的服务器,返回路径也一样,所以数据传输时间比较长。对于这种情况,常常使用CDN解决,CDN将数据内容缓存到运营商的机房,用户访问时先从最近的运营商获取数据,这样大大减少了网络访问的路径。比较专业的CDN运营商有蓝汛、网宿。 而反向代理,则是部署在网站的机房,当用户请求达到时首先访问反向代理服务器,反向代理服务器将缓存的数据返回给用户,如果没有没有缓存数据才会继续走应用服务器获取,也减少了获取数据的成本。反向代理有Squid,Nginx。 ![网站架构图](/upload/260851254513595.png "网站架构图") ## 七、使用分布式文件系统 用户一天天增加,业务量越来越大,产生的文件越来越多,单台的文件服务器已经不能满足需求。需要分布式的文件系统支撑。常用的分布式文件系统有NFS。 ![网站架构图](/upload/260851282647353.png "网站架构图") ## 八、使用NoSql和搜索引擎 对于海量数据的查询,我们使用nosql数据库加上搜索引擎可以达到更好的性能。并不是所有的数据都要放在关系型数据中。常用的NOSQL有mongodb和redis,搜索引擎有Lucene。 ![网站架构图](/upload/260851321075527.png "网站架构图") ## 九、将应用服务器进行业务拆分 随着业务进一步扩展,应用程序变得非常臃肿,这时我们需要将应用程序进行业务拆分,如百度分为新闻、网页、图片等业务。每个业务应用负责相对独立的业务运作。业务之间通过消息进行通信或者同享数据库来实现。 ![网站架构图](/upload/260851352481788.png "网站架构图") ## 十、搭建分布式服务 这时我们发现各个业务应用都会使用到一些基本的业务服务,例如用户服务、订单服务、支付服务、安全服务,这些服务是支撑各业务应用的基本要素。我们将这些服务抽取出来利用分部式服务框架搭建分布式服务。淘宝的Dubbo是一个不错的选择。 ![网站架构图](/upload/260851397174320.png "网站架构图") ## 小结 大型网站的架构是根据业务需求不断完善的,根据不同的业务特征会做特定的设计和考虑,本文只是讲述一个常规大型网站会涉及的一些技术和手段。

真正理解Mysql的四种隔离级别

作者:微信小助手

<h2 style="margin-bottom: 1rem;font-size: 22px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">什么是事务<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></h2> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">事务的结束有两种,当事务中的所以步骤全部成功执行时,事务提交。如果其中一个步骤失败,将发生回滚操作,撤消撤消之前到事务开始时的所以操作。</p> <h2 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 22px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">事务的 ACID</h2> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">事务具有四个特征:原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。这四个特性简称为 ACID 特性。</p> <ul class=" list-paddingleft-2" style="list-style-type: square;"> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px !important;">原子性。事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做</span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px !important;">一致性。事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。</span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px !important;">隔离性。一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。</span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px !important;">持续性。也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。</span></p></li> </ul> <h2 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 22px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">Mysql的四种隔离级别</h2> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。</p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 18px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">Read Uncommitted(读取未提交内容)</h3> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。</p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 18px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">Read Committed(读取提交内容)</h3> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。</p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 18px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">Repeatable Read(可重读)</h3> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。</p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 18px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">Serializable(可串行化)</h3> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:</p> <ul class=" list-paddingleft-2" style="list-style-type: square;"> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px !important;">脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。</span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px !important;">不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。</span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px !important;">幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就有几列数据是未查询出来的,如果此时插入和另外一个事务插入的数据,就会报错。</span></p></li> </ul> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">在MySQL中,实现了这四种隔离级别,分别有可能产生问题如下所示:</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.20408163265306123" data-type="other" data-w="686" src="/upload/25e92f7bde4a9a4e9b68ecbcf9d91f4a.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <h2 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 22px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">测试Mysql的隔离级别</h2> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">下面,将利用MySQL的客户端程序,我们分别来测试一下这几种隔离级别。</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">测试数据库为demo,表为test;表结构:</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.19155844155844157" data-type="other" data-w="616" src="/upload/a3c2400c5f69c11a69b909ab5b326160.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 616px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">两个命令行客户端分别为A,B;不断改变A的隔离级别,在B端修改数据。</p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 18px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">将A的隔离级别设置为read uncommitted(未提交读)</h3> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.04943502824858757" data-type="other" data-w="708" src="/upload/c1c570ec8de1d64875302f815b225527.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:启动事务,此时数据为初始状态</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.48450704225352115" data-type="other" data-w="710" src="/upload/9d1e70d7f6793d514895e90eed9bfd85.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:启动事务,更新数据,但不提交</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.3756983240223464" data-type="other" data-w="716" src="/upload/a372bceb2e37102e5eb7c379c2d2e353.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:再次读取数据,发现数据已经被修改了,这就是所谓的“脏读”</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.21971830985915494" data-type="other" data-w="710" src="/upload/501cd6ed99a28c7054a2b9906ef6eab9.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:回滚事务</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.05446927374301676" data-type="other" data-w="716" src="/upload/2524dda77735925aabf3cbc8cb52a443.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:再次读数据,发现数据变回初始状态</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.21971830985915494" data-type="other" data-w="710" src="/upload/8f86173fcb93eebed47a3f297a76ce72.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">经过上面的实验可以得出结论,事务B更新了一条记录,但是没有提交,此时事务A可以查询出未提交记录。造成脏读现象。未提交读是最低的隔离级别。</p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 18px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">将客户端A的事务隔离级别设置为read committed(已提交读)</h3> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.05049088359046283" data-type="other" data-w="713" src="/upload/df41a2b48b0bd2a86a464bf2fed40329.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:启动事务,此时数据为初始状态</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.47390691114245415" data-type="other" data-w="709" src="/upload/6b91dd7c579ce35c7aebdfc7921b3579.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:启动事务,更新数据,但不提交</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.3756983240223464" data-type="other" data-w="716" src="/upload/a372bceb2e37102e5eb7c379c2d2e353.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:再次读数据,发现数据未被修改</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.21971830985915494" data-type="other" data-w="710" src="/upload/4ea24c869bbc1643594907bfdd8dae9b.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:提交事务</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.059490084985835696" data-type="other" data-w="706" src="/upload/e25fd5fbcbdcedfd5680ea8197f2d5ac.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:再次读取数据,发现数据已发生变化,说明B提交的修改被事务中的A读到了,这就是所谓的“不可重复读”</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.21720733427362482" data-type="other" data-w="709" src="/upload/bd6fa564e793898dbe11835d65c51941.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">经过上面的实验可以得出结论,已提交读隔离级别解决了脏读的问题,但是出现了不可重复读的问题,即事务A在两次查询的数据不一致,因为在两次查询之间事务B更新了一条数据。已提交读只允许读取已提交的记录,但不要求可重复读。</p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 18px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">将A的隔离级别设置为repeatable read(可重复读)</h3> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.052039381153305204" data-type="other" data-w="711" src="/upload/f629ff55620418b5a116e4c160f44ad8.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:启动事务,此时数据为初始状态</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.4844632768361582" data-type="other" data-w="708" src="/upload/2ac1accca8e76e83983a969c53d20b06.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:启动事务,更新数据,但不提交</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.3756983240223464" data-type="other" data-w="716" src="/upload/a372bceb2e37102e5eb7c379c2d2e353.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:再次读取数据,发现数据未被修改</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.21971830985915494" data-type="other" data-w="710" src="/upload/4ea24c869bbc1643594907bfdd8dae9b.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:提交事务</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.059490084985835696" data-type="other" data-w="706" src="/upload/e25fd5fbcbdcedfd5680ea8197f2d5ac.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:再次读取数据,发现数据依然未发生变化,这说明这次可以重复读了</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.21971830985915494" data-type="other" data-w="710" src="/upload/4ea24c869bbc1643594907bfdd8dae9b.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:插入一条新的数据,并提交</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.3829787234042553" data-type="other" data-w="705" src="/upload/b6bdd8e285b7d405334a619a85827f65.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:再次读取数据,发现数据依然未发生变化,虽然可以重复读了,但是却发现读的不是最新数据,这就是所谓的“幻读”</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.21971830985915494" data-type="other" data-w="710" src="/upload/4ea24c869bbc1643594907bfdd8dae9b.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:提交本次事务,再次读取数据,发现读取正常了</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.31444759206798867" data-type="other" data-w="706" src="/upload/de5fdcfa56636dfb1310f9cb1b727bfc.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">由以上的实验可以得出结论,可重复读隔离级别只允许读取已提交记录,而且在一个事务两次读取一个记录期间,其他事务部的更新该记录。但该事务不要求与其他事务可串行化。例如,当一个事务可以找到由一个已提交事务更新的记录,但是可能产生幻读问题(注意是可能,因为数据库对隔离级别的实现有所差别)。像以上的实验,就没有出现数据幻读的问题。</p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 18px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">将A的隔离级别设置为可串行化(Serializable)</h3> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.06808510638297872" data-type="other" data-w="705" src="/upload/6af79c310c33a54490429f57388782a7.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:启动事务,此时数据为初始状态</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.47960618846694797" data-type="other" data-w="711" src="/upload/7dc649b50f3197a56ce3e9cdfa239ec2.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:发现B此时进入了等待状态,原因是因为A的事务尚未提交,只能等待(此时,B可能会发生等待超时)</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.11690140845070422" data-type="other" data-w="710" src="/upload/7525bb6b31248a19cb404dcddeac97e9.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">A:提交事务</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.05352112676056338" data-type="other" data-w="710" src="/upload/24ec1732b88a749be6f91c7d4f059b26.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">B:发现插入成功</p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.056022408963585436" data-type="other" data-w="714" src="/upload/cc587bdf066d1921f0c7e9fd1baf3d8d.other" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;box-sizing: border-box !important;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 15px;margin-bottom: 15px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;">serializable完全锁定字段,若一个事务来查询同一份数据就必须等待,直到前一个事务完成并解除锁定为止。是完整的隔离级别,会锁定对应的数据表格,因而会有效率的问题。</p> <h2 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 22px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;box-sizing: border-box !important;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">原文链接</h2> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="38" data-source-title=""> <section class="js_blockquote_digest"> <section> https://www.jianshu.com/p/8d735db9c2c0 </section> </section> </blockquote> <section class="_135editor" data-role="paragraph" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <br> </section> <section class="_135editor" data-tools="135编辑器" data-id="108" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section style="border-width: initial;border-style: none;border-color: initial;box-sizing: border-box;"> <section style="text-align: center;text-decoration: inherit;color:#fff;box-sizing: border-box;"> <section style="padding:0.4em 0.2em;box-sizing: border-box;border-color:#30cab0;border-radius:50px;background-color:#30cab0;"> <section style="width:70px;margin-top:-5px;float: left;"> <img class="" data-ratio="0.5" src="/upload/754e346d88977c4ada0185706960b005.png" data-type="png" data-w="160" data-width="100%" style="width:100%;margin-left: -30px;"> </section> <section class="135brush" data-brushtype="text" style="font-size: 14px;text-align:left;letter-spacing: 1px;line-height: 1.75em;"> 转载是一种动力 分享是一种美德 </section> </section> </section> </section> </section> <p><br></p>

日均5亿查询量的京东到家订单中心,为什么舍MySQL用ES?

作者:微信小助手

<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.1088" src="/upload/da7cea1bd120e6eb3173bfc708baf6e7.gif" data-type="gif" data-w="625" style=""></p> <p class="" style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="color: rgb(19, 139, 213);"><strong><br></strong></span></p> <p class="" style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="color: rgb(19, 139, 213);"><strong>作者介绍</strong></span></p> <section label="Copyright © 2015 Yead All Rights Reserved." class="" style="margin: 5px auto;letter-spacing: 0.544px;white-space: normal;color: rgb(34, 34, 34);font-size: 14px;background-color: rgb(255, 255, 255);max-width: 100%;line-height: 25.6px;font-family: 微软雅黑;text-align: justify;overflow-wrap: break-word !important;"> <section style="padding-top: 5px;padding-bottom: 5px;max-width: 100%;width: 1133px;text-decoration: inherit;box-sizing: border-box;overflow-wrap: break-word !important;"> <section style="padding-bottom: 5px;padding-left: 20px;max-width: 100%;border-left: 3px solid rgb(153, 153, 153);box-sizing: border-box;overflow-wrap: break-word !important;"> <p><strong><span style="font-size: 16px;">张sir,</span></strong><span style="text-decoration: inherit;letter-spacing: 0.544px;">京东到家研发工程师,主要负责订单中心、商家中心、计费等系统。</span></p> </section> </section> </section> <section data-role="outer" label="Powered by 135editor.com" style="font-size:16px;font-family:微软雅黑;"> <section data-role="paragraph" class="_135editor" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">京东到家订单中心系统业务中,无论是外部商家的订单生产,或是内部上下游系统的依赖,订单查询的调用量都非常大,造成了订单数据读多写少的情况。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">我们把订单数据存储在MySQL中,但显然只通过DB来支撑大量的查询是不可取的。同时对于一些复杂的查询,MySQL支持得不够友好,所以订单中心系统使用了Elasticsearch来承载订单查询的主要压力。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="text-align: center;"><img class="" data-croporisrc="/upload/c97f9d2b67f0ed149331f90f7eb4769a.jpg" data-cropx1="0" data-cropx2="693" data-cropy1="9.32286995515695" data-cropy2="374.46860986547085" data-ratio="0.5252525252525253" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/tibrg3AoIJTsEEHkHOWRD2ibF43qRx13Mxq2XhxjNxR2dMfNyxgDicOG2TBcRTxedibaRAU3F4QHXTOZNxU2eOZKlA/640?wx_fmt=jpeg" data-type="jpeg" data-w="693" style="width: 446px;height: 235px;"></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">Elasticsearch作为一款功能强大的分布式搜索引擎,支持近实时的存储、搜索数据,在京东到家订单系统中发挥着巨大作用,目前订单中心ES集群存储数据量达到10亿个文档,日均查询量达到5亿。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">随着京东到家近几年业务的快速发展,订单中心ES架设方案也不断演进,发展至今ES集群架设是一套实时互备方案,很好地保障了ES集群读写的稳定性,下面就给大家介绍一下这个历程以及过程中遇到的一些坑。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="86122" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;"> <section style="padding-bottom: 2px;text-align: center;color: rgb(255, 255, 255);background-color: rgb(19, 139, 222);box-sizing: border-box;"> <section style="border-bottom: 1px solid rgb(254, 254, 254);border-top-color: rgb(19, 139, 222);border-right-color: rgb(19, 139, 222);border-left-color: rgb(19, 139, 222);padding: 0.5em 1.5em;box-sizing: border-box;"> <p style="font-size: 20px;line-height: 20px;letter-spacing: 0.5px;"><span style="font-size: 16px;"><strong>一、ES集群架设演进历程</strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="max-width: 100%;margin-top: 0.8em;margin-bottom: 0.5em;overflow: hidden;"> <section class="135brush" data-brushtype="text" placeholder="请输入标题" style="height: 36px;display: inline-block;color: rgb(255, 255, 255);font-weight: bold;padding-right: 10px;padding-left: 10px;line-height: 36px;vertical-align: top;background-color: rgb(19, 139, 222);box-sizing: border-box !important;"> <span style="font-size: 15px;">1、初始阶段</span> </section> <section style="display: inline-block;height: 36px;vertical-align: top;border-left: 9px solid #138bde;box-sizing: border-box !important;border-top: 18px solid transparent !important;border-bottom: 18px solid transparent !important;"></section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">订单中心ES初始阶段如一张白纸,架设方案基本没有,很多配置都是保持集群默认配置。整个集群部署在集团的弹性云上,ES集群的节点以及机器部署都比较混乱。同时按照集群维度来看,一个ES集群会有单点问题,显然对于订单中心业务来说也是不被允许的。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="max-width: 100%;margin-top: 0.8em;margin-bottom: 0.5em;overflow: hidden;"> <section class="135brush" data-brushtype="text" placeholder="请输入标题" style="height: 36px;display: inline-block;color: rgb(255, 255, 255);font-weight: bold;padding-right: 10px;padding-left: 10px;line-height: 36px;vertical-align: top;background-color: rgb(19, 139, 222);box-sizing: border-box !important;"> <span style="font-size: 15px;">2、集群隔离阶段</span> </section> <section style="display: inline-block;height: 36px;vertical-align: top;border-left: 9px solid #138bde;box-sizing: border-box !important;border-top: 18px solid transparent !important;border-bottom: 18px solid transparent !important;"></section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">和很多业务一样,ES集群采用的混布的方式。但由于订单中心ES存储的是线上订单数据,偶尔会发生混布集群抢占系统大量资源,导致整个订单中心ES服务异常。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">显然任何影响到订单查询稳定性的情况都是无法容忍的,所以针对于这个情况,先是对订单中心ES所在的弹性云,迁出那些系统资源抢占很高的集群节点,ES集群状况稍有好转。但随着集群数据不断增加,弹性云配置已经不太能满足ES集群,且为了完全的物理隔离,最终干脆将订单中心ES集群部署到高配置的物理机上,ES集群性能又得到提升。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="max-width: 100%;margin-top: 0.8em;margin-bottom: 0.5em;overflow: hidden;"> <section class="135brush" data-brushtype="text" placeholder="请输入标题" style="height: 36px;display: inline-block;color: rgb(255, 255, 255);font-weight: bold;padding-right: 10px;padding-left: 10px;line-height: 36px;vertical-align: top;background-color: rgb(19, 139, 222);box-sizing: border-box !important;"> <span style="font-size: 15px;">3、节点副本调优阶段</span> </section> <section style="display: inline-block;height: 36px;vertical-align: top;border-left: 9px solid #138bde;box-sizing: border-box !important;border-top: 18px solid transparent !important;border-bottom: 18px solid transparent !important;"></section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">ES的性能跟硬件资源有很大关系,当ES集群单独部署到物理机器上时,集群内部的节点并不是独占整台物理机资源,在集群运行的时候同一物理机上的节点仍会出现资源抢占的问题。所以在这种情况下,为了让ES单个节点能够使用最大程度的机器资源,采用每个ES节点部署在单独一台物理机上方式。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">但紧接着,问题又来了,如果单个节点出现瓶颈了呢?我们应该怎么再优化呢?</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">ES查询的原理,当请求打到某号分片的时候,如果没有指定分片类型(Preference参数)查询,请求会负载到对应分片号的各个节点上。而集群默认副本配置是一主一副,针对此情况,我们想到了扩容副本的方式,由默认的一主一副变为一主二副,同时增加相应物理机。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">&nbsp;</span></p> <p style="text-align: center;"><img class="" data-croporisrc="/upload/b3d652dcbebf420c153e9171e6c0fa73.jpg" data-cropx1="0" data-cropx2="492" data-cropy1="0" data-cropy2="342" data-ratio="0.6951219512195121" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/tibrg3AoIJTsEEHkHOWRD2ibF43qRx13MxOks79ic1cDRKZIHRERTkgoqxM63ibZRSS0ibdCw10KbwcXGvdmiaBm37FA/640?wx_fmt=jpeg" data-type="jpeg" data-w="492" style="width: 492px;height: 342px;"></p> <p style="text-align: center;"><span style="font-family: 微软雅黑;letter-spacing: 0.5px;text-align: justify;font-size: 12px;">订单中心ES集群架设示意图</span></p> <p style="text-align: center;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">如图,整个架设方式通过VIP来负载均衡外部请求:</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">第一层Gateway节点实质为ES中Client Node,相当于一个智能负载均衡器,充当着分发请求的角色;</span></p></li> <li><p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">第二层为Data Node,负责存储数据以及执行数据的相关操作。</span></p></li> </ul> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">整个集群有一套主分片,二套副分片(一主二副),从网关节点转发过来的请求,会在打到数据节点之前通过轮询的方式进行均衡。集群增加一套副本并扩容机器的方式,增加了集群吞吐量,从而提升了整个集群查询性能。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">下图为订单中心ES集群各阶段性能示意图,直观地展示了各阶段优化后ES集群性能的显著提升:</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="text-align: center;"><img class="" data-croporisrc="/upload/f8db441ac8409a68e2b2f76cf17b32cf.jpg" data-cropx1="0" data-cropx2="934" data-cropy1="15.860377358490567" data-cropy2="630.8905660377359" data-ratio="0.6595289079229122" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/tibrg3AoIJTsEEHkHOWRD2ibF43qRx13MxFGTzBsgM86nAGloiaGk5mic3mf0cgicQhicc1FBE4Ma0bzibtykdcmVAEnQ/640?wx_fmt=jpeg" data-type="jpeg" data-w="934" style="width: 530px;height: 349px;"></p> <p style="text-align: center;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">当然分片数量和分片副本数量并不是越多越好,在此阶段,我们对选择适当的分片数量做了进一步探索。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">分片数可以理解为MySQL中的分库分表,而当前订单中心ES查询主要分为两类:单ID查询以及分页查询。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">分片数越大,集群横向扩容规模也更大,根据分片路由的单ID查询吞吐量也能大大提升,但聚合的分页查询性能则将降低;分片数越小,集群横向扩容规模也更小,单ID的查询性能也会下降,但分页查询的性能将会提升。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">所以如何均衡分片数量和现有查询业务,我们做了很多次调整压测,最终选择了集群性能较好的分片数。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="max-width: 100%;margin-top: 0.8em;margin-bottom: 0.5em;overflow: hidden;"> <section class="135brush" data-brushtype="text" placeholder="请输入标题" style="height: 36px;display: inline-block;color: rgb(255, 255, 255);font-weight: bold;padding-right: 10px;padding-left: 10px;line-height: 36px;vertical-align: top;background-color: rgb(19, 139, 222);box-sizing: border-box !important;"> <span style="font-size: 15px;">4、主从集群调整阶段</span> </section> <section style="display: inline-block;height: 36px;vertical-align: top;border-left: 9px solid #138bde;box-sizing: border-box !important;border-top: 18px solid transparent !important;border-bottom: 18px solid transparent !important;"></section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">到此,订单中心的ES集群已经初具规模,但由于订单中心业务时效性要求高,对ES查询稳定性要求也高,如果集群中有节点发生异常,查询服务会受到影响,从而影响到整个订单生产流程。很明显这种异常情况是致命的,所以为了应对这种情况,我们初步设想是增加一个备用集群,当主集群发生异常时,可以实时的将查询流量降级到备用集群。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">那备用集群应该怎么来搭?主备之间数据如何同步?备用集群应该存储什么样的数据?</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">考虑到ES集群暂时没有很好的主备方案,同时为了更好地控制ES数据写入,我们采用业务双写的方式来搭设主备集群。每次业务操作需要写入ES数据时,同步写入主集群数据,然后异步写入备集群数据。同时由于大部分ES查询的流量都来源于近几天的订单,且订单中心数据库数据已有一套归档机制,将指定天数之前已经关闭的订单转移到历史订单库。</span><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">所以归档机制中增加删除备集群文档的逻辑,让新搭建的备集群存储的订单数据与订单中心线上数据库中的数据量保持一致。同时使用ZK在查询服务中做了流量控制开关,保证查询流量能够实时降级到备集群。在此,订单中心主从集群完成,ES查询服务稳定性大大提升。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="text-align: center;"><img class="" data-croporisrc="/upload/59b806c17fd3f2dc7c0b186dddb8653a.jpg" data-cropx1="0" data-cropx2="505" data-cropy1="3.884615384615384" data-cropy2="265.4487179487179" data-ratio="0.5188118811881188" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/tibrg3AoIJTsEEHkHOWRD2ibF43qRx13MxUphFJOZq9HPZhJ26bnLhCUlvJ2dGxUpMvghKeP0o4HpNMu60iaYnEXg/640?wx_fmt=jpeg" data-type="jpeg" data-w="505" style="width: 390px;height: 202px;"></p> <p style="text-align: center;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="max-width: 100%;margin-top: 0.8em;margin-bottom: 0.5em;overflow: hidden;"> <section class="135brush" data-brushtype="text" placeholder="请输入标题" style="height: 36px;display: inline-block;color: rgb(255, 255, 255);font-weight: bold;padding-right: 10px;padding-left: 10px;line-height: 36px;vertical-align: top;background-color: rgb(19, 139, 222);box-sizing: border-box !important;"> <span style="font-size: 15px;">5、现今:实时互备双集群阶段</span> </section> <section style="display: inline-block;height: 36px;vertical-align: top;border-left: 9px solid #138bde;box-sizing: border-box !important;border-top: 18px solid transparent !important;border-bottom: 18px solid transparent !important;"></section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">期间由于主集群ES版本是较低的1.7,而现今ES稳定版本都已经迭代到6.x,新版本的ES不仅性能方面优化很大,更提供了一些新的好用的功能,所以我们对主集群进行了一次版本升级,直接从原来的1.7升级到6.x版本。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">集群升级的过程繁琐而漫长,不但需要保证线上业务无任何影响,平滑无感知升级,同时由于ES集群暂不支持从1.7到6.x跨越多个版本的数据迁移,所以需要通过重建索引的方式来升级主集群,具体升级过程就不在此赘述了。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">主集群升级的时候必不可免地会发生不可用的情况,但对于订单中心ES查询服务,这种情况是不允许的。所以在升级的阶段中,备集群暂时顶上充当主集群,来支撑所有的线上ES查询,保证升级过程不影响正常线上服务。同时针对于线上业务,我们对两个集群做了重新的规划定义,承担的线上查询流量也做了重新的划分。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">备集群存储的是线上近几天的热点数据,数据规模远小于主集群,大约是主集群文档数的十分之一。集群数据量小,在相同的集群部署规模下,备集群的性能要优于主集群。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">然而在线上真实场景中,线上大部分查询流量也来源于热点数据,所以用备集群来承载这些热点数据的查询,而备集群也慢慢演变成一个热数据集群。之前的主集群存储的是全量数据,用该集群来支撑剩余较小部分的查询流量,这部分查询主要是需要搜索全量订单的特殊场景查询以及订单中心系统内部查询等,而主集群也慢慢演变成一个冷数据集群。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">同时备集群增加一键降级到主集群的功能,两个集群地位同等重要,但都可以各自降级到另一个集群。双写策略也优化为:假设有AB集群,正常同步方式写主(A集群)异步方式写备(B集群)。A集群发生异常时,同步写B集群(主),异步写A集群(备)。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="text-align: center;"><img class="" data-croporisrc="/upload/d9c04497bfda0d6d486ad930d599ebd5.jpg" data-cropx1="0" data-cropx2="708" data-cropy1="5.075268817204301" data-cropy2="356.5376344086022" data-ratio="0.4943502824858757" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/tibrg3AoIJTsEEHkHOWRD2ibF43qRx13MxebicNPiaVWMiacIZzGia9OYFaOax7U6VsxM0mNx28Lkp0UfNlEWwqFuKjA/640?wx_fmt=jpeg" data-type="jpeg" data-w="708" style="width:75%;height:auto;"></p> <p style="text-align: center;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="86122" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;"> <section style="padding-bottom: 2px;text-align: center;color: rgb(255, 255, 255);background-color: rgb(19, 139, 222);box-sizing: border-box;"> <section style="border-bottom: 1px solid rgb(254, 254, 254);border-top-color: rgb(19, 139, 222);border-right-color: rgb(19, 139, 222);border-left-color: rgb(19, 139, 222);padding: 0.5em 1.5em;box-sizing: border-box;"> <p style="font-size: 20px;line-height: 20px;letter-spacing: 0.5px;"><strong><span style="font-size: 16px;">二、ES订单数据的同步方案</span></strong></p> </section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">MySQL数据同步到ES中,大致总结可以分为两种方案:</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><strong><span style="font-size: 15px;">方案1:</span></strong><span style="font-size: 15px;">监听MySQL的Binlog,分析Binlog将数据同步到ES集群中。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">优点:业务与ES数据耦合度低,业务逻辑中不需要关心ES数据的写入;</span></p></li> <li><p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">缺点:Binlog模式只能使用ROW模式,且引入了新的同步服务,增加了开发量以及维护成本,也增大了ES同步的风险。</span></p></li> </ul> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><strong><span style="font-size: 15px;">方案2:</span></strong><span style="font-size: 15px;">直接通过ES API将数据写入到ES集群中。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">优点:简洁明了,能够灵活的控制数据的写入;</span></p></li> <li><p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;caret-color: red;">缺点:与业务耦合严重,强依赖于业务系统的写入方式。</span></p></li> </ul> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">考虑到订单系统ES服务的业务特殊性,对于订单数据的实时性较高,显然监听Binlog的方式相当于异步同步,有可能会产生较大的延时性。且方案1实质上跟方案2类似,但又引入了新的系统,维护成本也增高。所以订单中心ES采用了直接通过ES API写入订单数据的方式,该方式简洁灵活,能够很好的满足订单中心数据同步到ES的需求。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">由于ES订单数据的同步采用的是在业务中写入的方式,当新建或更新文档发生异常时,如果重试势必会影响业务正常操作的响应时间。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">所以每次业务操作只更新一次ES,如果发生错误或者异常,在数据库中插入一条补救任务,有Worker任务会实时地扫这些数据,以数据库订单数据为基准来再次更新ES数据。通过此种补偿机制,来保证ES数据与数据库订单数据的最终一致性。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="86122" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;"> <section style="padding-bottom: 2px;text-align: center;color: rgb(255, 255, 255);background-color: rgb(19, 139, 222);box-sizing: border-box;"> <section style="border-bottom: 1px solid rgb(254, 254, 254);border-top-color: rgb(19, 139, 222);border-right-color: rgb(19, 139, 222);border-left-color: rgb(19, 139, 222);padding: 0.5em 1.5em;box-sizing: border-box;"> <p style="font-size: 20px;line-height: 20px;letter-spacing: 0.5px;"><strong><span style="font-size: 16px;">三、遇到的一些坑</span></strong></p> </section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="max-width: 100%;margin-top: 0.8em;margin-bottom: 0.5em;overflow: hidden;"> <section class="135brush" data-brushtype="text" placeholder="请输入标题" style="height: 36px;display: inline-block;color: rgb(255, 255, 255);font-weight: bold;padding-right: 10px;padding-left: 10px;line-height: 36px;vertical-align: top;background-color: rgb(19, 139, 222);box-sizing: border-box !important;"> <span style="font-size: 15px;">1、实时性要求高的查询走DB</span> </section> <section style="display: inline-block;height: 36px;vertical-align: top;border-left: 9px solid #138bde;box-sizing: border-box !important;border-top: 18px solid transparent !important;border-bottom: 18px solid transparent !important;"></section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">对于ES写入机制的有了解的同学可能会知道,新增的文档会被收集到Indexing Buffer,然后写入到文件系统缓存中,到了文件系统缓存中就可以像其他的文件一样被索引到。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">然而默认情况文档从Indexing Buffer到文件系统缓存(即Refresh操作)是每秒分片自动刷新,所以这就是我们说ES是近实时搜索而非实时的原因:文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">当前订单系统ES采用的是默认Refresh配置,故对于那些订单数据实时性比较高的业务,直接走数据库查询,保证数据的准确性。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="text-align: center;"><img class="" data-croporisrc="/upload/e96a6428369614db857b3902554b745a.jpg" data-cropx1="0" data-cropx2="1080" data-cropy1="0" data-cropy2="514.8387096774193" data-ratio="0.4759259259259259" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/tibrg3AoIJTsEEHkHOWRD2ibF43qRx13MxlTL890r0Q5aeBXBFWLHpEcJpCy2bibiaW3QebCT4dNqe3YpDMTzOMJJQ/640?wx_fmt=jpeg" data-type="jpeg" data-w="1080" style="width: 558px;height: 266px;"></p> <p style="text-align: center;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="max-width: 100%;margin-top: 0.8em;margin-bottom: 0.5em;overflow: hidden;"> <section class="135brush" data-brushtype="text" placeholder="请输入标题" style="height: 36px;display: inline-block;color: rgb(255, 255, 255);font-weight: bold;padding-right: 10px;padding-left: 10px;line-height: 36px;vertical-align: top;background-color: rgb(19, 139, 222);box-sizing: border-box !important;"> <span style="font-size: 15px;">2、避免深分页查询</span> </section> <section style="display: inline-block;height: 36px;vertical-align: top;border-left: 9px solid #138bde;box-sizing: border-box !important;border-top: 18px solid transparent !important;border-bottom: 18px solid transparent !important;"></section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">ES集群的分页查询支持from和size参数,查询的时候,每个分片必须构造一个长度为from+size的优先队列,然后回传到网关节点,网关节点再对这些优先队列进行排序找到正确的size个文档。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">假设在一个有6个主分片的索引中,from为10000,size为10,每个分片必须产生10010个结果,在网关节点中汇聚合并60060个结果,最终找到符合要求的10个文档。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">由此可见,当from足够大的时候,就算不发生OOM,也会影响到CPU和带宽等,从而影响到整个集群的性能。所以应该避免深分页查询,尽量不去使用。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="39" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="max-width: 100%;margin-top: 0.8em;margin-bottom: 0.5em;overflow: hidden;"> <section class="135brush" data-brushtype="text" placeholder="请输入标题" style="height: 36px;display: inline-block;color: rgb(255, 255, 255);font-weight: bold;padding-right: 10px;padding-left: 10px;line-height: 36px;vertical-align: top;background-color: rgb(19, 139, 222);box-sizing: border-box !important;"> <span style="font-size: 15px;">3、FieldData与Doc Values</span> </section> <section style="display: inline-block;height: 36px;vertical-align: top;border-left: 9px solid #138bde;box-sizing: border-box !important;border-top: 18px solid transparent !important;border-bottom: 18px solid transparent !important;"></section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><strong><span style="font-size: 15px;">FieldData</span></strong></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">线上查询出现偶尔超时的情况,通过调试查询语句,定位到是跟排序有关系。排序在es1.x版本使用的是FieldData结构,FieldData占用的是JVM Heap内存,JVM内存是有限,对于FieldData Cache会设定一个阈值。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">如果空间不足时,使用最久未使用(LRU)算法移除FieldData,同时加载新的FieldData Cache,加载的过程需要消耗系统资源,且耗时很大。所以导致这个查询的响应时间暴涨,甚至影响整个集群的性能。针对这种问题,解决方式是采用Doc Values。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><strong><span style="font-size: 15px;">Doc Values</span></strong></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;"><br></span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">Doc Values是一种列式的数据存储结构,跟FieldData很类似,但其存储位置是在Lucene文件中,即不会占用JVM Heap。随着ES版本的迭代,Doc Values比FieldData更加稳定,Doc Values在2.x起为默认设置。</span></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <section class="_135editor" data-tools="135编辑器" data-id="86122" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;" data-color="#138bde" data-custom="#138bde"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;"> <section style="padding-bottom: 2px;text-align: center;color: rgb(255, 255, 255);background-color: rgb(19, 139, 222);box-sizing: border-box;"> <section style="border-bottom: 1px solid rgb(254, 254, 254);border-top-color: rgb(19, 139, 222);border-right-color: rgb(19, 139, 222);border-left-color: rgb(19, 139, 222);padding: 0.5em 1.5em;box-sizing: border-box;"> <p style="font-size: 20px;line-height: 20px;letter-spacing: 0.5px;"><span style="font-size: 16px;"><strong>四、总结</strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><br></p> <p style="line-height: 1.75em;letter-spacing: 0.5px;margin-left: 5px;margin-right: 5px;text-align: justify;"><span style="font-size: 15px;">架构的快速迭代源于业务的快速发展,正是由于近几年到家业务的高速发展,订单中心的架构也不断优化升级。而架构方案没有最好的,只有最合适的,相信再过几年,订单中心的架构又将是另一个面貌,但吞吐量更大,性能更好,稳定性更强,将是订单中心系统永远的追求。</span></p> </section> </section> <p><br></p> <section class="" data-tools="135编辑器" data-id="88286" style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);"> <section style="margin-top: 10px;margin-bottom: 10px;"> <section style="margin-top: -4px;padding: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <section class=""> <p style="margin-right: 5px;margin-left: 5px;letter-spacing: 0.5px;line-height: 1.5em;"><span style="color: rgb(127, 127, 127);letter-spacing: 0.544px;font-size: 14px;">作者:张sir</span></p> <p style="margin-right: 5px;margin-left: 5px;letter-spacing: 0.5px;line-height: 1.5em;"><span style="color: rgb(127, 127, 127);letter-spacing: 0.544px;font-size: 14px;">来源:京东技术订阅号(ID:<span style="font-family: 微软雅黑;letter-spacing: 0.544px;">jingdongjishu</span>)</span></p> <p style="margin-right: 5px;margin-left: 5px;letter-spacing: 0.5px;line-height: 1.5em;"><span style="max-width: 100%;color: rgb(127, 127, 127);font-size: 14px;">dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn</span></p> </section> </section> </section> </section> <section data-role="paragraph" class="" style="font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;color: rgb(62, 62, 62);"> <p style="max-width: 100%;min-height: 1em;text-align: center;line-height: 1.5em;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;text-align: center;line-height: 1.5em;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><img class="" data-ratio="0.06323529411764706" src="/upload/40534c8d76805d9aebe348b342b414a.png" data-type="png" data-w="680" style="display: inline;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;visibility: visible !important;width: 300px !important;" title="分割线 卡通" width="300px"></p> <p style="max-width: 100%;min-height: 1em;text-align: center;line-height: 1.5em;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><br></p> </section> <p class="" style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;"><strong>近期热文</strong></p> <p class="" style="text-align: center;"><a href="http://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&amp;mid=2650773592&amp;idx=1&amp;sn=2f8ffa31ace5335d61b2f7ef7a24b5a5&amp;chksm=f3f92dcdc48ea4dbf7d4bb1a5ebd24fabde28554f8d40f0c76b7e69b916182842b717797e5c9&amp;scene=21#wechat_redirect" target="_blank" style="text-decoration: underline;font-size: 12px;color: rgb(136, 136, 136);" data-linktype="2"><span style="font-size: 12px;color: rgb(136, 136, 136);">为运维质量、效率和成本保驾护航,携程请了谁来帮忙?</span></a><br></p> <p class="" style="text-align: center;"><a href="http://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&amp;mid=2650773558&amp;idx=1&amp;sn=96f82c1de66d8fe597d22dcf512b7843&amp;chksm=f3f92da3c48ea4b527efa7ffc38cd6a2970c7c669776675d368e973c6a6f02c8edee46728bfb&amp;scene=21#wechat_redirect" target="_blank" style="text-decoration: underline;font-size: 12px;color: rgb(136, 136, 136);" data-linktype="2"><span style="font-size: 12px;color: rgb(136, 136, 136);">还有这些MySQL高性能索引优化策略等你试用</span></a><br></p> <p class="" style="text-align: center;"><a href="http://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&amp;mid=2650773501&amp;idx=1&amp;sn=fb640d105ba1cb9a1e4dd181c1e9aac2&amp;chksm=f3f92268c48eab7eed67f2965124007fd03e2c51bc72c09d4c8bdf75083c0a5152b32784b326&amp;scene=21#wechat_redirect" target="_blank" style="text-decoration: underline;font-size: 12px;color: rgb(136, 136, 136);" data-linktype="2"><span style="font-size: 12px;color: rgb(136, 136, 136);">Redis存储总用String?你大概错过了更优的使用方法</span></a><br></p> <p class="" style="text-align: center;"><a href="http://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&amp;mid=2650773492&amp;idx=1&amp;sn=c553bbed265f950e12858017cd402fa6&amp;chksm=f3f92261c48eab774a24cb874ea9b3b3bc72407462dff9342579cf862f809417203bb9b68759&amp;scene=21#wechat_redirect" target="_blank" style="text-decoration: underline;font-size: 12px;color: rgb(136, 136, 136);" data-linktype="2"><span style="font-size: 12px;color: rgb(136, 136, 136);">面对“恐龙级”老旧系统,怎样用微服务实现敏捷交付?</span></a><br></p> <p class="" style="text-align: center;"><a href="http://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&amp;mid=2650773491&amp;idx=1&amp;sn=74b8d3d637ea40ab3c3a675602c42080&amp;chksm=f3f92266c48eab706496418478aee51097d509bc8d78c170214296e5e2157ad40dd765f6be8d&amp;scene=21#wechat_redirect" target="_blank" style="text-decoration: underline;font-size: 12px;color: rgb(136, 136, 136);" data-linktype="2"><span style="font-size: 12px;color: rgb(136, 136, 136);">2周内交付85%以上需求,阿里工程师有哪些策略?</span></a><br></p> <p class="" style="margin-right: 8px;margin-left: 8px;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);letter-spacing: 0.5px;text-align: justify;line-height: 1.75em;"><br></p> <p class="" style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;"><img class="" data-copyright="0" data-ratio="0.36086956521739133" data-s="300,640" src="/upload/34c97e48356fa746aa5f98cb6dd83c00.jpg" data-type="jpeg" data-w="1150" style="visibility: visible !important;width: 677px !important;"></p>

Java设计模式(转)——18.命令模式

作者:じ☆ve宝贝

## 18.命令模式(Command) 命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的。我们看看关系图: ![命令设计模式](/upload/content29.png "命令设计模式") Invoker是调用者(司令员),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象,看实现代码: ``` public interface Command { public void exe(); } ``` ``` public class MyCommand implements Command { private Receiver receiver; public MyCommand(Receiver receiver) { this.receiver = receiver; } @Override public void exe() { receiver.action(); } } ``` ``` public class Receiver { public void action(){ System.out.println("command received!"); } } ``` ``` public class Invoker { private Command command; public Invoker(Command command) { this.command = command; } public void action(){ command.exe(); } } ``` 测试类: ``` public class Test { public static void main(String[] args) { Receiver receiver = new Receiver(); Command cmd = new MyCommand(receiver); Invoker invoker = new Invoker(cmd); invoker.action(); } } ``` 输出:command received! 这个很好理解,命令模式的目的就是达到命令的发出者和执行者之间解耦,实现请求和执行分开,熟悉Struts的同学应该知道,Struts其实就是一种将请求和呈现分离的技术,其中必然涉及命令模式的思想!