文章列表

CTO要我把这份MySQL规范贴在工位上!

作者:微信小助手

<section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="padding: 10px 10px 0px;background-color: rgb(239, 239, 239);box-sizing: border-box;"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;" title=""> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span style="letter-spacing: 1px;">因为工作岗位的原因,负责制定了关于后端组数据库的规约规范,作为所有产品线的规范,历经几版的修改,最终形成下边的文本。</span></p> </section> <section style="clear: both;box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.5611205432937182" data-s="300,640" src="/upload/4289fd5e91144abbc836d92f8e083149.png" data-type="png" data-w="1178" style=""> </section> <section style="text-align: center;line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;"><em>图片来自 Pexels</em></span> <br> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">规范在整个后端执行也有大半年的时间,对于整个团队在开发阶段就减少不恰当的建表语句、错误 SQL、错误的索引有积极的意义,故分享出来给大家参考。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">下边分为建表规约、SQL 规约、索引规约三个部分,每部分的每一条都有强制、建议两个级别,大家在参考时,根据自己公司的情况来权衡。</span></p> <p style="line-height: normal;"><br></p> <section data-tools="135编辑器" data-id="86318" data-color="#138bde" data-custom="#138bde"> <section> <section> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin: 0.5em 0px;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-color: rgb(89, 89, 89);border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">建表规约</p> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】</span>:</strong><span style="font-size: 15px;"><strong>①</strong></span><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">存储引擎必须使用 InnoDB</span></strong></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">InnoDB 支持事物、行级锁、并发性能更好,CPU 及内存缓存页优化使得资源利用率更高。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:②每张表必须设置一个主键 ID,且这个主键 ID 使用自增主键(在满足需要的情况下尽量短),除非在分库分表环境下</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">由于 InnoDB 组织数据的方式决定了需要有一个主键,而且若是这个主键 ID 是单调递增的可以有效提高插入的性能,避免过多的页分裂、减少表碎片提高空间的使用率。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而在分库分表环境下,则需要统一来分配各个表中的主键值,从而避免整个逻辑表中主键重复。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:③必须使用 utf8mb4 字符集</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在 MySQL 中的 UTF-8 并非“真正的 UTF-8”,而 utf8mb4”才是真正的“UTF-8”。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:④数据库表、表字段必须加入中文注释</span></strong></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">大家都别懒。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:⑤库名、表名、字段名均小写,下划线风格,不超过 32 个字符,必须见名知意,禁止拼音英文混用</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:约定。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:⑥单表列数目必须小于 30,若超过则应该考虑将表拆分</span></strong></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">单表列数太多使得 MySQL 服务器处理 InnoDB 返回数据之间的映射成本太高。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:⑦禁止使用外键,如果有外键完整性约束,需要应用程序控制</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">外键会导致表与表之间耦合,UPDATE 与 DELETE 操作都会涉及相关联的表,十分影响 SQL 的性能,甚至会造成死锁。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:⑧必须把字段定义为 NOT NULL 并且提供默认值</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">解读:</span><br></p> <ul style="list-style-type: disc;" class="list-paddingleft-2"> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">NULL 的列使索引/索引统计/值比较都更加复杂,对 MySQL 来说更难优化。</span></p></li> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">NULL 这种类型 MySQL 内部需要进行特殊处理,增加数据库处理记录的复杂性;同等条件下,表中有较多空字段的时候,数据库的处理性能会降低很多。</span></p></li> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">NULL 值需要更多的存储空,无论是表还是索引中每行中的 NULL 的列都需要额外的空间来标识。</span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><strong>【强制】:⑨禁用保留字,如 DESC、RANGE、MARCH 等</strong></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">请参考 MySQL 官方保留字。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:⑩如果存储的字符串长度几乎相等,使用 CHAR 定长字符串类型</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:能够减少空间碎片,节省存储空间。</span> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:</span></strong> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">⑪</span></strong> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在一些场景下,考虑使用 TIMESTAMP 代替 DATETIME</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">解读:</span> <br> </section> <ul style="list-style-type: disc;" class="list-paddingleft-2"> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这两种类型的都能表达"yyyy-MM-dd HH:mm:ss"格式的时间,TIMESTAMP 只需要占用 4 个字节的长度,可以存储的范围为(1970-2038)年,在各个时区,所展示的时间是不一样的。</span></p></li> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而 DATETIME 类型占用 8 个字节,对时区不敏感,可以存储的范围为(1001-9999)年。</span></p></li> </ul> <section data-role="list"> <p style="line-height: normal;"><br></p> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:⑫当心自动生成的 Schema,建议所有的 Schema 手动编写</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">对于一些数据库客户端不要太过信任。</span> </section> <section style="line-height: normal;"> <br> </section> <section data-tools="135编辑器" data-id="86318" data-color="#138bde" data-custom="#138bde"> <section> <section> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin: 0.5em 0px;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-color: rgb(89, 89, 89);border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">SQL 规约</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: normal;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:①为了充分利用缓存,不允许使用自定义函数、存储函数、用户变量</span></strong></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL 库中的系统表,其查询结果都不会被缓存。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">比如函数 NOW() 或者 CURRENT_DATE() 会因为不同的查询时间,返回不同的查询结果。</span></p> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:②在查询中指定所需的列,而不是直接使用“ *”返回所有的列</span></strong> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">解读:</span> <br> </section> <ul style="list-style-type: disc;" class="list-paddingleft-2"> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">读取不需要的列会增加 CPU、IO、NET 消耗。</span></p></li> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">不能有效的利用覆盖索引。</span></p></li> </ul> <section data-role="list"> <p style="line-height: normal;"><br></p> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:③不允许使用属性隐式转换</span></strong> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">假设我们在手机号列上添加了索引,然后执行下面的 SQL 会发生什么?<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">explain SELECT user_name FROM parent WHERE phone=13812345678;很明显就是索引不生效,会全表扫描。</span></p> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:④在 WHERE 条件的属性上使用函数或者表达式</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MySQL 无法自动解析这种表达式,无法使用到索引。</span> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:</span></strong> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"></span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">⑤</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">禁止使用外键与级联,一切外键概念必须在应用层解决</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"></span> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。</span> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:⑥应尽量避免在 WHERE 子句中使用 or 作为连接条件</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">根据情况可以选择使用 UNION ALL 来代替 OR。</span> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:⑦不允许使用 % 开头的模糊查询</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">根据索引的最左前缀原理,%开头的模糊查询无法使用索引,可以使用 ES 来做检索。</span> </section> <p style="line-height: normal;"><br></p> <section data-tools="135编辑器" data-id="86318" data-color="#138bde" data-custom="#138bde"> <section> <section> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin: 0.5em 0px;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-color: rgb(89, 89, 89);border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">索引规约</p> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:①避免在更新比较频繁、区分度不高的列上单独建立索引</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">区分度不高的列单独创建索引的优化效果很小,但是较为频繁的更新则会让索引的维护成本更高。</span> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:②JOIN 的表不允许超过五个。需要 JOIN 的字段,数据类型必须绝对一致; 多表关联查询时,保证被关联的字段需要有索引</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">太多表的 JOIN 会让 MySQL 的优化器更难权衡出一个“最佳”的执行计划(可能性为表数量的阶乘),同时要注意关联字段的类型、长度、字符编码等等是否一致。</span> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:③在一个联合索引中,若第一列索引区分度等于 1,那么则不需要建立联合索引</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">索引通过第一列就能够完全定位的数据,所以联合索引的后边部分是不需要的。</span> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【强制】:④建立联合索引时,必须将区分度更高的字段放在左边</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">区分度更高的列放在左边,能够在一开始就有效的过滤掉无用数据。提高索引的效率,相应我们在 Mapper 中编写 SQL 的 WHERE 条件中有多个条件时,需要先看看当前表是否有现成的联合索引直接使用,注意各个条件的顺序尽量和索引的顺序一致。</span> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:⑤利用覆盖索引来进行查询操作,避免回表</span></strong> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">覆盖查询即是查询只需要通过索引即可拿到所需 DATA,而不再需要再次回表查询,所以效率相对很高。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们在使用 EXPLAIN 的结果,extra 列会出现:"using index"。这里也要强调一下不要使用“SELECT * ”,否则几乎不可能使用到覆盖索引。</span></p> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:⑥在较长 VARCHAR 字段,例如 VARCHAR(100) 上建立索引时,应指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度即可</span></strong> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">索引的长度与区分度是一对矛盾体,一般对字符串类型数据,若长度为 20 的索引,区分度会高达 90% 以上,则可以考虑创建长度例为 20 的索引,而非全字段索引。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">例如可以使用 SELECT COUNT(DISTINCT LEFT(lesson_code, 20))/COUNT(*) FROM lesson;来确定 lesson_code 字段字符长度为 20 时文本区分度。</span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:⑦如果有 ORDER BY 的场景,请注意利用索引的有序性</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">ORDER BY 最后的字段是联合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。</span></p> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">解读:</span> <br> </section> <ul style="list-style-type: disc;" class="list-paddingleft-2"> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">假设有查询条件为 WHERE a=? and b=? ORDER BY c;存在索引:a_b_c,则此时可以利用索引排序。</span></p></li> <li><p><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">反例:在查询条件中包含了范围查询,那么索引有序性无法利用,如:WHERE a&gt;10 ORDER BY b;索引 a_b 无法排序。</span></p></li> </ul> <section data-role="list"> <p style="line-height: normal;"><br></p> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:⑧在 Where 中索引的列不能某个表达式的一部分,也不能是函数的参数</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">即是某列上已经添加了索引,但是若此列成为表达式的一部分、或者是函数的参数,MySQL 无法将此列单独解析出来,索引也不会生效。</span> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:⑨我们在 Where 条件中使用范围查询时,索引最多用于一个范围条件,超过一个则后边的不走索引</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MySQL 能够使用多个范围条件里边的最左边的第一个范围查询,但是后边的范围查询则无法使用。</span> </section> <section style="line-height: normal;"> <br> </section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">【建议】:⑩在多个表进行外连接时,表之间的关联字段类型必须完全一致</span></strong> </section> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">解读:</span></strong> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当两个表进行 Join 时,字段类型若没有完全一致,则加索引也不会生效,这里的完全一致包括但不限于字段类型、字段长度、字符集、Collection 等等。</span> </section> <p style="line-height: normal;"><br></p> <section data-tools="135编辑器" data-id="85988" data-color="#138bde" data-custom="#138bde"> <section data-width="100%"> <section> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(71, 193, 168);"><em><span style="letter-spacing: 1px;">参考资料:</span></em></span> </section> </section> </section> </section> <ul style="list-style-type: disc;" class="list-paddingleft-2"> <li><p><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">《High.Performance.MySQL.3rd.Edition》</span></em></span></p></li> <li><p><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">《阿里巴巴java开发手册》</span></em></span></p></li> </ul> <section data-role="paragraph"> <p style="line-height: normal;"><br></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;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;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">作者:</span></em><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">浮雷</span></em><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></em></span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;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;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;max-width: 100%;color: rgb(89, 89, 89);letter-spacing: 1px;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">编辑:陶家龙</span></em></span></em></span><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 1.75em;font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;">出处:</span></em><em><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">https://juejin.im/post/6871969929365553165</span></em></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.39375" src="/upload/eccf90ae5f48405df149baa3056d4bf3.png" data-type="gif" data-w="640" style=""></p> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="margin: 0.5em 0px;box-sizing: border-box;"> <section style="font-size: 15px;border-style: solid;border-width: 0px 0px 1px;color: rgb(89, 89, 89);border-bottom: 1px solid rgba(215, 215, 215, 0.96);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span style="letter-spacing: 1px;"><strong>精彩文章推荐:</strong></span></p> </section> </section> </section> <p style="line-height: 2em;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655837591&amp;idx=2&amp;sn=62612861416d958bb15a416bf1f9caf3&amp;chksm=bd7490408a031956f2887db082c68058b75d082d565469a2ee550805bc1e1911abc6a7f0ff1e&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">明明加了索引,为什么查询还是慢?</span></a><br><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655837574&amp;idx=2&amp;sn=e89204058938fa90d8070b1f4feb4458&amp;chksm=bd7490518a031947e1c91ee21b3baf9eb4763ce2b7feb2026176274eea1534cfa59c5b3e309c&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">CTO说了,delete后不加limit,直接滚蛋!</span></a><br><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655837426&amp;idx=1&amp;sn=956acc1972dea87c401e8f9e148bc013&amp;chksm=bd7491258a031833183d11638b7039c37de9fde28896200d3dcc420f81d35e32c519754ce804&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">啥?我写的一条SQL让公司网站瘫痪了...</span></a><br></p> </section>

日订单量达到100万单后,我们做了订单中心重构

作者:微信小助手

<p style="white-space: normal;" data-mpa-powered-by="yiban.io"><strong style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;text-align: left;color: rgb(214, 168, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;">作者简介:曾任职于阿里巴巴,每日优鲜等互联网公司,任技术总监。</span></strong></p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;">最近很多读者朋友留言,希望“二马”多写一些实际工作经历以及工作中遇到的问题和技术解决方案。应大家要求,本文介绍一次订单中心重构的经历。</p> <p><br></p> <p><span style="color: rgb(255, 104, 39);"><strong>背景</strong></span></p> <hr style="border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p><br></p> <p>几年前我曾经服务过的一家电商公司,随着业务增长我们每天的订单量很快从30万单增长到了100万单,订单总量也突破了一亿。当时用的Mysql数据库。根据监控,我们的每秒最高订单量已经达到了2000笔(不包括秒杀,秒杀TPS已经上万了。秒杀我们有一套专门的解决方案,详见《秒杀系统设计~亿级用户》)。不过,直到此时,订单系统还是单库单表,幸好当时数据库服务器配置不错,我们的系统才能撑住这么大的压力。<br></p> <p><br></p> <p>业务量还在快速增长,再不重构系统早晚出大事,我们花了一天时间快速制定了重构方案。<br></p> <p><br></p> <p>重构?说这么高大上,不就是分库分表吗?的确,就是<strong>分库分表</strong>。不过除了分库分表,还包括<strong>管理端的解决方案</strong>,比如运营,客服和商务需要从多维度查询订单数据,分库分表后,怎么满足大家的需求?分库分表后,上线方案和<strong>数据</strong><strong>不停机迁移</strong>方案都需要慎重考虑。为了保证系统稳定,还需要考虑相应的<strong>降级方案</strong>。</p> <p><br></p> <p><span style="color: rgb(255, 104, 39);"></span><span style="color: rgb(255, 104, 39);"><strong>为什么要分库分表?</strong></span></p> <hr style="border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p data-tool="mdnice编辑器"><br></p> <p data-tool="mdnice编辑器">当数据库产生性能瓶颈:IO瓶颈或CPU瓶颈。两种瓶颈最终都会导致数据库的活跃连接数增加,进而达到数据库可承受的最大活跃连接数阈值。终会导致应用服务无连接可用,造成灾难性后果。可以先从代码<span style="font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);">,</span>sql<span style="font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);">,</span>索引几方面进行优化。如果这几方面已经没有太多优化的余地,就该考虑分库分表了。</p> <p data-tool="mdnice编辑器"><br></p> <h3 data-tool="mdnice编辑器">1、IO瓶颈</h3> <p data-tool="mdnice编辑器"><br></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p data-tool="mdnice编辑器">磁盘读IO瓶颈。由于热点数据太多,数据库缓存完全放不下,查询时会产生大量的磁盘IO,查询速度会比较慢,这样会导致产生大量活跃连接,最终可能会发展成无连接可用的后果。可以采用一主多从,读写分离的方案,用多个从库分摊查询流量。或者采用分库+水平分表(把一张表的数据拆成多张表来存放,比如订单表可以按user_id来拆分)的方案。</p><p data-tool="mdnice编辑器"><br></p></li> <li><p data-tool="mdnice编辑器">第二种:磁盘写IO瓶颈。由于数据库写入频繁,会产生频繁的磁盘写入IO操作,频繁的磁盘IO操作导致产生大量活跃连接,最终同样会发展成无连接可用的后果。这时只能采用分库方案,用多个库来分摊写入压力。再加上水平分表的策略,分表后,单表存储的数据量会更小,插入数据时索引查找和更新的成本会更低,插入速度自然会更快。</p></li> </ul> <p data-tool="mdnice编辑器"><br></p> <h3 data-tool="mdnice编辑器">2、CPU瓶颈</h3> <p><br></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p data-tool="mdnice编辑器">SQL问题。如果SQL中包含join,group by,order by,非索引字段条件查询等增加CPU运算的操作,会对CPU产生明显的压力。&nbsp;这时可以考虑SQL优化,创建适当的索引,也可以把一些计算量大的SQL逻辑放到应用中处理。</p><p data-tool="mdnice编辑器"><br></p></li> <li><p data-tool="mdnice编辑器">单表数据量太大。由于单张表数据量过大,比如超过一亿,查询时遍历树的层次太深或者扫描的行太多,SQL效率会很低,也会非常消耗CPU。这时可以根据业务场景水平分表。</p></li> </ul> <p data-tool="mdnice编辑器"><br></p> <p><span style="color: rgb(255, 104, 39);"><strong>分库分表方案</strong></span></p> <hr style="border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p><br></p> <p>分库分表主要有两种方案:<br></p> <p><br></p> <ol class="list-paddingleft-2" style="list-style-type: decimal;"> <li><p>利用MyCat,KingShard这种代理中间件分库分表。好处是和业务代码耦合度很低,只需做一些配置即可,接入成本低。缺点是这种代理中间件需要单独部署,所以从调用连路上又多了一层。而且分库分表逻辑完全由代理中间件管理,对于程序员完全是黑盒,一旦代理本身出问题(比如出错或宕机),会导致无法查询和存储相关业务数据,引发灾难性的后果。如果不熟悉代理中间件源码,排查问题会非常困难。曾经有公司使用MyCat,线上发生故障后,被迫修改方案,三天三夜才恢复系统。CTO也废了!</p><p><br></p></li> <li><p>利用Sharding-Jdbc,TSharding等以Jar包形式呈现的轻量级组件分库分表。缺点是,会有一定的代码开发工作量,对业务有一些侵入性。好处是对程序员透明,程序员对分库分表逻辑的把控会更强,一旦发生故障,排查问题会比较容易。</p></li> </ol> <p><br></p> <p>稳妥起见,我们选用了第二种方案,使用更轻量级的Sharding-Jdbc。</p> <p><br></p> <p>做系统重构前,我们首先要确定重构的目标,其次要对未来业务的发展有一个预期,这个可以找相关业务负责人了解。根据目标和业务预期来确定重构方案。例如,我们希望经过本次重构,系统能支撑两年,两年内不再大改。业务方预期两年内日单量达到1000万。相当于两年后日订单量要翻10倍。</p> <p><br></p> <p>根据上面的数据,我们分成了16个数据库。按日订单量1000万来算,每个库平均的日订单量就是62.5万(1000万/16),每秒最高订单量理论上在1250左右( 2000*(62.5/100) )。这样数据库的压力基本上是可控的,而且基本不会浪费服务器资源。</p> <p><br></p> <p>每个库分了16张表,即便按照每天1000万的订单量,两年总单量是73亿(73亿=1000万*365*2),每个库的数据量平均是4.56亿(4.56亿=73亿/16),每张表的数据量平均是2850万(2850万=4.56亿/16)。可以看到未来两到三年每张表的数据量也不算多,完全在可控范围。<br></p> <p><br></p> <p>分库分表主要是为了用户端下单和查询使用,按user_id的查询频率最高,其次是order_id。所以我们选择user_id做为sharding column,按user_id做hash,将相同用户的订单数据存储到同一个数据库的同一张表中。这样用户在网页或者App上查询订单时只需要路由到一张表就可以获取用户的所有订单了,这样就保证了查询性能。</p> <p><br></p> <p>另外我们在订单ID(order_id)里掺杂了用户ID(user_id)信息。简单来说,order_id的设计思路就是,将order_id分为前后两部分,前面的部分是user_id,后面的部分是具体的订单编号,两部分组合在一起就构成了order_id。这样我们很容易从order_id解析出user_id。通过order_id查询订单时,先从order_id中解析出user_id,然后就可以根据user_id路由到具体的库表了。<br></p> <p><br></p> <p>另外,数据库分成16个,每个库分16张表还有一个好处。16是2的N次幂,所以hash值对16取模的结果与hash值和16按位“与运算”的结果是一样的。我们知道位运算基于二进制,跨过各种编译和转化直接到最底层的机器语言,效率自然远高于取模运算。</p> <p><br></p> <p>有读者可能会问,查询直接查数据库,会不会有性能问题?是的。所以我们在上层加了Redis,Redis做了分片集群,用于存储活跃用户最近50条订单。这样一来,只有少部分在Redis查不到订单的用户请求才会到数据库查询订单,这样就减小了数据库查询压力,而且每个分库还有两个从库,查询操作只走从库,进一步分摊了每个分库的压力。</p> <p><br></p> <p>有读者可能会问,为什么没采用一致性hash方案?用户查询最近50条之前的订单怎么办?请继续往后看!</p> <p><br></p> <p><span style="color: rgb(255, 104, 39);"><strong>管理端技术方案</strong></span></p> <hr style="border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p><br></p> <p>分库分表后,不同用户的订单数据散落在不同的库和表中,如果需要根据用户ID之外的其他条件查询订单。例如,运营同学想从后台查出某天iphone7的订单量,就需要从所有数据库的表中查出数据然后在聚合到一起。这样代码实现非常复杂,而且查询性能也会很差。所以我们需要一种更好的方案来解决这个问题。<br></p> <p><br></p> <p>我们采用了ES(Elastic Search)+HBase组合的方案,将索引与数据存储隔离。可能参与条件检索的字段都会在ES中建一份索引,例如商家,商品名称,订单日期等。所有订单数据全量保存到HBase中。我们知道HBase支持海量存储,而且根据rowkey查询速度超快。而ES的多条件检索能力非常强大。可以说,这个方案把ES和HBase的优点发挥地淋漓尽致。</p> <p><br></p> <p>看一下该方案的查询过程:先根据输入条件去ES相应的索引上查询符合条件的rowkey值,然后用rowkey值去HBase查询,后面这一步查询速度极快,查询时间几乎可以忽略不计。如下图:&nbsp;</p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.789405684754522" data-s="300,640" src="/upload/becfa1d7afbce8f22c7025d3d8f7d8a2.png" data-type="png" data-w="774" style=""></p> <p><br></p> <p>该方案,解决了管理端通过各种字段条件查询订单的业务需求,同时也解决了商家端按商家ID和其他条件查询订单的需求。如果用户希望查询最近50条订单之前的历史订单,也同样可以用这个方案。</p> <p><br></p> <p>每天产生数百万的订单数据,如果管理后台想查到最新的订单数据,就需要频繁更新ES索引。在海量订单数据的场景下,索引频繁更新会不会对ES产生太大压力?</p> <p><br></p> <p>ES索引有一个segment(片段)的概念。ES把每个索引分成若干个较小的 segment 片段。每一个 segement 都是一个完整的倒排索引,在搜索查询时会依次扫描相关索引的所有 segment。每次 refresh(刷新索引) 的时候,都会生成一个新的 segement,因此 segment 实际上记录了索引的一组变化值。由于每次索引刷新只涉及个别segement片段,更新索引的成本就很低了。所以,即便默认的索引刷新(refresh)间隔只有1秒钟,ES也能从容应对。不过,由于每个 segement 的存储和扫描都需要占用一定的内存和CPU等资源,因此ES后台进程需要不断的进行segement合并来减少 segement 的数量,从而提升扫描效率以及降低资源消耗。</p> <p><br></p> <p>Mysql中的订单数据需要实时同步到Hbase和ES中。同步方案是什么?<br></p> <p><br></p> <p>我们利用Canal实时获取Mysql库表中的增量订单数据,然后把订单数据推到消息队列RocketMQ中,消费端获取消息后把数据写到Hbase,并在ES更新索引。<br></p> <p><br></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-ratio="0.42857142857142855" data-s="300,640" data-type="png" data-w="826" src="/upload/aba3abd25032dfda649c18bdf61dd14f.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 15px;">图片来源于网络</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">上面是Canal的原理图,</p> <p style="white-space: normal;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">1,Canal模拟mysql slave的交互协议,把自己伪装成mysql的从库</p> <p style="white-space: normal;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">2,向mysql master发送dump协议</p> <p style="white-space: normal;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">3. mysql master收到dump协议,发送binary log给slave(Canal)</p> <p style="white-space: normal;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">4. Canal解析binary log字节流对象,根据应用场景对binary log字节流做相应的处理</p> <p style="white-space: normal;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p>为了保证数据一致性,不丢失数据。我们使用了RocketMQ的事务型消息,保证消息一定能成功发送。另外,在Hbase和ES都操作成功后才做ack操作,保证消息正常消费。</p> <p><br></p> <p><strong style="color: rgb(255, 104, 39);">不停机数据迁移</strong></p> <hr style="border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p><br></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);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-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);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-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">数据迁移过程我们要注意哪些关键点呢?第一,保证迁移后数据准确不丢失,即每条记录准确而且不丢失记录;第二,不影响用户体验,尤其是访问量高的C端业务需要不停机平滑迁移;第三,保证迁移后的系统性能和稳定性。<span style="letter-spacing: 0.544px;"></span></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">常用的数据迁移方案主要包括:挂从库,双写以及利用数据同步工具三种方案。下面分别做一下介绍。</p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong><span style="color: rgb(0, 82, 255);">挂从库</span></strong><span style="color: rgb(0, 82, 255);"></span><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">在主库上建一个从库。从库数据同步完成后,将从库升级成主库(新库),再将流量切到新库。</p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">这种方式适合表结构不变,而且空闲时间段流量很低,允许停机迁移的场景。<span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">一般发生在平台迁移的场景</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">,如从机房迁移到云平台,从一个云平台迁移到另一个云平台。</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">大</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">部分中小型互联网</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">系统,空闲时段访问量很低。</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在空闲时段,几分钟的停机时间,对用户影响很小,业务方是可以接受的。</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">所以我们可以采用停机迁移的方案。</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">步骤如下:</span></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">1,新建从库(新数据库),数据开始从主库向从库同步。</p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">2,数据同步完成后,找一个空闲时间段。为了保证主从数据库数据一致,需要先停掉服务,然后再把从库升级为主库。如果访问数据库用的是域名,直接解析域名到新数据库(从库升级成的主库),如果访问数据库用的是IP,将IP改成新数据库IP。</p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">3,最后启动服务,整个迁移过程完成。</p> <p style="max-width: 100%;min-height: 1em;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;box-sizing: border-box !important;overflow-wrap: break-word !important;">这种迁移方案的优势是迁移成本低,迁移周期短。缺点是,切换数据库过程需要停止服务。<strong>我们的并发量比较高,而且又做了分库分表,表结构也变了,</strong><strong>所以不能采取这种方案!</strong><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;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;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong><span style="color: rgb(0, 82, 255);">双写</span></strong><span style="color: rgb(0, 82, 255);"></span></p> <p><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">老库和新库同时写入,然后将老数据批量迁移到新库,最后流量切换到新库并关闭老库读写。</p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">这种方式适合数据结构发生变化,不允许停机迁移的场景。一般发生在系统重构时,表结构发生变化,如表结构改变或者分库分表等场景。有些大型互联网系统,平常并发量很高,即便是空闲时段也有相当的访问量。几分钟的停机时间,对用户也会有明显的影响,甚至导致一定的用户流失,这对业务方来说是无法接受的。所以我们需要考虑一种用户无感知的不停机迁移方案。</p> <p style="max-width: 100%;min-height: 1em;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;box-sizing: border-box !important;overflow-wrap: break-word !important;">聊一下我们的具体迁移方案,<span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">步骤如下:</span></p> <ol class="list-paddingleft-2" style="max-width: 100%;width: 577.422px;white-space: normal;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">代码准备。</span><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">在服务层对订单<span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">表进行增删改</span>的地方,要同时操作新库(分库分表后的数据库表)和老库,需要修改相应的代码(同时写新库和老库)。</span><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">准备迁移程序脚本,用于做老数据迁移。</span><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">准备校验程序脚本,用于校验新库和老库的数据是否一致。</span></p></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">开启双写,老库和新库同时写入。</span><span style="max-width: 100%;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">注意:</span><span style="max-width: 100%;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">任何对数据库的增删改都要双写;</span><span style="max-width: 100%;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">对于更新操作,如果新库没有相关记录,需要先从老库查出记录,将更新后的记录写入新库;</span><span style="max-width: 100%;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了保证写入性能,老库写完后,可以采用消息队列异步写入新库。</span><span style="max-width: 100%;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">利用脚本程序</span>,将某一时间戳之前的老数据迁移到新库。注意:1,时间戳一定要选择开启双写后的时间点,比如开启双写后10分钟的时间点,避免部分老数据被漏掉;2,迁移过程遇到记录冲突直接忽略,因为第2步的更新操作,已经把记录拉到了新库;3,迁移过程一定要记录日志,尤其是错误日志,如果有双写失败的情况,我们可以通过日志恢复数据,以此来保证新老库的数据一致。</p></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">第3步完成后,我们还需要通过脚本程序检验数据,看新库数据是否准确以及有没有漏掉的数据</p></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">数据校验没问题后,开启双读,起初给新库放少部分流量,新库和老库同时读取。由于延时问题,新库和老库可能会有少量数据记录不一致的情况,所以新库读不到时需要再读一遍老库。然后再逐步将读流量切到新库,相当于灰度上线的过程。遇到问题可以及时把流量切回老库</p></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">读流量全部切到新库后,关闭老库写入(可以在代码里加上热配置开关),只写新库</p></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">迁移完成,后续可以去掉双写双读相关无用代码。</p><p style="max-width: 100%;min-height: 1em;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;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;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-ratio="0.77109375" data-s="300,640" data-type="jpeg" data-w="1280" src="/upload/efaadbf53de3bc64b72e047e1c420257.jpg" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p></li> </ol> <p style="max-width: 100%;min-height: 1em;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;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong><span style="color: rgb(0, 82, 255);">利用数据同步工具</span></strong></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;font-weight: 600;color: rgb(64, 64, 64);font-family: -apple-system, system-ui, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size: 16px;text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;</span>&nbsp;我们可以看到上面双写的方案比较麻烦,很多数据库写入的地方都需要修改代码。有没有更好的方案呢?</p> <p style="max-width: 100%;min-height: 1em;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;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;我们还<span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">可以利用</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Canal,</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Data</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Bus</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">等工具</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">做数据同步。</span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">以阿里开源的Canal为例。</span></p> <p style="max-width: 100%;min-height: 1em;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;box-sizing: border-box !important;overflow-wrap: break-word !important;">利用同步工具,就不需要开启双写了,<span style="max-width: 100%;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">服务层</span>也不需要编写双写的代码,直接用Canal做增量数据同步即可。相应的步骤就变成了:</p> <ol class="list-paddingleft-2" style="max-width: 100%;width: 577.422px;white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">代码准备。准备Canal代码,解析binary log字节流对象,并把解析好的订单数据写入新库。</span><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">准备迁移程序脚本,用于做老数据迁移。</span><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">准备校验程序脚本,用于校验新库和老库的数据是否一致。</span></p></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">运行Canal代码,开始<span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">增量</span>数据(线上产生的新数据)从老库到新库的同步。</p></li> <li style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">利用脚本程序</span>,将某一时间戳之前的老数据迁移到新库。注意:1,时间戳一定要选择开始<span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">运行</span><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">Canal程序</span>后的时间点(比如<span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">运行</span><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">Canal代码</span>后10分钟的时间点),避免部分老数据被漏掉;3,迁移过程一定要记录日志,尤其是错误日志,如果有些记录写入失败,我们可以通过日志恢复数据,以此来保证新老库的数据一致。</p></li> <li style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">第3步完成后,我们还需要通过脚本程序检验数据,看新库数据是否准确以及有没有漏掉的数据</p></li> <li style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">数据校验没问题后,开启双读,<span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">起初给新库放少部分流量,新库和老库同时读取。</span><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">由于延时问题,新库和老库可能会有少量数据记录不一致的情况,所以新库读不到时需要再读一遍老库。</span><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">逐步将读流量切到新库,相当于灰度上线的过程。</span><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">遇到问题可以及时把流量切回老库</span></p></li> <li style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">读流量全部切到新库后,将写入流量切到新库(可以在代码里加上热配置开关。注:由于切换过程<span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">Canal程序</span>还在运行,仍然能够获取老库的数据变化并同步到新库,所以切换过程不会导致部分老库数据无法同步新库的情况)</p></li> <li style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">关闭Canal程序<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p></li> <li style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">迁移完成。</p></li> </ol> <p style="white-space: normal;"><br></p> <p><span style="color: rgb(255, 104, 39);"><strong>扩容缩容方案</strong></span></p> <hr style="border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p style="white-space: normal;"><br></p> <p style="white-space: normal;">需要对数据重新hash取模,再将原来多个库表的数据写入扩容后的库表中。整体扩容方案和上面的不停机迁移方案基本一致。采用双写或者Canal等数据同步方案都可以。</p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;"><span style="color: rgb(255, 104, 39);"><strong>更好的分库分表方案</strong></span></p> <hr style="white-space: normal;border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p style="white-space: normal;max-width: 100%;min-height: 1em;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="white-space: normal;">通过前面的描述,不难看出我们的分库分表方案有一些缺陷,比如采用hash取模的方式会产生数据分布不均匀的情况,扩容缩容也非常麻烦。</p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;">这些问题可以用一致性hash方案解决。基于虚拟节点设计原理的一致性hash可以让数据分布更均匀。</p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;">而且一致性hash采用环形设计思路,在增减节点时,使得数据迁移的成本会更低,只需要迁移临近节点的数据。不过需要扩容时基本上要成倍扩容,在hash环上每个节点间隙都增加新的节点,这样才能分摊所有原有节点的访问和存储压力。</p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;">由于篇幅原因,这里不详细介绍一致性hash了,网上有很多相关资料,大家有兴趣可以仔细研究一下。</p> <p><br></p> <p><span style="color: rgb(255, 104, 39);"><strong>降级方案</strong></span></p> <hr style="border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);"> <p><span style="color: rgb(255, 104, 39);"></span></p> <p><br></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">在大促期间订单服务压力过大时,可以将同步调用改为异步消息队列方式,来减小订单服务压力并提高吞吐量。</p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);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-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">大促时某些时间点瞬间生成订单量很高。我们采取异步批量写数据库的方式,来减少数据库访问频次,进而降低数据库的写入压力。详细步骤:<span style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">后端服务接到下单请求,直接放进消息队列,订单服务取出消息后,先将订单信息写入Redis,每隔100ms或者积攒10条订单,批量写入数据库一次。前端页面下单后定时向后端拉取订单信息,获取到订单信息后跳转到支付页面。用这种异步<span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">批量</span>写入数据库的方式大幅减少了数据库写入频次,从而明显降低了订单数据库写入压力。不过,</span>因为订单是异步写入数据库的,就会存在数据库订单和相应库存数据暂时不一致的情况,以及用户下单后不能及时查到订单的情况。因为毕竟是降级方案,可以适当降低用户体验,我们保证数据最终一致即可。根据系统压力情况,可以在大促开始时开启异步批量写的降级开关,大促结束后再关闭降级开关。流程如下图:</p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.6050119331742243" data-s="300,640" src="/upload/bf04a3b6444d7a72c2fe71f3eb558abc.png" data-type="png" data-w="838" style=""></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="white-space: normal;"><br></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(0, 0, 0);"><strong><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">原创不易,如果感觉本文对您有帮助,有劳“转发分享”或“在看”!让更多人收获知识和经验!</span></strong></span><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);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-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;text-align: left;color: rgb(214, 168, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;">作者简介:</span><span style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;text-align: left;color: rgb(214, 168, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;">曾任职于阿里巴巴,每日优鲜等互联网公司,任技术总监,15年电商互联网经历</span><span style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;text-align: left;color: rgb(214, 168, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;">。</span></span></p> <pre data-darkmode-bgcolor-15923650965579="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15923650965579="rgb(255, 255, 255)" data-darkmode-color-15923650965579="rgb(167, 167, 167)" data-darkmode-original-color-15923650965579="rgb(63, 63, 63)" data-style="letter-spacing: 0.544px; font-size: 16px; color: rgb(63, 63, 63); word-spacing: 1px; line-height: inherit;" class="js_darkmode__91" style="letter-spacing: 0.544px;color: rgb(84, 84, 84);font-size: 16px;background-color: rgb(255, 255, 255);"><p 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;color: rgb(63, 63, 63);font-size: 15px;text-align: center;"><strong><img data-type="png" data-ratio="0.4875207986688852" data-w="601" data-backw="563" data-backh="274" src="/upload/dc8e3642ddbd4929ec2f7ede5eacac04.png" style="letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;box-sizing: border-box !important;visibility: visible !important;width: 661.016px !important;"></strong></p><p 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;text-align: right;"><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: 0.544px;text-align: center;"><strong><span style="font-size: 15px;color: rgb(0, 0, 0);letter-spacing: 0.544px;text-align: start;white-space: pre-line;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;">如果你觉得文章不错,文末的赞 👍 又回来啦,</span></strong><strong>记得给我「</strong><strong>点赞</strong><strong>」和「</strong><strong>在看</strong><strong>」哦~</strong></span></p></pre> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;text-align: left;color: rgb(214, 168, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></span><br></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: -apple-system-font, system-ui, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.544px;text-align: left;color: rgb(214, 168, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></p> <p><br></p>

这样设计订单系统,同事直呼 "666"!

作者:微信小助手

<p style="margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 15px;white-space: normal;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;background-color: rgb(255, 255, 255);line-height: normal;text-align: center;" data-mpa-powered-by="yiban.io"><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(136, 136, 136);">点击蓝色“</span><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(0, 128, 255);">架构文摘</span><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(136, 136, 136);">”关注我哟</span></p> <p style="margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 15px;white-space: normal;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;background-color: rgb(255, 255, 255);text-size-adjust: auto;word-spacing: 2px;text-align: center;"><span style="font-size: 14px;color: rgb(136, 136, 136);">加个“</span><span style="color: rgb(0, 128, 255);font-size: 14px;">星标</span><span style="font-size: 14px;color: rgb(136, 136, 136);">”,每天上午 09:25,干货推送!</span></p> <p style="color: rgb(62, 62, 62);white-space: normal;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;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 14px;text-align: center;"><img data-backh="36" data-backw="578" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.jpg" 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;widows: 1;word-spacing: 2px;color: rgb(136, 136, 136);box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="color: rgb(63, 63, 63);font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;background-color: rgb(255, 255, 255);"> <section style="text-align: right;"> <span style="color: rgb(136, 136, 136);"><em><span style="font-size: 12px;">来源:</span></em></span> <span style="color: rgb(136, 136, 136);"><em><span style="font-size: 12px;">人人都是产品经理</span></em></span> <span style="color: rgb(136, 136, 136);"><em><span style="color: rgb(136, 136, 136);font-size: 12px;">| http://dwz.win/Wkh</span></em></span> </section> </section> <section style="margin-top: 5px;padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"> 本文主要讲述了在传统电商企业中,订单系统应承载的角色,就订单系统所包含的主要功能模块梳理了设计思路,并对订单系统未来的发展做了一些思考。 <br> </section> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 15px;font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"><span style="margin-left: 8px;font-size: 17px;display: inline-block;color: rgb(72, 179, 120);">1. 订单系统在企业中的角色</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">在搭建企业订单系统之前,需要先梳理企业整体业务系统之间的关系和订单系统上下游关系,只有划分清业务系统边界,才能确定订单系统的职责与功能,进而保证各系统之间高效简洁的工作。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 15px;font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"><span style="margin-left: 8px;font-size: 17px;display: inline-block;color: rgb(72, 179, 120);">2. 订单系统与各业务系统的关系</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.6710144927536232" data-type="png" data-w="690" src="/upload/e8957f198795acc64de019271c1cec0a.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"><strong style="line-height: 1.75em;">(1)对外系统:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">所有给企业外部用户使用的系统都在这一层,包括官网、普通用户使用的C端,还包括给商户使用的商家后台和在各个销售渠道进行分销的系统,比如与银行信用卡中心合作、微信合作在合作商的平台露出本企业的产品。这类系统站在与客户接触的最前线,是公司实现商业模式的桥头堡。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">(2)管理中后台:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">每个C端的业务形态都会有一个对应的系统模块,如负责管理平台交易的订单系统,管理优惠信息的促销系统,管理平台所有产品的产品系统,以及管理所有对外系统显示内容的内容系统等。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">(3)公共服务系统:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">随着企业的发展,信息化建设到达一定程度后,企业需要将通用功能服务化、平台化,以保证应用架构的合理性,提升服务效率。这类系统主要给其他应用系统提供基础服务能力支持。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 15px;font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"><span style="margin-left: 8px;font-size: 17px;display: inline-block;color: rgb(72, 179, 120);">3. 订单系统上下游关系</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.33207190160832545" data-type="png" data-w="1057" src="/upload/b4092eaf9ca2112d14990f50474126dd.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;">由此可见,订单系统对上接收用户信息,将用户信息转化为产品订单,同时管理并跟踪订单信息和数据,承载了公司整个交易线的重要对客环节。对下则衔接产品系统、促销系统、仓储系统、会员系统、支付系统等,对整个电商平台起着承上启下的作用。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 15px;font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"><span style="margin-left: 8px;font-size: 17px;display: inline-block;color: rgb(72, 179, 120);">4. 订单系统的业务架构</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.2254335260115607" data-type="png" data-w="1038" src="/upload/360d5948a75c3f05c79b9fd5cd7e73cd.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"><strong style="line-height: 1.75em;">(1)订单服务</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">该模块的主要功能是用户日常使用的服务和页面,主要有订单列表、订单详情、在线下单等,还包括为公共业务模块提供的多维度订单数据服务。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">(2)订单逻辑</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">订单系统的核心,起着至关重要的作用,在订单系统负责管理订单创建、订单支付、订单生产、订单确认、订单完成、取消订单等订单流程。还涉及到复杂的订单状态规则、订单金额计算规则以及增减库存规则等。在4节核心功能设计中会重点来说。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">(3)底层服务</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">信息化建设达到一定程度的企业,一般会将公司公共服务模块化,比如:产品,会构建对应的产品系统,代码、数据库,接口等相对独立。但是,这也带来了一个问题,比如:订单创建的场景下需要获取的信息分散在各个系统。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">如果需要从各个公共服务系统调用:一是会花费大量时间,二是代码的维护成本非常高。因此,订单系统接入所需的公共服务模块接口,在订单系统即可完成对接公共系统的服务。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 10px;font-weight: bold;font-size: 22px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;white-space: normal;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/lgiaG5BicLkVcc5lpo9iaOjvvH61opxGuwY0wdO4EbbRGBqwkMdy7J73eZMrqOw8FLqLf3V2sgVpJ5kslo9wUk7ibA/640?wx_fmt=png&quot;) center center / 50px no-repeat rgb(255, 255, 255);color: black;text-align: center;"><span style="margin-top: 38px;margin-bottom: 10px;display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;font-size: 18px;">订单系统核心功能</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 15px;font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"><span style="margin-left: 8px;font-size: 17px;display: inline-block;color: rgb(72, 179, 120);">1. 订单中所包含的内容信息</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.689922480620155" data-type="png" data-w="774" src="/upload/15919f2d661dd6cf4f78ed592972c6b3.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;">为了使订单系统能够对订单进行高效、精准的管理和跟踪,订单会储存关于产品、优惠、用户、支付信息等一系列的订单实时数据,来和下游系统,如:促销、仓储、物流进行交互。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">以一个通用B2C商城的订单为例,梳理其包含的信息如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">这里要注意的是订单类型,随着平台业务的不断发展,品类丰富、交易方式丰富后,需要对订单进行多维度的分类管理,同时订单类型利于订单系统的扩展性。每种订单类型将会对应一套流程及一套状态,便于对订单进行分类管理和复用。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 15px;font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"><span style="margin-left: 8px;font-size: 17px;display: inline-block;color: rgb(72, 179, 120);">2. 流程引擎</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">流程是指从平台角度出发,将订单从创建到完成的整个流转过程进行抽象,从而形成了一套标准流程规则。而不同的产品类型或交易类型在系统中的流程会千差万别,因此为了方便对订单流程进行管理,会组建流程引擎模块。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">每套订单流程中会包含正向流程及逆向流程,正向流程可以比作一次顺利的网购体验过程中,后台系统之间的信息流转。逆向流程则是修改订单、取消订单、退款、退货等各种动作引起的后台系统流程,同时每个流程触发的条件又可分为系统触发和人工触发两种场景。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">(1)正向流程</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">以一个通用B2C商城的订单系统为例,根据其实际业务场景,其订单流程可抽象为5大步骤:<strong style="line-height: 1.75em;">订单创建&gt;订单支付&gt;订单生产&gt;订单确认&gt;订单完成。</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">而每个步骤的背后,订单是如何在多系统之间交互流转的,可概括如下图:</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.9544344995931652" data-type="jpeg" data-w="1229" src="/upload/c4f392ebc8cda7fa6c02b6fe138d9a73.jpg" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"><strong style="line-height: 1.75em;">订单创建:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">用户下单后,系统需要生成订单,此时需要先获取下单中涉及的商品信息,然后获取该商品所涉及到的优惠信息,如果商品不参与优惠信息,则无此环节。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">接着获取该账户的会员权益,这里要注意的是:优惠信息与会员权益的区别,比如:商品满减是优惠信息,SUPER会员全场9.8折指的是会员权益,一个是针对商品,另一个是针对账户。其次就是优惠活动的叠加规则和优先级规则等。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><span style="letter-spacing: 0.544px;">增减</span><span style="letter-spacing: 0.544px;">库存规则是指订单中的商品,何时从仓储系统中对相应商品库存进行扣除,目前主流有两种方式:</span></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">下单减库存——即用户下单成功时减少库存数量</strong></p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="line-height: 1.75em;color: rgb(74, 74, 74);">优势</strong>:用户体验友好,系统逻辑简洁; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="line-height: 1.75em;color: rgb(74, 74, 74);">缺点</strong>:会导致恶意下单或下单后却不买,使得真正有需求的用户无法购买,影响真实销量; </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">解决办法:</strong></p> <ol data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 设置订单有效时间,若订单创建成功N分钟不付款,则订单取消,库存回滚; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 限购,用各种条件来限制买家的购买件数,比如一个账号、一个ip,只能买一件; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 风控,从技术角度进行判断,屏蔽恶意账号,禁止恶意账号购买。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">付款减库存——即用户支付完成并反馈给平台后再减少库存数量</strong></p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="line-height: 1.75em;color: rgb(74, 74, 74);">优势</strong>:减少无效订单带来的资源损耗; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="line-height: 1.75em;color: rgb(74, 74, 74);">缺点</strong>:因第三方支付返回结果存在时差,同一时间多个用户同时付款成功,会导致下单数目超过库存,商家库存不足容易引发断货和投诉,成本增加。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">解决办法:</strong></p> <ol data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 付款前再次校验库存,如确认订单要付款时再验证一次,并友好提示用户库存不足; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 增加提示信息:在商品详情页,订单步骤页面提示不及时付款,不能保证有库存等。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">综上所述,两种方式各有优缺点,因此,需结合实际场景进行考虑,如:秒杀、抢购、促销活动等,可使用下单减库存的方式。而对于产品库存量大,并发流量没有那么强的产品使用付款减库存的方式。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">将两种方式带入到销售场景中,关联商品类型、促销类型、供需关系等,灵活使用,以充分发挥计算机系统的优势。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">关注公众号:后端面试那些事儿,每天学一点,一起进大厂!</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">订单支付:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">用户支付完订单后,需要获取订单的支付信息,包括支付流水号、支付时间等。支付完订单接着就是等商家发货,但在发货过程中,根据平台业务模式的不同,可能会涉及到订单的拆分。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">订单拆分一般分两种:</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 一种是用户挑选的商品来自于不同渠道(自营与商家,商家与商家); </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 另一种是在SKU层面上拆分订单:不同仓库,不同运输要求的SKU,包裹重量体积限制等因素需要将订单拆分。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">订单拆分也是一个相对独立的模块,这里就不详细描述了。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">订单生产</strong>:订单生产,是指产品从企业到用户这一流程的概述。如电商平台中,商家发货过程已有一个标准化的流程,订单内容会发送到仓库,仓库对商品进行打单、拣货、包装、交接快递进行配送。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">订单确认</strong>:收到货后,订单系统需要在快递被签收后提醒用户对商品做评价。这里要注意,确认收到货不代表交易成功,相反是售后服务的开始。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">订单完成</strong>:订单完成是指在收到货X天的状态,此时订单不在售后的支持时间范围内。到此,一个订单的正向流程就算走完了。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">(2)逆向流程</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.41816009557945044" data-type="png" data-w="837" src="/upload/55fce9050f2739459a177a2d82310a7a.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;">上面说到逆向流程是各种修改订单、取消订单、退款、退货等操作,需要梳理清楚这些流程与正向流程的关系,才能理清订单系统完整的订单流程。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">订单修改</strong>:可梳理订单内信息,根据信息关联程度及业务诉求,设定订单的可修改范围是什么,比如:客户下单后,想修改收货人地址及电话。此时只需对相应数据进行更新即可。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">订单取消</strong>:用户提交订单后没有进行支付操作,此时用户原则上属于取消订单,因为还未付款,则比较简单,只需要将原本提交订单时扣减的库存补回,促销优惠中使用的优惠券,权益等视平台规则,进行相应补回。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">退款</strong>:用户支付成功后,客户发出退款的诉求后,需商户进行退款审核,双方达成一致后,系统应以退款单的形式完成退款,关联原订单数据。因商品无变化,所以不需考虑与库存系统的交互,仅需考虑促销系统及支付系统交互即可。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">退货</strong>:用户支付成功后,客户发出退货的诉求后,需商户进行退款审核,双方达成一致后,需对库存系统进行补回,支付系统、促销系统以退款单形式完成退款。最后,在退款/退货流程中,需结合平台业务场景,考虑优惠分摊的逻辑,在发生退款/退货时,优惠该如何退回的处理规则和流程。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">(3)状态机</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">状态机是管理订单状态逻辑的工具。状态机可归纳为3个要素,即现态、动作、次态。</p> <ol data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: black;"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="line-height: 1.75em;color: rgb(74, 74, 74);">现态</strong>:是指当前所处的状态。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="line-height: 1.75em;color: rgb(74, 74, 74);">动作</strong>:动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="line-height: 1.75em;color: rgb(74, 74, 74);">次态</strong>:动作满足后要迁往的新状态,“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">状态机的设计需要结合平台实际业务场景,将状态间的切换细化成了执行了某个动作。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">以一个B2C商城的订单系统举例如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.5304054054054054" data-type="png" data-w="888" src="/upload/e4f15e0c3999df584e5d545bb5607142.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;">订单系统为了高效的对订单进行跟踪和管理,会对订单流程当中的关键节点,抽象出订单状态。而订单状态从不同用户的角度可分为,系统订单状态、商家订单状态、买家订单状态等。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">对于订单系统来说,订单状态细分的颗粒度越细、越明确,订单系统管理的精度和可靠性就越高,比如:在待付款和待发货两个状态中,订单系统后台会细分为订单超时取消、订单支付失败、订单付款完成等。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">因此,订单状态模块中,通常会维护状态映射表,以不同的用户角色对系统订单状态进行重新划分,以满足不同用户的需求。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">除此以外,随着电商平台的不断发展,不同的业务类型,所对应的订单状态都会有所区别。所以,订单系统中一般会储存多套状态机,以满足不同的订单类型来使用。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><span style="color: rgb(74, 74, 74);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;background-color: rgb(255, 255, 255);"></span></p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 10px;font-weight: bold;font-size: 22px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;white-space: normal;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/lgiaG5BicLkVcc5lpo9iaOjvvH61opxGuwY0wdO4EbbRGBqwkMdy7J73eZMrqOw8FLqLf3V2sgVpJ5kslo9wUk7ibA/640?wx_fmt=png&quot;) center center / 50px no-repeat rgb(255, 255, 255);color: black;text-align: center;"><span style="margin-top: 38px;margin-bottom: 10px;display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;font-size: 18px;">订单系统的发展</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">订单系统的主体框架,和主要业务模块已基本讲完,那么随着企业的发展,业务量和业务形式不断变化,企业有可能形成多个订单系统并存以满足不同的业务需要的情况。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">业务系统架构如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><img data-ratio="0.5919395465994962" data-type="png" data-w="794" src="/upload/54f0e6bac2b4d46dba3920d79788279f.png" style="margin-right: auto;margin-bottom: 25px;margin-left: auto;display: block;border-radius: 4px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;">这种状况的出现,将会给平台带来非常大的发展瓶颈,如:</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">三个订单系统,每个订单系统处理不同类型的订单,没有统一的订单销量、订单状态信息,网站前台对订单的状态展示与控制不统一,只能是在网站前台会员中心硬代码维护一套面向会员的统一订单明细与状态数据。而无线侧上线后,由于不了解前台网站会员中心的订单状态管理逻辑,所以需要把前台网站的订单明细及状态管理再在无线应用侧再实现一遍。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">三套后台订单系统与公共业务系统如会员中心、支付与财务、促销工具、客户分单等系统都需要对接一遍,公共业务处理逻辑不统一,一旦逻辑变更,多个系的同一个接口都要修改一遍,接口的重复维护开发工作量大。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">订单开发目前分到事业部,各个事业部只会考虑自己的逻辑,不会考虑公共架构,只会越走越远。碰到像无线这样的项目,需要对接各个事业部,无线侧应用上线进展慢。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">因此未来的订单系统可拆分为订单中心与业务订单系统两个模块,以管理公司所有订单数据,并为各个模块提供统一服务。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 1em;margin-bottom: 10px;font-weight: bold;font-size: 22px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;letter-spacing: 0.544px;white-space: normal;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/lgiaG5BicLkVcc5lpo9iaOjvvH61opxGuwY0wdO4EbbRGBqwkMdy7J73eZMrqOw8FLqLf3V2sgVpJ5kslo9wUk7ibA/640?wx_fmt=png&quot;) center center / 50px no-repeat rgb(255, 255, 255);color: black;text-align: center;"><span style="margin-top: 38px;margin-bottom: 10px;display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;font-size: 18px;">最后</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">对于企业订单系统的搭建,并不是要做的大而全、也不是要小而精。而需要结合市场、公司、业务的实际情况来最终制定系统设计方案和产品迭代计划。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;">最终,和公司整体发展相互协调,相辅相成。</p> <p data-tool="mdnice编辑器" style="padding-top: 1em;padding-bottom: 8px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;font-size: 16px;letter-spacing: 0.544px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);line-height: 1.75em;"><br></p> <section data-mpa-template="t" mpa-from-tpl="t" style="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;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;text-align: start;widows: 1;caret-color: rgb(0, 0, 0);color: rgb(120, 114, 114);word-spacing: 2px;"> <section data-id="89429" mpa-from-tpl="t" style="border-width: 0px;border-style: none;border-color: initial;"> <section mpa-from-tpl="t" style="text-align: center;height: 50px;"> <section mpa-from-tpl="t" style="margin-right: auto;margin-left: auto;width: 48px;height: 48px;color: rgb(255, 255, 255);line-height: 48px;display: inline-block;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_gif/kiaqiahsnxHd4Zt4378tqib1DnnfKYvZAI7sUNZCYmGN2HCMDFDYV5hLu6HrHIK5BynAAwgHGiafFFU7ibYez6mXL4w/640?wx_fmt=gif&quot;);background-repeat: no-repeat;background-size: 100%;background-position: 0px center;"> <p style="font-weight: bold;"><span style="font-size: 14px;">end</span></p> </section> <section mpa-from-tpl="t" style="margin-top: -26px;height: 2px;background-color: rgb(34, 33, 33);"> <br> </section> </section> </section> </section> <p style="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;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);font-size: 16px;text-align: start;widows: 1;word-spacing: 1px;caret-color: rgb(255, 0, 0);"><br></p> <section mpa-from-tpl="t" style="padding-left: 5px;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: medium;text-align: start;widows: 1;caret-color: rgb(0, 0, 0);word-spacing: 2px;border-left: 5px solid rgb(51, 51, 51);line-height: 1.5em;"> <section powered-by="xiumi.us" mpa-from-tpl="t"> <section mpa-from-tpl="t"> <section mpa-from-tpl="t" style="font-size: 18px;"> <p><span style="font-size: 16px;">推荐阅读:</span></p> </section> </section> </section> </section> <ul class="list-paddingleft-2" mpa-from-tpl="t" style="letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: medium;text-align: start;widows: 1;caret-color: rgb(0, 0, 0);word-spacing: 2px;"> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247493717&amp;idx=1&amp;sn=e3ba0c0fb0afb3963f94fb10ff348cb9&amp;chksm=9f44849da8330d8b8c4b88dff59af148800de008e5a5b814f5f90bfec198fec56e8e53f96357&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">万字好文,电商秒杀系统架构分析与实战!</a><br></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247493401&amp;idx=2&amp;sn=08dcf94d57a9ec9e69bb2fbfd4c57a3d&amp;chksm=9f448bd1a83302c7710b3a0d331bf0e70e7ac96e1941933e7027677406c257fb72d7c5fabab5&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">拜托,不要再问我线程池啦!</a><br></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247493867&amp;idx=1&amp;sn=cc70b9a3c15c517090afb4efc4db12ec&amp;chksm=9f448423a8330d3524c2b42f5ccf6bbf586f1a9bba757f7dd6b4906e0d974e77a50483335625&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">ElasticSearch 在数十亿级别数据下,如何提高查询效率?</a><br></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247493562&amp;idx=1&amp;sn=69cc7740c30877d298281dacf7c74572&amp;chksm=9f448b72a8330264c3932d5735fa39cb8548b7502a63a403617f174f518a69d7a9130381390f&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">Spring Cloud架构的各个组件的原理分析</a><br></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&amp;mid=2247493607&amp;idx=1&amp;sn=71a3bea53bcca4ba1051447abe1cac13&amp;chksm=9f448b2fa8330239dce3dc00fa256d41db52d816ba65c630d00ec12d9ebf279c2a10ff55630b&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">一口气说出 5 种 IO 模型,蒙圈了!</a><br></p></li> </ul> <p style="margin-top: 5px;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 15px;background-color: rgb(255, 255, 255);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: start;widows: 1;caret-color: rgb(0, 0, 0);word-spacing: 2px;"><br></p> <p style="margin-top: 5px;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 15px;background-color: rgb(255, 255, 255);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;widows: 1;caret-color: rgb(0, 0, 0);word-spacing: 2px;text-align: right;"><img class="rich_pages" data-ratio="0.5555555555555556" data-s="300,640" data-type="jpeg" data-w="900" src="/upload/9d786e52e671b1ce4beb338d1e0d1815.jpg" style="letter-spacing: 0.544px;text-align: center;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"><span style="letter-spacing: 0.544px;font-size: 14px;">如有收获,点个在看,诚挚感谢</span><img data-ratio="1" data-type="png" data-w="19" width="19px" src="/upload/5f7454d24a334e968c32b8ce9ae53c5.png" style="font-size: 16px;letter-spacing: 0.544px;display: inline-block;vertical-align: text-bottom;box-sizing: border-box !important;visibility: visible !important;width: 19px !important;"></p>

接口测试如何在post请求中传递文件

作者:测试人生路

## 在做接口测试的时候往往会遇到文件上传的接口,今天教大家如何使用apipost进行文档上传操作。 **1.打开apipost,新建一个关于文件上传的接口** ![1.png](/storage/thumbnails/_signature/39B73LI9E9G27FHSAC3UFOI8FG.png) **2.找到body这个选项,输入文件对应的参数名,在然后把参数名后面的text选择为file。** ![2.png](/storage/thumbnails/_signature/K99V0R6RAFI3NK8NLJ96RVIG6.png) **3.修改完成之后,后面参数值的框已经显示为请选择文件上传,点击,选择需要上传的文件** ![3.png](/storage/thumbnails/_signature/27TLIIU50TPN5V46PG147IIIJ2.png) ![4.png](/storage/thumbnails/_signature/P21OOSFF4M6MP71U7IQ8UNUIT.png) **4.选择完成之后点击保存接口点击请求发送。** ![5.png](/storage/thumbnails/_signature/295NQ66MHG5P18PNMAEK7SSTKC.png) 这就是apipost如何实现文件上传的操作了。 工具下载地址:[https://www.apipost.cn](https://www.apipost.cn/?dt=20201109)

ElasticSearch 在数十亿级别数据下,如何提高查询效率?

作者:微信小助手

<p style="margin-bottom: 10px;max-width: 100%;min-height: 1em;color: rgb(62, 62, 62);font-size: 15px;white-space: normal;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;background-color: rgb(255, 255, 255);line-height: normal;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;" data-mpa-powered-by="yiban.io"><em style="color: rgb(136, 136, 136);font-size: 12px;text-align: left;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">来源:https://zhuanlan.zhihu.com/p/60458049</em></p> <section style="font-size: 15px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">面试题</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">面试官心理分析</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">这个问题是肯定要问的,说白了,就是看你有没有实际干过 es,因为啥?其实 es 性能并没有你想象中那么好的。很多时候数据量大了,特别是有几亿条数据的时候,可能你会懵逼的发现,跑个搜索怎么一下 <code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">5~10s</code>,坑爹了。第一次搜索的时候,是5~10s,后面反而就快了,可能就几百毫秒。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">你就很懵,每个用户第一次访问都会比较慢,比较卡么?所以你要是没玩儿过 es,或者就是自己玩玩儿 demo,被问到这个问题容易懵逼,显示出你对 es 确实玩儿的不怎么样?</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">面试题剖析</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">说实话,es 性能优化是没有什么银弹的,啥意思呢?就是<strong style="font-size: inherit;color: inherit;line-height: inherit;">不要期待着随手调一个参数,就可以万能的应对所有的性能慢的场景</strong>。也许有的场景是你换个参数,或者调整一下语法,就可以搞定,但是绝对不是所有场景都可以这样。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">性能优化的杀手锏——filesystem cache</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">你往 es 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code>里面去。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.9902912621359223" src="/upload/e1a49156830471c03678a2a59a2f2af1.png" data-type="png" data-w="515" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">es 的搜索引擎严重依赖于底层的<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code>,你如果给 <code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code> 更多的内存,尽量让内存可以容纳所有的<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">idx segment file</code> 索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">性能差距究竟可以有多大?我们之前很多的测试和压测,如果走磁盘一般肯定上秒,搜索性能绝对是秒级别的,1秒、5秒、10秒。但如果是走 filesystem cache,是走纯内存的,那么一般来说性能比走磁盘要高一个数量级,基本上就是毫秒级的,从几毫秒到几百毫秒不等。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">这里有个真实的案例。某个公司 es 节点有 3 台机器,每台机器看起来内存很多,64G,总内存就是<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">64 * 3 = 192G</code>。每台机器给<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">es jvm heap</code> 是 32G,那么剩下来留给 <code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code> 的就是每台机器才 32G,总共集群里给<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code> 的就是<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">32 * 3 = 96G</code>内存。而此时,整个磁盘上索引数据文件,在 3 台机器上一共占用了 1T 的磁盘容量,es 数据量是 1T,那么每台机器的数据量是 300G。这样性能好吗?<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code>的内存才 100G,十分之一的数据可以放内存,其他的都在磁盘,然后你执行搜索操作,大部分操作都是走磁盘,性能肯定差。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">归根结底,你要让 es 性能要好,最佳的情况下,就是你的机器的内存,至少可以容纳你的总数据量的一半。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">根据我们自己的生产环境实践经验,最佳的情况下,是仅仅在 es 中就存少量的数据,就是你要用来搜索的那些索引,如果内存留给 filesystem cache 的是 100G,那么你就将索引数据控制在 100G 以内,这样的话,你的数据几乎全部走内存来搜索,性能非常之高,一般可以在 1 秒以内。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">比如说你现在有一行数据。id,name,age …. 30 个字段。但是你现在搜索,只需要根据 id,name,age 三个字段来搜索。如果你傻乎乎往 es 里写入一行数据所有的字段,就会导致说 90% 的数据是不用来搜索的,结果硬是占据了 es 机器上的 filesystem cache 的空间,单条数据的数据量越大,就会导致 filesystem cahce 能缓存的数据就越少。其实,仅仅写入 es 中要用来检索的少数几个字段就可以了,比如说就写入 es id,name,age 三个字段,然后你可以把其他的字段数据存在 mysql/hbase 里,我们一般是建议用 es + hbase 这么一个架构。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">hbase 的特点是适用于<strong style="font-size: inherit;color: inherit;line-height: inherit;">海量数据的在线存储</strong>,就是对 hbase 可以写入海量数据,但是不要做复杂的搜索,做很简单的一些根据 id 或者范围进行查询的这么一个操作就可以了。从 es 中根据 name 和 age 去搜索,拿到的结果可能就 20 个 doc id,然后根据 doc id 到 hbase 里去查询每个 doc id 对应的完整的数据,给查出来,再返回给前端。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><strong style="font-size: inherit;color: inherit;line-height: inherit;">写入 es 的数据最好小于等于,或者是略微大于 es 的 filesystem cache 的内存容量</strong>。然后你从 es 检索可能就花费 20ms,然后再根据 es 返回的 id 去 hbase 里查询,查 20 条数据,可能也就耗费个 30ms,可能你原来那么玩儿,1T 数据都放 es,会每次查询都是 5~10s,现在可能性能就会很高,每次查询就是 50ms。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">数据预热</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">假如说,哪怕是你就按照上述的方案去做了,es 集群中每个机器写入的数据量还是超过了<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code> 一倍,比如说你写入一台机器 60G 数据,结果<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code> 就 30G,还是有 30G 数据留在了磁盘上。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">其实可以做<strong style="font-size: inherit;color: inherit;line-height: inherit;">数据预热</strong>。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">举个例子,拿微博来说,你可以把一些大V,平时看的人很多的数据,你自己提前后台搞个系统,每隔一会儿,自己的后台系统去搜索一下热数据,刷到<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">filesystem cache</code> 里去,后面用户实际上来看这个热数据的时候,他们就是直接从内存里搜索了,很快。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">或者是电商,你可以将平时查看最多的一些商品,比如说 iphone 8,热数据提前后台搞个程序,每隔 1 分钟自己主动访问一次,刷到 filesystem cache 里去。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">对于那些你觉得比较热的、经常会有人访问的数据,最好做一个专门的缓存预热子系统,就是对热数据每隔一段时间,就提前访问一下,让数据进入 filesystem cache 里面去。这样下次别人访问的时候,性能一定会好很多。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">冷热分离</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">es 可以做类似于 mysql 的水平拆分,就是说将大量的访问很少、频率很低的数据,单独写一个索引,然后将访问很频繁的热数据单独写一个索引。最好是将冷数据写入一个索引中,然后热数据写入另外一个索引中,这样可以确保热数据在被预热之后,尽量都让他们留<br>在 filesystem os cache 里,别让冷数据给冲刷掉。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">你看,假设你有 6 台机器,2 个索引,一个放冷数据,一个放热数据,每个索引 3 个 shard。3 台机器放热数据 index,另外 3 台机器放冷数据 index。然后这样的话,你大量的时间是在访问热数据 index,热数据可能就占总数据量的 10%,此时数据量很少,几乎全都保留在 filesystem cache 里面了,就可以确保热数据的访问性能是很高的。但是对于冷数据而言,是在别的 index 里的,跟热数据 index 不在相同的机器上,大家互相之间都没什么联系了。如果有人访问冷数据,可能大量数据是在磁盘上的,此时性能差点,就 10% 的人去访问冷数据,90% 的人在访问热数据,也无所谓了。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">Document 模型设计</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">对于 MySQL,我们经常有一些复杂的关联查询。在 es 里该怎么玩儿,es 里面的复杂的关联查询尽量别用,一旦用了性能一般都不太好。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">最好是先在 Java 系统里就完成关联,将关联好的数据直接写入 es 中。搜索的时候,就不需要利用 es 的搜索语法来完成 join 之类的关联搜索了。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">document 模型设计是非常重要的,很多操作,不要在搜索的时候才想去执行各种复杂的乱七八糟的操作。es 能支持的操作就那么多,不要考虑用 es 做一些它不好操作的事情。如果真的有那种操作,尽量在 document 模型设计的时候,写入的时候就完成。另外对于一些太复杂的操作,比如<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">join/nested/parent-child</code> 搜索都要尽量避免,性能都很差的。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">分页性能优化</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">es 的分页是较坑的,为啥呢?举个例子吧,假如你每页是 10 条数据,你现在要查询第 100 页,实际上是会把每个 shard 上存储的前 1000 条数据都查到一个协调节点上,如果你有个 5 个 shard,那么就有 5000 条数据,接着协调节点对这 5000 条数据进行一些合并、处理,再获取到最终第 100 页的 10 条数据。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">分布式的,你要查第 100 页的 10 条数据,不可能说从 5 个 shard,每个 shard 就查 2 条数据,最后到协调节点合并成 10 条数据吧?你必须得从每个 shard 都查 1000 条数据过来,然后根据你的需求进行排序、筛选等等操作,最后再次分页,拿到里面第 100 页的数据。你翻页的时候,翻的越深,每个 shard 返回的数据就越多,而且协调节点处理的时间越长,非常坑爹。所以用 es 做分页的时候,你会发现越翻到后面,就越是慢。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我们之前也是遇到过这个问题,用 es 作分页,前几页就几十毫秒,翻到 10 页或者几十页的时候,基本上就要 5~10 秒才能查出来一页数据了。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><strong style="font-size: inherit;color: inherit;line-height: inherit;">有什么解决方案吗?</strong></p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">不允许深度分页(默认深度分页性能很差)</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">跟产品经理说,你系统不允许翻那么深的页,默认翻的越深,性能就越差。</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">类似于 app 里的推荐商品不断下拉出来一页一页的</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">类似于微博中,下拉刷微博,刷出来一页一页的,你可以用<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">scroll api</code>,关于如何使用,自行上网搜索。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><strong style="font-size: inherit;color: inherit;line-height: inherit;">scroll 会一次性给你生成所有数据的一个快照</strong>,然后每次滑动向后翻页就是通过游标 scroll_id 移动,获取下一页下一页这样子,性能会比上面说的那种分页性能要高很多很多,基本上都是毫秒级的。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">但是,唯一的一点就是,这个适合于那种类似微博下拉翻页的,<strong style="font-size: inherit;color: inherit;line-height: inherit;">不能随意跳到任何一页的场景</strong>。也就是说,你不能先进入第 10 页,然后去第 120 页,然后又回到第 58 页,不能随意乱跳页。所以现在很多产品,都是不允许你随意翻页的,app,也有一些网站,做的就是你只能往下拉,一页一页的翻。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">初始化时必须指定 <code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">scroll</code>参数,告诉 es 要保存此次搜索的上下文多长时间。你需要确保用户不会持续不断翻页翻几个小时,否则可能因为超时而失败。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">除了用<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">scroll api</code>,你也可以用<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">search_after</code> 来做,<code style="font-size: inherit;line-height: inherit;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">search_after</code> 的思想是使用前一页的结果来帮助检索下一页的数据,显然,这种方式也不允许你随意翻页,你只能一页页往后翻。初始化时,需要使用一个唯一值的字段作为 sort 字段。</p> <pre ng-bind-html="message.MMActualContent" style="text-align: left;letter-spacing: 0.544px;color: rgb(62, 62, 62);font-size: 15px;background-color: rgb(255, 255, 255);widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);white-space: pre-wrap;word-break: normal;"><p style="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;letter-spacing: 0.544px;white-space: normal;"><span style="font-size: 14px;color: rgb(255, 76, 0);">特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:</span></p><p style="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;letter-spacing: 0.544px;white-space: normal;text-align: center;"><img class="rich_pages" data-ratio="0.5555555555555556" data-s="300,640" data-type="jpeg" data-w="900" src="/upload/c86a3619353fb9ac25fa19df4ec53cb1.jpg" style="box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p><p style="text-align: center;"><img class="rich_pages" data-ratio="0.5555555555555556" data-s="300,640" data-type="png" data-w="900" src="/upload/c8a5249d1ca6482fd512bd028bfaa944.png" style="box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p></pre> <p style="white-space: normal;font-size: 16px;letter-spacing: 0.544px;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;background-color: rgb(255, 255, 255);color: rgba(0, 0, 0, 0.8);text-align: center;widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);"><img class="rich_pages" data-ratio="0.5555555555555556" data-s="300,640" data-type="png" data-w="900" src="/upload/6ceab10a2b199fa5589c60da151b3e93.png" style="box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p> <pre ng-bind-html="message.MMActualContent" style="font-size: 16px;text-align: left;letter-spacing: 0.544px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);white-space: pre-wrap;word-break: normal;"><p style="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;letter-spacing: 0.544px;white-space: normal;text-align: center;">长按订阅更多精彩▼</p><p style="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;letter-spacing: 0.544px;white-space: normal;text-align: center;"><img class="rich_pages" data-ratio="1" data-s="300,640" data-type="jpeg" data-w="258" width="205px" src="/upload/cff6d4b6b063076da067005708088611.jpg" style="box-shadow: rgb(170, 170, 170) 0px 0px 14px 0px;display: inline;box-sizing: border-box !important;visibility: visible !important;width: 205px !important;"></p><p style="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;letter-spacing: 0.544px;white-space: normal;text-align: right;line-height: 2em;"><span style="font-size: 14px;">如有收获,点个在看,诚挚感谢</span><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;letter-spacing: 0px;text-align: justify;"></span></p></pre> </section>

接口测试的时候如何生成随机数据进行测试

作者:测试人生路

在进行接口测试的时候会需要生成一些随机数据进行测试,今天教大家使用apipost自带的mock字段变量生成随机数据进行测试。 打开apipost ![1.png](/storage/thumbnails/_signature/3UVLU1FT2ASLN0MMI297TQQ799.png) 左下角有一个红色字体的内置mock字段变量,今天我们生成随机数据就是使用这个内置mock字段变量。 ![2.png](/storage/thumbnails/_signature/3E0BUFACLP7BLDQCBF2JD3TM3.png) 选择需要生成的数据数据类型,然后进行引用就可以了 ![3.png](/storage/thumbnails/_signature/BPEU8I3ONBS85OC4OLMI7U2KI.png) 直接复制这些变量的名称然后粘贴到参数值当中。 ![4.png](/storage/thumbnails/_signature/6LJICSVK4KUIFO5T5SC63AGEO.png) 点击发送查看数据结果,可以看到每次test传递的数据都是不一样的。 ![5.png](/storage/thumbnails/_signature/1VED5HD1PFMHCPR5OPPAVQE7IS.png) ![6.png](/storage/thumbnails/_signature/1RESNS7L4ROAN1IST0S3FHOK8I.png) 这就是关于如何使用apipost随机生成测数据的操作了。 工具下载地址:https://www.apipost.cn/?dt=20201110

接口文档生成详细教程

作者:测试人生路

接口文档是一个项目开发中必需的说明文档,但时接口文档编写起来比较费事费力。本文为大家推荐一款特别好用的接口文档生成工具--apipost apipost是一款国产的接口测试和接口文档生成的工具。其中它接口文档生成的功能特别强大。 打开apipost编写一个登录的接口请求 ![1.png](/storage/thumbnails/_signature/2ID0I6P4K2R5J8BET3JNQIR2UV.png) 它这里有两个功能,成功响应示例及文档和错误响应示例及文档 ![2.png](/storage/thumbnails/_signature/17ILOJ12N2CE6MRN5BC68QSDB7.png) 成功响应示例文档,我们点击从现有响应结果导入和导出字段,获得如图效果 ![3.png](/storage/thumbnails/_signature/F95O22IHKMKNMREQHHSPLCU48.png) 分享文档查看 ![4.png](/storage/thumbnails/_signature/1FK58QD6ODT8PK3KK2953D51DJ.png) 还可以添加错误响应示例文档 ![5.png](/storage/thumbnails/_signature/FMBBHMQM6L88267LN23KQCDR1.png) 分享查看,成功和失败的响应示例都会出现 ![6.png](/storage/thumbnails/_signature/QTJ1K7P2BPBLIUCJD6TR6T1E.png) 它还支持html、markdown和word格式的接口文档 ![7.png](/storage/thumbnails/_signature/2E0JKA10A1G36RRKOU7EC9UE1E.png) 看一下word格式的接口文档效果(word只生成成功响应示例文档) ![8.png](/storage/thumbnails/_signature/R77AAUNJ2N7C1L6NP0P7IJE3V.png) 这就是apipost生成接口文档的具体流程了 工具下载地址:[https://www.apipost.cn](https://www.apipost.cn/?dt=20201111)

Redis删除数据后,为什么内存占用率还是很高?

作者:微信小助手

<p data-lake-id="a20d224c568e48b9d67847a2c66a8c01_p_0" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" data-mpa-powered-by="yiban.io"><span style="letter-spacing: 0.5px;"></span><span style="letter-spacing: 0.5px;">在使用 Redis 时,我们经常会遇到这样一个问题:</span><span style="letter-spacing: 0.5px;">明明做了数据删除,数据量已经不大了,为什么使用 top 命令查看时,还会发现 Redis 占用了很多内存呢?</span></p> <p data-lake-id="02a6d14eb1fafc76958808a2bcc397d2" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><br></p> <p data-lake-id="0cf9c00e067e725f8859247dea240d77" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">实际上,这是因为,当数据删除后,Redis 释放的内存空间会由内存分配器管理,并不会立即返回给操作系统。所以,操作系统仍然会记录着给 Redis 分配了大量内存。</span></p> <p data-lake-id="5dd00165bdf4360727310085cf9b3efb" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><br></p> <p data-lake-id="ac97844fa084b7176765a4adce5a0a3a" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">但是,这往往会伴随一个潜在的风险点:Redis 释放的内存空间可能并不是连续的,那么,这些不连续的内存空间很有可能处于一种闲置的状态。这就会导致一个问题:虽然有空闲空间,Redis 却无法用来保存数据,不仅会减少 Redis 能够实际保存的数据量,还会降低 Redis 运行机器的成本回报率。</span><span style="letter-spacing: 0.5px;"></span></p> <p style="margin-top: 15px;white-space: normal;text-size-adjust: auto;background-color: rgb(255, 255, 255);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: center;background-size: 112px;background-position: center 20px;background-repeat: no-repeat;"><span style="margin-bottom: 10px;color: rgb(234, 84, 41);outline-style: none;line-height: 48px;border-bottom: 2px solid rgb(234, 84, 41);display: inline-block;letter-spacing: 0.5px;">Redis 内存碎片是如何形成的?</span></p> <section style="margin-top: 10px;"> <span style="color: rgb(64, 64, 64);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: 15px;letter-spacing: 0.5px;text-align: left;background-color: rgb(255, 255, 255);">Redis内存碎片的形成可以由两方面引起</span> </section> <ul class="list-paddingleft-2" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">内因是操作系统的内存分配机制</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">外因是 Redis 的负载特征</span></p></li> </ul> <p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><br></p> <h2 data-lake-id="b9194f0af8a34e9db8058d570a75d8b0" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;margin-bottom: 10px;"><span style="letter-spacing: 0.5px;font-size: 18px;"><strong>内因:内存分配器的分配策略</strong></span></h2> <p data-lake-id="2603a14cef6db86e8c321bdeb5522249" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">内存分配器的分配策略就决定了操作系统无法做到“按需分配”。</span><span style="letter-spacing: 0.5px;">这是因为,内存分配器一般是按固定大小来分配内存,而不是完全按照应用程序申请的内存空间大小给程序分配。</span></p> <p data-lake-id="2603a14cef6db86e8c321bdeb5522249" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;"><br></span></p> <p data-lake-id="34a33d679846fcf88832f07b5dcc6a0c" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><strong><span style="letter-spacing: 0.5px;">Redis 可以使用 libc、</span><span style="letter-spacing: 0.5px;">jemalloc</span><span style="letter-spacing: 0.5px;">、tcmalloc 多种内存分配器来分配内存,默认使用 jemalloc。</span></strong><span style="letter-spacing: 0.5px;"></span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p data-lake-id="4aa13762155302e2fb26899ec6d4b681" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">jemalloc 的分配策略之一,是按照一系列固定的大小划分内存空间,例如 8 字节、16 字节、32 字节、48 字节,…, 2KB、4KB、8KB 等。</span><span style="letter-spacing: 0.5px;">当程序申请的内存最接近某个固定值时,jemalloc 会给它分配相应大小</span><span style="letter-spacing: 0.5px;">的空间。</span><br></p></li> </ul> <p data-lake-id="4aa13762155302e2fb26899ec6d4b681" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;"><br></span></p> <p data-lake-id="fe5ce110c12a6a79de118f277db6a07e" style="font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;"><span style="letter-spacing: 0.5px;background-color: rgb(255, 255, 255);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;text-align: left;">如果 </span><strong><span style="letter-spacing: 0.5px;background-color: rgb(255, 255, 255);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;text-align: left;">Redis 每次向分配器申请的内存空间大小不一样</span></strong><span style="letter-spacing: 0.5px;background-color: rgb(255, 255, 255);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;text-align: left;">,这种分配方式就会有形成碎片的风险,而这正好来源于 Redis 的外因了。</span><br></p> <p data-lake-id="fe5ce110c12a6a79de118f277db6a07e" style="font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;"><span style="letter-spacing: 0.5px;background-color: rgb(255, 255, 255);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;text-align: left;"><br></span></p> <h2 data-lake-id="b9194f0af8a34e9db8058d570a75d8b0" data-wording="true" style="margin-bottom: 10px;font-size: 15px;white-space: normal;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;background-color: rgb(255, 255, 255);color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;font-size: 18px;"><strong>内因:内存分配器的分配策略</strong></span></h2> <p data-lake-id="2603a14cef6db86e8c321bdeb5522249" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">比如说,应用 A 保存 6 字节数据,jemalloc 按分配策略分配 8 字节。如果应用 A 不再保存新数据</span><span style="letter-spacing: 0.5px;">,那么,这里多出来的 2 字节空间就是内存碎片了,如下图所示:</span></p> <p style="margin-top: 10px;margin-bottom: 10px;"><span data-card-type="inline" data-lake-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fcdn.nlark.com%2Fyuque%2F0%2F2020%2Fpng%2F663581%2F1603618846651-ab920289-5af3-4764-b17e-ea88c5fddd1f.png%22%2C%22originWidth%22%3A2318%2C%22originHeight%22%3A1031%2C%22name%22%3A%22image.png%22%2C%22size%22%3A183244%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22ocrLocations%22%3A%5B%7B%22x%22%3A932.8838%2C%22y%22%3A121.227776%2C%22width%22%3A725.8166%2C%22height%22%3A101.42002399999998%2C%22text%22%3A%22%E5%BA%94%E7%94%A8A%E7%94%B3%E8%AF%B76%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A729.2544%2C%22y%22%3A464.2201%2C%22width%22%3A299.17859999999996%2C%22height%22%3A76.64430000000004%2C%22text%22%3A%22%E5%AE%9E%E9%99%85%E6%95%B0%E6%8D%AE%22%7D%2C%7B%22x%22%3A1541.5945%2C%22y%22%3A478.55798%2C%22width%22%3A302.953%2C%22height%22%3A77.79302000000001%2C%22text%22%3A%22%E7%A2%8E%E7%89%87%E7%A9%BA%E9%97%B4%22%7D%2C%7B%22x%22%3A873.9359%2C%22y%22%3A750.626%2C%22width%22%3A877.8113000000001%2C%22height%22%3A91.04655000000002%2C%22text%22%3A%22%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E5%99%A8%E5%AE%9E%E9%99%85%E5%88%86%E9%85%8D8%E5%AD%97%22%7D%2C%7B%22x%22%3A874.5199%2C%22y%22%3A857.2166%2C%22width%22%3A541.0912000000001%2C%22height%22%3A87.71596%2C%22text%22%3A%22%E8%8A%82%2C%E7%A9%BA%E4%BD%992%E5%AD%97%E8%8A%82%22%7D%5D%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%E5%BA%94%E7%94%A8A%E7%94%B3%E8%AF%B76%E5%AD%97%E8%8A%82%20%E5%AE%9E%E9%99%85%E6%95%B0%E6%8D%AE%20%E7%A2%8E%E7%89%87%E7%A9%BA%E9%97%B4%20%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E5%99%A8%E5%AE%9E%E9%99%85%E5%88%86%E9%85%8D8%E5%AD%97%20%E8%8A%82%2C%E7%A9%BA%E4%BD%992%E5%AD%97%E8%8A%82%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A512%2C%22height%22%3A228%7D"><img data-backh="228" data-backw="512" data-height="228px" data-ratio="0.44466666666666665" src="/upload/b6652d714a240d64ee0bab8f35834529.png" data-type="png" data-w="1500" style="visibility: visible;width: 100%;height: auto;" title="image.png"></span></p> <p data-lake-id="29e6f380443cb9e46ab97743d0b3882c" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" data-wording="true"><span style="letter-spacing: 0.5px;">第二个外因是,这些键值对会被修改和删除,这会导致空间的扩容和释放。具体来说,</span><span style="letter-spacing: 0.5px;">一</span><span style="letter-spacing: 0.5px;">方面,如果修改后的键值对变大或变小了,就需要占用额外的空间或者释放不用的空间。</span><span style="letter-spacing: 0.5px;">另一方面</span><span style="letter-spacing: 0.5px;">,删除的键值对就不再需要内存空间了,此时,就会把空间释放出来,形成空闲空间。</span></p> <p style="margin-top: 10px;margin-bottom: 10px;"><span data-card-type="inline" data-lake-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fcdn.nlark.com%2Fyuque%2F0%2F2020%2Fpng%2F663581%2F1603618898389-65154344-a97e-4042-8dd1-2ae09d12a9c4.png%22%2C%22originWidth%22%3A2483%2C%22originHeight%22%3A2094%2C%22name%22%3A%22image.png%22%2C%22size%22%3A418651%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22ocrLocations%22%3A%5B%7B%22x%22%3A213.01044%2C%22y%22%3A104.698105%2C%22width%22%3A538.43196%2C%22height%22%3A83.24693500000001%2C%22text%22%3A%22%E5%BA%94%E7%94%A8A%E4%BF%9D%E5%AD%983%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A1006.0589%2C%22y%22%3A106.87169%2C%22width%22%3A555.3052%2C%22height%22%3A84.97259%2C%22text%22%3A%22%E5%BA%94%E7%94%A8C%E4%BF%9D%E5%AD%982%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A618.9497%2C%22y%22%3A405.55328%2C%22width%22%3A531.0057%2C%22height%22%3A84.37854000000004%2C%22text%22%3A%22%E5%BA%94%E7%94%A8B%E4%BF%9D%E5%AD%981%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A1516.8481%2C%22y%22%3A406.18677%2C%22width%22%3A545.8841%2C%22height%22%3A85.14717999999999%2C%22text%22%3A%22%E5%BA%94%E7%94%A8D%E4%BF%9D%E5%AD%984%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A215.43896%2C%22y%22%3A855.4129%2C%22width%22%3A539.6196399999999%2C%22height%22%3A80.64765%2C%22text%22%3A%22%E5%BA%94%E7%94%A8A%E4%BF%9D%E5%AD%983%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A1012.7481%2C%22y%22%3A856.02515%2C%22width%22%3A551.3641%2C%22height%22%3A79.23224999999991%2C%22text%22%3A%22%E5%BA%94%E7%94%A8C%E4%BF%9D%E5%AD%982%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A1517.5077%2C%22y%22%3A1153.5024%2C%22width%22%3A530.4152999999999%2C%22height%22%3A80.07129999999984%2C%22text%22%3A%22%E5%BA%94%E7%94%A8D%E5%88%A0%E9%99%A41%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A619.6189%2C%22y%22%3A1155.0494%2C%22width%22%3A530.6340999999999%2C%22height%22%3A79.82679999999982%2C%22text%22%3A%22%E5%BA%94%E7%94%A8B%E4%BF%9D%E5%AD%981%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A1005.55646%2C%22y%22%3A1675.1592%2C%22width%22%3A549.26874%2C%22height%22%3A83.08259999999996%2C%22text%22%3A%22%E5%BA%94%E7%94%A8C%E5%88%A0%E9%99%A42%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A154.64822%2C%22y%22%3A1677.7264%2C%22width%22%3A619.1202099999999%2C%22height%22%3A77.50700000000006%2C%22text%22%3A%22%E5%BA%94%E7%94%A8A%E4%BF%AE%E6%94%B9%E5%90%8E4%E5%AD%97%E8%8A%82%22%7D%2C%7B%22x%22%3A1741.1866%2C%22y%22%3A1680.8741%2C%22width%22%3A654.3739%2C%22height%22%3A75.74929999999995%2C%22text%22%3A%22%E5%BA%94%E7%94%A8B%E6%95%B0%E6%8D%AE%E6%8B%B7%E8%B4%9D%E8%87%B3%E6%AD%A4%22%7D%2C%7B%22x%22%3A1516.1082%2C%22y%22%3A1970.795%2C%22width%22%3A532.3942%2C%22height%22%3A74.61770000000001%2C%22text%22%3A%22%E5%BA%94%E7%94%A8D%E5%88%A0%E9%99%A41%E5%AD%97%E8%8A%82%22%7D%5D%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%E5%BA%94%E7%94%A8A%E4%BF%9D%E5%AD%983%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8C%E4%BF%9D%E5%AD%982%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8B%E4%BF%9D%E5%AD%981%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8D%E4%BF%9D%E5%AD%984%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8A%E4%BF%9D%E5%AD%983%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8C%E4%BF%9D%E5%AD%982%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8D%E5%88%A0%E9%99%A41%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8B%E4%BF%9D%E5%AD%981%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8C%E5%88%A0%E9%99%A42%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8A%E4%BF%AE%E6%94%B9%E5%90%8E4%E5%AD%97%E8%8A%82%20%E5%BA%94%E7%94%A8B%E6%95%B0%E6%8D%AE%E6%8B%B7%E8%B4%9D%E8%87%B3%E6%AD%A4%20%E5%BA%94%E7%94%A8D%E5%88%A0%E9%99%A41%E5%AD%97%E8%8A%82%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A512%2C%22height%22%3A432%7D"><img data-backh="432" data-backw="512" data-height="432px" data-ratio="0.8433333333333334" src="/upload/2271bd7bfaca22ef4e65ccafe1995c41.png" data-type="png" data-w="1500" style="visibility: visible;width: 100%;height: auto;" title="image.png"></span></p> <p data-lake-id="3a20189bac39caa6c8e5614fbe0baece" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;"></span></p> <p style="margin-top: 15px;white-space: normal;text-size-adjust: auto;background-color: rgb(255, 255, 255);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: center;background-size: 112px;background-position: center 20px;background-repeat: no-repeat;"><span style="margin-bottom: 10px;color: rgb(234, 84, 41);outline-style: none;line-height: 48px;border-bottom: 2px solid rgb(234, 84, 41);display: inline-block;letter-spacing: 0.5px;">如何判断是否有内存碎片?</span></p> <section style="text-align: left;margin-top: 10px;"> <span style="display: none;line-height: 0px;">‍</span> <strong style="color: rgb(64, 64, 64);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: 16px;letter-spacing: 0.12px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><span style="letter-spacing: 0.5px;">info 命令:</span></strong> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="properties"><code><span class="code-snippet_outer"><span class="code-snippet__attr">INFO</span> <span class="code-snippet__string">memory</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"># Memory</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">used_memory</span>:<span class="code-snippet__string">1073741736</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">used_memory_human</span>:<span class="code-snippet__string">1024.00M</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">used_memory_rss</span>:<span class="code-snippet__string">1997159792</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">used_memory_rss_human</span>:<span class="code-snippet__string">1.86G</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">…</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">mem_fragmentation_ratio</span>:<span class="code-snippet__string">1.86</span></span></code></pre> </section> <ul data-lake-id="3a7b341836a6062eb9769675173965b9" lake-indent="0" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" class="list-paddingleft-2"> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">mem_fragmentation_ratio: Redis 当前的内存碎片率</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">used_memory_rss: 操作系统实际分配给 Redis 的物理内存空间,里面就包含了碎片</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">used_memory: Redis 为了保存数据实际申请使用的空间</span></p></li> </ul> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="ini"><code><span class="code-snippet_outer"><span class="code-snippet__attr">mem_fragmentation_ratio</span> = used_memory_rss/ used_memory</span></code></pre> </section> <p data-lake-id="36a09104775270d808ae1808c57ac70a" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><br></p> <p data-lake-id="36a09104775270d808ae1808c57ac70a" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="font-size: 16px;"><strong><span style="font-size: 16px;letter-spacing: 0.5px;">经验阈值:</span></strong></span><br></p> <ul data-lake-id="d6dfbe3b6f69b6f20f295e0ee1fa8a6e" lake-indent="0" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" class="list-paddingleft-2"> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">mem_fragmentation_ratio 大于 1 但小于 1.5。这种情况是合理的。这是因为,刚才我介绍的那些因素是难以避免的。毕竟,内因的内存分配器是一定要使用的,分配策略都是通用的,不会轻易修改;而外因由 Redis 负载决定,也无法限制。所以,存在内存碎片也是正常的。</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">mem_fragmentation_ratio 大于 1.5 。这表明内存碎片率已经超过了 50%。一般情况下,这个时候,我们就需要采取一些措施来降低内存碎片率了。</span></p></li> </ul> <p style="margin-top: 15px;white-space: normal;text-size-adjust: auto;background-color: rgb(255, 255, 255);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: center;background-size: 112px;background-position: center 20px;background-repeat: no-repeat;"><span style="margin-bottom: 10px;color: rgb(234, 84, 41);outline-style: none;line-height: 48px;border-bottom: 2px solid rgb(234, 84, 41);display: inline-block;letter-spacing: 0.5px;">如何清理内存碎片?</span></p> <section style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;margin-top: 10px;"> <span style="font-size: 16px;"><strong><span style="font-size: 16px;letter-spacing: 0.5px;">重启 Redis 实例:</span></strong></span> </section> <ul data-lake-id="a7e8be5182e8ab7ab142196340f2b794" lake-indent="0" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" class="list-paddingleft-2"> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">如果 Redis 中的数据没有持久化,那么,数据就会丢失;</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">即使 Redis 数据持久化了,我们还需要通过 AOF 或 RDB 进行恢复,恢复时长取决于 AOF 或 RDB 的大小,如果只有一个 Redis 实例,恢复阶段无法提供服务。</span></p></li> </ul> <p data-lake-id="d38c78c03cdb71bab3b33d5a8b8793b2" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">幸运的是,从 4.0-RC3 版本以后,Redis 自身提供了一种内存碎片自动清理的方法:</span></p> <p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><strong style="font-size: 16px;letter-spacing: 0.008em;"><span style="letter-spacing: 0.5px;"></span></strong></p> <p data-lake-id="1fc102ae4b8a9a7b17e49f83d27d1883" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" data-wording="true"><strong><span style="letter-spacing: 0.5px;">Redis 专门为自动内存碎片清理功机制设置的参数:</span></strong><span style="letter-spacing: 0.5px;"></span></p> <ul data-lake-id="958ac6009e39e3125c36926c6a5c7a4a" lake-indent="0" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" class="list-paddingleft-2"> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">控制碎片清理的开始和结束时机</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">占用的 CPU 比例</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">从而减少碎片清理对 Redis 本身请求处理的性能影响</span></p></li> </ul> <p data-lake-id="75ce70a180766d4cb829242619c67fba" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">首先,Redis 需要启用自动内存碎片清理,可以把 activedefrag 配置项设置为 yes,命令如下:</span><span style="color: rgb(255, 76, 65);"><em><span style="color: rgb(255, 76, 65);letter-spacing: 0.5px;"><span style="color: rgb(255, 76, 65);white-space: pre-wrap;font-family: &quot;Chinese Quote&quot;, -apple-system, system-ui, &quot;Segoe UI&quot;, Roboto, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;font-size: 14px;text-align: start;">config set activedefrag yes</span></span></em></span></p> <p data-lake-id="52ca816b3e3cb9902db547826795fcae" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><br></p> <p data-lake-id="52ca816b3e3cb9902db547826795fcae" data-wording="true" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><strong><span style="letter-spacing: 0.5px;">触发清理的条件 (需要同时满足):</span></strong><span style="letter-spacing: 0.5px;"></span></p> <ul data-lake-id="dffac5e254e75bd84b5592d8bb027f20" lake-indent="0" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" class="list-paddingleft-2"> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">active-defrag-ignore-bytes 100mb:表示内存碎片的字节数达到 100MB 时,开始清理;</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">active-defrag-threshold-lower 10:表示内存碎片空间占操作系统分配给 Redis 的总空间比例达到 10% 时,开始清理。</span></p></li> </ul> <p style="margin-top: 15px;white-space: normal;text-size-adjust: auto;background-color: rgb(255, 255, 255);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: center;background-size: 112px;background-position: center 20px;background-repeat: no-repeat;"><span style="margin-bottom: 10px;color: rgb(234, 84, 41);outline-style: none;line-height: 48px;border-bottom: 2px solid rgb(234, 84, 41);display: inline-block;letter-spacing: 0.5px;">注意事项</span></p> <section style="margin-top: 10px;white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"> <span style="letter-spacing: 0.5px;">为了尽可能减少碎片清理对 Redis 正常请求处理的影响,自动内存碎片清理功能在执行时,还会监控清理操作占用的 CPU 时间,而且还设置了两个参数,分别用于控制清理操作占用的 CPU 时间比例的上、下限,既保证清理工作能正常进行,又避免了降低 Redis 性能。</span> <span style="letter-spacing: 0.5px;">这两个参数具体如下:</span> </section> <ul data-lake-id="47ef03ea6d82d79cfed424a18384500e" lake-indent="0" style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;" class="list-paddingleft-2"> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">active-defrag-cycle-min 25:表示自动清理过程所用 CPU 时间的比例不低于 25%,保证清理能正常开展;</span></p></li> <li style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;">active-defrag-cycle-max 75:表示自动清理过程所用 CPU 时间的比例不高于 75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致响应延迟升高。</span></p></li> </ul> <p style="white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: left;line-height: 2em;"><span style="letter-spacing: 0.5px;"></span></p> <section data-recommend-type="list-title" data-recommend-tid="8" data-mpa-template="t" style="width: 100%;display: flex;justify-content: center;align-items: center;" data-mid="" data-from="yb-recommend"> <section style="width: 100%;background: rgb(255, 255, 255);border-radius: 3px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 235);padding: 20px 14px;" data-mid=""> <section style="width: 100%;display: flex;justify-content: center;align-items: center;align-items: flex-end;" data-mid=""> <section style="display: flex;justify-content: center;align-items: center;max-width: 100%;background: #fff;margin-bottom: -10px;z-index: 10;" data-mid=""> <section style="width: 10px;height: 10px;border-radius: 50%;border-width: 1px;border-style: solid;border-color: rgb(51, 51, 51);" data-mid=""> <br> </section> <section style="margin: 0 8px;height: 20px;font-size: 14px;font-weight: 500;color: #333333;line-height: 20px;" data-mid=""> <p data-mid="">往期推荐</p> </section> <section style="width: 10px;height: 10px;border-radius: 50%;border-width: 1px;border-style: solid;border-color: rgb(51, 51, 51);" data-mid=""> <br> </section> </section> </section> <section style="width: 100%;height: 1px;background: #333333;margin-bottom: 16px;" data-mid=""> <br> </section> <section style="width: 100%;" data-mid=""> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="8" data-recommend-article-id="2247492221_1" data-recommend-article-time="1605184200" data-recommend-article-cover="http://mmbiz.qpic.cn/sz_mmbiz_jpg/d7YzaYDnrxFVq2TibUDobEXottfInu5u2icAIVIpFSUM4V9RsX1RlKPNoTn5cVP7K3Q1XUqm9ia48nemC2DkSTBOQ/0?wx_fmt=jpeg" data-recommend-article-title="消息模型:主题和队列有什么区别?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492221&amp;idx=1&amp;sn=8fbddf58fc155393b5fbe7767188e51d&amp;chksm=fd63f2c2ca147bd4fcfd7cd4a2b3ed8aa9188dc0d983b460e2cbea34fc93647f1c4895a2b549#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492221&amp;idx=1&amp;sn=8fbddf58fc155393b5fbe7767188e51d&amp;chksm=fd63f2c2ca147bd4fcfd7cd4a2b3ed8aa9188dc0d983b460e2cbea34fc93647f1c4895a2b549&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;background: #f5f5f5;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px 6px;font-size: 13px;font-weight: 400;color: #333333;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">消息模型:主题和队列有什么区别?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="8" data-recommend-article-id="2247492141_1" data-recommend-article-time="1605096000" data-recommend-article-cover="http://mmbiz.qpic.cn/sz_mmbiz_jpg/d7YzaYDnrxGwhZE4vYAWQ4EDgWloI9IVpwLAT4WQ1HHFVU0R9ichjlic531C2OLBX7vrMIqSBKKHnYLp4NxELefw/0?wx_fmt=jpeg" data-recommend-article-title="Hash算法原理解析" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492141&amp;idx=1&amp;sn=7976dc8f1a77381a6d250cc68d8817f4&amp;chksm=fd63f292ca147b8405d7c866c38e51fc6930cd46b4167aefb4f835df81f75326923dbaf939d8#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492141&amp;idx=1&amp;sn=7976dc8f1a77381a6d250cc68d8817f4&amp;chksm=fd63f292ca147b8405d7c866c38e51fc6930cd46b4167aefb4f835df81f75326923dbaf939d8&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px 6px;font-size: 13px;font-weight: 400;color: #333333;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">Hash算法原理解析</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="8" data-recommend-article-id="2247492141_2" data-recommend-article-time="1605096000" data-recommend-article-cover="http://mmbiz.qpic.cn/sz_mmbiz_jpg/d7YzaYDnrxFSO1Kbbghqj0poHTwYHcRqkXt2nkmt72Qw2toj3uODfTBm9xJszDiaSTZibf1D2enupv47Zqu1QQGw/0?wx_fmt=jpeg" data-recommend-article-title="MySQL中悲观锁和乐观锁到底是什么?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492141&amp;idx=2&amp;sn=d8396552c713d3ffd09fec5901967469&amp;chksm=fd63f292ca147b84a1f2894586adcbee9363d1bf295719c6abf65aed1a867fb3a3235305efd2#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492141&amp;idx=2&amp;sn=d8396552c713d3ffd09fec5901967469&amp;chksm=fd63f292ca147b84a1f2894586adcbee9363d1bf295719c6abf65aed1a867fb3a3235305efd2&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;background: #f5f5f5;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px 6px;font-size: 13px;font-weight: 400;color: #333333;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">MySQL中悲观锁和乐观锁到底是什么?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="8" data-recommend-article-id="2247492089_1" data-recommend-article-time="1605005938" data-recommend-article-cover="http://mmbiz.qpic.cn/sz_mmbiz_jpg/d7YzaYDnrxGH6UBOeEKxiaT3ibTiaq2qZibwHwRHVico7ic4BEYIpmiauDPbjeiagnZXKJqbwQFhA6xTINIJwrB6kpUz3A/0?wx_fmt=jpeg" data-recommend-article-title="走进黑盒:SQL是如何在数据库中执行的?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492089&amp;idx=1&amp;sn=e4f4b5371719393d2ebcba8ebf38cd7c&amp;chksm=fd63f146ca14785001deabc783cec970c9f99c955e0eb7e633db69f816507f030c5430778427#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492089&amp;idx=1&amp;sn=e4f4b5371719393d2ebcba8ebf38cd7c&amp;chksm=fd63f146ca14785001deabc783cec970c9f99c955e0eb7e633db69f816507f030c5430778427&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px 6px;font-size: 13px;font-weight: 400;color: #333333;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">走进黑盒:SQL是如何在数据库中执行的?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="8" data-recommend-article-id="2247492089_2" data-recommend-article-time="1605005938" data-recommend-article-cover="http://mmbiz.qpic.cn/sz_mmbiz_jpg/d7YzaYDnrxGwhZE4vYAWQ4EDgWloI9IVicOjrOa7hdMUIhSrdLlK5HOSeibpwU0wPcwQZZoza13S7kVSYKsR8ibpQ/0?wx_fmt=jpeg" data-recommend-article-title="一致性哈希设计思想" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492089&amp;idx=2&amp;sn=33fe645bdaff42820dfe043dd710b541&amp;chksm=fd63f146ca147850809217e62e6e79332880180d8a0096849d634f21fa14fe6c88c2caf0edb0#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492089&amp;idx=2&amp;sn=33fe645bdaff42820dfe043dd710b541&amp;chksm=fd63f146ca147850809217e62e6e79332880180d8a0096849d634f21fa14fe6c88c2caf0edb0&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;background: #f5f5f5;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px 6px;font-size: 13px;font-weight: 400;color: #333333;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">一致性哈希设计思想</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="8" data-recommend-article-id="2247492089_3" data-recommend-article-time="1605005938" data-recommend-article-cover="http://mmbiz.qpic.cn/sz_mmbiz_jpg/d7YzaYDnrxGH6UBOeEKxiaT3ibTiaq2qZibwicldrGRNzwiaVftGgOY7JvbhwwalOb68iaA942XQML3IwcWzcPDicKm7ibA/0?wx_fmt=jpeg" data-recommend-article-title="解读Redis缓存穿透,缓存击穿以及缓存雪崩问题,附带解决方式" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492089&amp;idx=3&amp;sn=92bf8302fa27d67d48b513131cba78f9&amp;chksm=fd63f146ca147850cc410d2bfbc20179e5871aeeedd3807dc1d1f26a4854904f403634e7af71#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&amp;mid=2247492089&amp;idx=3&amp;sn=92bf8302fa27d67d48b513131cba78f9&amp;chksm=fd63f146ca147850cc410d2bfbc20179e5871aeeedd3807dc1d1f26a4854904f403634e7af71&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;padding: 6px 16px 6px;font-size: 13px;font-weight: 400;color: #333333;line-height: 18px;border-bottom:none !important;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">解读Redis缓存穿透,缓存击穿以及缓存雪崩问题,附带解决方式</p> </section></a> </section> </section> </section> </section> <section style="margin-top: 10px;white-space: normal;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;background-color: rgb(255, 255, 255);font-size: 15px;color: rgb(64, 64, 64);letter-spacing: 0.008em;outline-style: none;text-align: center;line-height: 2em;"> <img class="rich_pages js_insertlocalimg" data-ratio="0.21328125" data-s="300,640" src="/upload/62e1c66b7ebe4ae627c388db8f4eef36.png" data-type="png" data-w="1280" data-backw="578" data-backh="123" style="text-indent: 0pt;color: rgb(63, 74, 89);font-family: 微软雅黑;font-size: 11pt;letter-spacing: 0.4pt;width: 100%;"> <br> </section>

Postgre SQL:Problem running post-install step windows 10

作者:じ☆ve不哭

> 今天安装postgresql遇到Problem running post-install step问题。我本地是win10最新的系统。 1、遇到上述问题直接点击确定,让他继续安装 2、安装后:我的电脑->右键管理->服务和应用程序->服务->postgresql-x64-13 ![1.png](/storage/thumbnails/_signature/1SR1H6R3G4F1R6O1UGI8B8GQFQ.png) 3、点击postgresql-x64-13->右键属性->登录->登录身份选择本地系统并允许与桌面交互 ![2.png](/storage/thumbnails/_signature/229T85ONERR07S3E1ALJIONV6H.png) 4、大功告成,可以连接啦

接口测试并不只是测试参数和返回值

作者:测试人生路

一般理解的接口测试无非就是,输入url、参数值,点击请求发送查看一下响应值和响应状态码是否正常就完事儿了。 ![1.png](/storage/thumbnails/_signature/36RLU5IR2FTLS57V1Q98VJ6L0D.png) 但是接口测试真正的关注点不值这些,今天就给大家说说接口测试有那些需要关注的地方。 在实际项目中,后端接口测试通过后,一般前端还需要再测试一遍,读者可能会提出疑问:后端接口测试一遍,前端也测试一遍,是不是重复测试了?其实这两者并不重复,区别在于后端接口测试和前端功能测试各自的侧重点不一样,后端接口测试侧重点是检查数据的交换、传递和控制管理过程。而前端功能测试更加测试检测提供给用户的使用功能是否正确可用。虽然各种测试的重点不一样,但也存在相同的部分,以功能测试、业务逻辑测试、性能测试和安全测试为例: ## 一、接口功能关注点 功能测试:由于测试最终的目标都是业务功能是否正确且稳定可用,所以不管是前端给用户使用的功能策是,还是后端的接口测试,功能保障是基本要求,也是后端测试和前端测试两种测试重合度最高的一块。 具体关注点: 1.接口的功能是否正确实现了 2.接口是否按照设计文档中来实现(比如username参数写为了name,那么这就不符合,因为接口文档在整个开发中都需要使用,所以接口实际的设计要与接口设计文档中保持一致) 3.兼容性测试: 比如说今天接口进行了调整,但是前端没有进行变更,这时候需要验证新的接口是否满足旧的调用方式 4.错误码测试: 通用的错误码与业务错误码是否能够清晰的说明调用问题,错误码是否能够尽可能的全的覆盖所有的情况 5.返回值测试: 返回值除了内容需要是正确的,还需要类型也是正确的,保证调用方拿到这些参数能够正确的解析 6.默认值测试: 很多情况一些非必填的参数会有默认值,比如说一个查询的接口,参数count为返回查询的结果数量, 默认为10,那么就应该有一条case来测试,当然前置条件是数据库里面必须要存在这样的数据超过10条。 ## 二、接口业务逻辑测试 1.是否有依赖业务,比如查看订单,是需要用户首先登录的,所以肯定要保证登录了或有相应的cookie 2.业务逻辑测试: 传递正确的参数,接口对数据库进行查询的操作,需要去验证数据库查询是否正确,接口对数据库进行 增删改的操作,也需要看数据库是否同步进行了这些操作 ## 三、接口性能测试 1.接口响应时间 2.接口对应的服务器的吞吐量 3.接口并发数量 4.服务器进出口带宽 ## 四、接口安全测试 1.接口中敏感信息是否加密 2.必要参数是否后端也进行校验(现在很多系统前后端架构是分离的,从安全层面来说,只依赖前端进行限制已经完全不能满足系统的安全要求(绕过前端太容易了), 需要后端同样进行控制,在这种情况下就需要从接口层面进行验证) 3.接口是否防恶意请求(SQL注入) 4.cookie:就是将header中的cookie修改或删除后看是否能返回相应的error code 5.header:就是删除或修改header中部分参数的值,看是否能返回相应的error code 6.唯一识别码:删除修改唯一识别码测试 ## 五、接口测试工具 [apipost](https://www.apipost.cn/?dt=20201118)可以进行接口的功能测试和业务逻辑测试,除此之外还有强大的接口文档生成功能。 ![2.png](/storage/thumbnails/_signature/322LCICJVCAQ4C4QM1OHVM18MI.png) jmeter强大的接口性能测试功能 ![3.png](/storage/thumbnails/_signature/C3UUNOUCG0OKEMR77RG6C6DNI.png)