作者:微信小助手
<p style="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;" data-mpa-powered-by="yiban.io"><span data-mce-style="font-size: 10px" style="color: rgb(64, 64, 64);letter-spacing: 0.008em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;"><span style="color: #888888;">点击上方蓝色“</span></span><span data-mce-style="font-size: 10px" style="letter-spacing: 0.008em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;color: rgb(24, 144, 255);font-size: 13px;">后端面试那些事儿</span><span data-mce-style="font-size: 10px" style="color: rgb(64, 64, 64);letter-spacing: 0.008em;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;"><span style="color: #888888;">”,选择“设为星标”</span></span><span style="letter-spacing: 0.544px;color: rgb(127, 127, 127);font-size: 14px;line-height: 1.75em;"></span></p> <p data-lake-id="f47942fff38c686ed626a530b6d84219" style="text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><span style="color: rgb(140, 140, 140);font-size: 13px;letter-spacing: 0.008em;">学最好的别人,做最好的我们</span><br></p> <p style="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;"><img data-ratio="0.5614583333333333" src="/upload/fd7b0fd7a83bfd8512e329e88adc1ed.jpg" data-type="jpeg" data-w="960"></p> <section style="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);"> <section> <section> <section> <blockquote data-type="2" data-url="" data-author-name="" data-content-utf8-length="48" data-source-title="" style="color: rgba(0, 0, 0, 0.5);"> <section> <section> <p style="margin-bottom: 10px;color: rgba(0, 0, 0, 0.498);letter-spacing: 0.544px;line-height: normal;"><span style="font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;text-align: start;widows: 1;font-size: 10px;color: rgb(178, 178, 178);">作者:编码砖家</span></p> <p style="margin-bottom: 10px;color: rgba(0, 0, 0, 0.498);letter-spacing: 0.544px;line-height: normal;"><span style="font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;text-align: start;widows: 1;font-size: 10px;color: rgb(178, 178, 178);">cnblogs.com/xiaoyangjia/p/11267191.html</span><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;widows: 1;"></span></p> </section> </section> </blockquote> </section> </section> </section> </section> <ul class="list-paddingleft-2" style="list-style-type: square;"> <li><p style="text-align: left;"><span style="font-size: 13px;">MySQL性能</span></p></li> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: left;"><span style="font-size: 13px;">最大数据量</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">最大并发数</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">查询耗时0.5秒</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">实施原则</span></p></li> </ul> <li><p style="text-align: left;"><span style="font-size: 13px;">数据表设计</span></p></li> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: left;"><span style="font-size: 13px;">数据类型</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">避免空值</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">text类型</span></p></li> </ul> <li><p style="text-align: left;"><span style="font-size: 13px;">索引优化</span></p></li> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: left;"><span style="font-size: 13px;">索引分类</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">优化原则</span></p></li> </ul> <li><p style="text-align: left;"><span style="font-size: 13px;">SQL优化</span></p></li> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: left;"><span style="font-size: 13px;">分批处理</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">不做列运算</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">避免Select *</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">操作符<>优化</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">OR优化</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">IN优化</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">LIKE优化</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">JOIN优化</span></p></li> <li><p style="text-align: left;"><span style="font-size: 13px;">LIMIT优化</span></p></li> </ul> <li><p style="text-align: left;"><span style="font-size: 13px;">其他数据库</span></p></li> </ul> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">博主负责的项目主要采用阿里云数据库MySQL,最近频繁出现慢SQL告警,执行时间最长的竟然高达5分钟。导出日志后分析,主要原因竟然是没有命中索引和没有分页处理。其实这是非常低级的错误,我不禁后背一凉,团队成员的技术水平亟待提高啊。改造这些SQL的过程中,总结了一些经验分享给大家,如果有错误欢迎批评指正。</p> <h2 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.2em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">MySQL性能</span></h2> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">最大数据量</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.4747634069400631" data-s="300,640" data-type="png" data-w="634" src="/upload/d20f4bd4ba6497c5ebd879cd75831c8e.png" style=""></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">博主曾经操作过超过4亿行数据的单表,分页查询最新的20条记录耗时0.6秒,SQL语句大致是<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;border-radius: 4px;background: rgb(248, 248, 248);">select field_1,field_2 from table where id < #{prePageMinId} order by id desc limit 20</code>,prePageMinId是上一页数据记录的最小ID。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">虽然当时查询速度还凑合,随着数据不断增长,有朝一日必定不堪重负。分库分表是个周期长而风险高的大活儿,应该尽可能在当前结构上优化,比如升级硬件、迁移历史数据等等,实在没辙了再分。对分库分表感兴趣的同学可以阅读分库分表的基本思想。</p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">最大并发数</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">并发数是指同一时刻数据库能处理多少个请求,由max_connections和max_user_connections决定。max_connections是指MySQL实例的最大连接数,上限值是16384,max_user_connections是指每个数据库用户的最大连接数。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">MySQL会为每个连接提供缓冲区,意味着消耗更多的内存。如果连接数设置太高硬件吃不消,太低又不能充分利用硬件。一般要求两者比值超过10%,计算方法如下:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);display: block;font-family: Consolas, Inconsolata, Courier, monospace;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">max<span style="font-size: inherit;color: inherit;line-height: inherit;font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">_used_</span>connections / max_connections <span style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">* 100% = 3/100 *</span>100% ≈ 3%<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">查看最大连接数与响应最大连接数:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);display: block;font-family: Consolas, Inconsolata, Courier, monospace;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">show</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">variables</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">like</span> <span style="font-size: inherit;color: rgb(162, 252, 162);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">'%max_connections%'</span>;<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">show</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">variables</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">like</span> <span style="font-size: inherit;color: rgb(162, 252, 162);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">'%max_user_connections%'</span>;<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">在配置文件my.cnf中修改最大连接数</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);display: block;font-family: Consolas, Inconsolata, Courier, monospace;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span style="font-size: inherit;color: rgb(255, 255, 170);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">[mysqld]</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">max_connections</span> = <span style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">100</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">max_used_connections</span> = <span style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">20</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">查询耗时0.5秒</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">建议将单次查询耗时控制在0.5秒以内,0.5秒是个经验值,源于用户体验的3秒原则。如果用户的操作3秒内没有响应,将会厌烦甚至退出。响应时间=客户端UI渲染耗时+网络请求耗时+应用程序处理耗时+查询数据库耗时,0.5秒就是留给数据库1/6的处理时间。</p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">实施原则</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">相比NoSQL数据库,MySQL是个娇气脆弱的家伙。它就像体育课上的女同学,一点纠纷就和同学闹别扭(扩容难),跑两步就气喘吁吁(容量小并发低),常常身体不适要请假(SQL约束太多)。如今大家都会搞点分布式,应用程序扩容比数据库要容易得多,所以实施原则是<strong style="color: inherit;font-size: inherit;line-height: inherit;">数据库少干活,应用程序多干活</strong>。</p> <ul style="list-style-type: square;" class="list-paddingleft-2"> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">充分利用但不滥用索引,须知索引也消耗磁盘和CPU。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">不推荐使用数据库函数格式化数据,交给应用程序处理。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">不推荐使用外键约束,用应用程序保证数据准确性。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">写多读少的场景,不推荐使用唯一索引,用应用程序保证唯一性。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">适当冗余字段,尝试创建中间表,用应用程序计算中间结果,用空间换时间。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">不允许执行极度耗时的事务,配合应用程序拆分成更小的事务。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">预估重要数据表(比如订单表)的负载和数据增长态势,提前优化。</span><span style="font-size: inherit;color: inherit;line-height: inherit;"></span></p></li> </ul> <h2 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.2em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">数据表设计</span></h2> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">数据类型</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">数据类型的选择原则:更简单或者占用空间更小。</p> <ul style="list-style-type: square;" class="list-paddingleft-2"> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">如果长度能够满足,整型尽量使用tinyint、smallint、medium_int而非int。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">如果字符串长度确定,采用char类型。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">如果varchar能够满足,不采用text类型。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">精度要求较高的使用decimal类型,也可以使用BIGINT,比如精确两位小数就乘以100后保存。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">尽量采用timestamp而非datetime。</span><span style="font-size: inherit;color: inherit;line-height: inherit;"></span></p></li> </ul> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.1836734693877551" data-s="300,640" data-type="png" data-w="686" src="/upload/d4bf84317a27be5bb235c814dcdb7192.png" style=""></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">相比datetime,timestamp占用更少的空间,以UTC的格式储存自动转换时区。<br></p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">避免空值</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">MySQL中字段为NULL时依然占用空间,会使索引、索引统计更加复杂。从NULL值更新到非NULL无法做到原地更新,容易发生索引分裂影响性能。尽可能将NULL值用有意义的值代替,也能避免SQL语句里面包含is not null的判断。</p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">text类型优化</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">由于text字段储存大量数据,表容量会很早涨上去,影响其他字段的查询性能。建议抽取出来放在子表里,用业务主键关联。</p> <h2 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.2em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">索引优化</span></h2> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">索引分类</span></h3> <ul style="list-style-type: square;" class="list-paddingleft-2"> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">普通索引:最基本的索引。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">组合索引:多个字段上建立的索引,能够加速复合查询条件的检索。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">唯一索引:与普通索引类似,但索引列的值必须唯一,允许有空值。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">组合唯一索引:列值的组合必须唯一。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">主键索引:特殊的唯一索引,用于唯一标识数据表中的某一条记录,不允许有空值,一般用primary key约束。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">全文索引:用于海量文本的查询,MySQL5.6之后的InnoDB和MyISAM均支持全文索引。由于查询精度以及扩展性不佳,更多的企业选择Elasticsearch。</span><span style="font-size: inherit;color: inherit;line-height: inherit;"></span></p></li> </ul> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">索引优化</span></h3> <ul style="list-style-type: square;" class="list-paddingleft-2"> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">分页查询很重要,如果查询数据量超过30%,MYSQL不会使用索引。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">单表索引数不超过5个、单个索引字段数不超过5个。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">字符串可使用前缀索引,前缀长度控制在5-8个字符。</span></p></li> <li><p><span style="color: inherit;line-height: inherit;font-size: 15px;">字段唯一性太低,增加索引没有意义,如:是否删除、性别。</span><span style="font-size: inherit;color: inherit;line-height: inherit;"></span></p></li> </ul> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">合理使用覆盖索引,如下所示:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);display: block;font-family: Consolas, Inconsolata, Courier, monospace;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">select</span> login_name, nick_name <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">from</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">member</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">where</span> login_name = ?<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">login_name, nick_name两个字段建立组合索引,比login_name简单索引要更快。索引优化可以参考:<a href="http://mp.weixin.qq.com/s?__biz=MzU2MTI4MjI0MQ==&mid=2247485634&idx=1&sn=76f99ceab80fe79a73c3e9b40b803312&chksm=fc7a656ccb0dec7a4e0f4ac7626afae8d68c6f8b74f1664c0ec34496605cd5a2b17073113100&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" style="text-decoration: underline;color: rgb(136, 136, 136);" data-linktype="2"><span style="color: rgb(136, 136, 136);">MySQL索引优化分析</span></a></p> <h2 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.2em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">SQL优化</span></h2> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;color: rgb(21, 153, 87);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="font-size: inherit;color: inherit;line-height: inherit;">分批处理</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">博主小时候看到鱼塘挖开小口子放水,水面有各种漂浮物。浮萍和树叶总能顺利通过出水口,而树枝会挡住其他物体通过,有时还会卡住,需要人工清理。MySQL就是鱼塘,最大并发数和网络带宽就是出水口,用户SQL就是漂浮物。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">不带分页参数的查询或者影响大量数据的update和delete操作,都是树枝,我们要把它打散分批处理,举例说明:</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">业务描述:更新用户所有已过期的优惠券为不可用状态。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">SQL语句:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);display: block;font-family: Consolas, Inconsolata, Courier, monospace;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;"><span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">update</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">status</span>=<span style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">0</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">FROM</span> <span style="font-size: inherit;color: rgb(162, 252, 162);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">`coupon`</span> <span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">WHERE</span> expire_date <= <span style="font-size: inherit;color: rgb(136, 136, 136);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">#{currentDate} and status=1;</span><br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">如果大量优惠券需要更新为不可用状态,执行这条SQL可能会堵死其他SQL,分批处理伪代码如下:</p> <pre style="font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code style="margin-right: 2px;margin-left: 2px;padding: 0.5em;font-size: 12px;color: white;line-height: 15px;border-radius: 0px;background: rgb(51, 51, 51);display: block;font-family: Consolas, Inconsolata, Courier, monospace;overflow-x: auto;word-spacing: -3px;letter-spacing: 0px;overflow-wrap: normal !important;word-break: normal !important;overflow-y: auto !important;">int pageNo = <span style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">1</span>;<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">int PAGE_SIZE = <span style="font-size: inherit;color: rgb(211, 99, 99);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">100</span>;<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">while</span>(<span style="font-size: inherit;color: rgb(252, 194, 140);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">true</span>) {<br style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"> List<Integer> batchIdList = queryList(<span style="font-size: inherit;color: rgb(162, 252, 162);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">'select id FROM `coupon` WHERE expire_date <= <span style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">#{currentDate}</span> and status = 1 limit <span style="font-size: inherit;color: inherit;line-
作者:微信小助手
<section style="font-size: 15px;line-height: 2;box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">本节篇幅较长,我们主要围绕以下几点来展开:</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class="list-paddingleft-2" style="list-style-type: disc;box-sizing: border-box;"> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">什么是服务网格?</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">初识 Istio</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">核心特性</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">流程架构</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">核心模块</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">Envoy 进阶</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">方案畅想</p></li> </ul> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">对许多公司来说,Docker 和 Kubernetes 这样的工具已经解决了部署问题,或者说几乎解决了。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">但他们还没有解决运行时的问题,这就是服务网格(Service Mesh)的由来。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width:0;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: top;width: 33.33%;box-sizing: border-box;"> <section style="text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;width: 30%;box-sizing: border-box;"> <img data-ratio="0.8814815" data-w="1080" src="/upload/3fa901c1afa7ff2ec6661a198dc9d97c.jpg" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" width="100%" data-type="jpeg"> </section> </section> </section> <section style="display: inline-block;vertical-align: top;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width:0;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="text-align: center;font-size: 18px;color: rgb(0, 117, 168);box-sizing: border-box;" powered-by="xiumi.us"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">什么是服务网格?</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">服务网格(Service Mesh)用来描述组成这些应用程序的微服务网络以及它们之间的交互。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">它是一个用于保证服务间安全、快速、可靠通信的网络代理组件,是随着微服务和云原生应用兴起而诞生的基础设施层。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;">它通常以轻量级网络代理的方式同应用部署在一起。比如 Sidecar 方式,如下图所示:</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;"> <img data-ratio="0.5231481" data-w="1080" src="/upload/fcefcde00e2489f8bf15d537f143d6fe.jpg" style="vertical-align: middle;max-width: 100%;box-sizing: border-box;" data-type="jpeg"> </section> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">我们对上图做个解释:Service Mesh 设计一般划分为两个模块,控制面和数据面。对于应用来说,所有流量都会经过数据面进行转发。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">顺利转发的前提:数据面需要知道转发的目标地址,目标地址本身是由一些业务逻辑来决定的(例如服务发现)。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">所以自然而然地,我们可以推断控制面需要负责管理数据面能正常运行所需要的一些配置:</p> <ul class="list-paddingleft-2" style="list-style-type: disc;box-sizing: border-box;"> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;">需要知道某次请求转发去哪里:</strong>服务发现配置。</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;">外部流量进入需要判断是否已经达到服务流量上限:</strong>限流配置。</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;">依赖服务返回错误时,需要能够执行相应的熔断逻辑:</strong>熔断配置。</p></li> </ul> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Serivce Mesh 可以看作是一个位于 TCP/IP 之上的网络模型,抽象了服务间可靠通信的机制。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">但与 TCP 不同,它是面向应用的,为应用提供了统一的可视化和控制。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Service Mesh 具有如下优点:</p> <ul class="list-paddingleft-2" style="list-style-type: disc;box-sizing: border-box;"> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">屏蔽分布式系统通信的复杂性(负载均衡、服务发现、认证授权、监控追踪、流量控制等等),服务只用关注业务逻辑。</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">真正的语言无关,服务可以用任何语言编写,只需和 Service Mesh 通信即可。</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">对应用透明,Service Mesh 组件可以单独升级。</p></li> </ul> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Service Mesh 目前也面临一些挑战:</p> <ul class="list-paddingleft-2" style="list-style-type: disc;box-sizing: border-box;"> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">Service Mesh 组件以代理模式计算并转发请求,一定程度上会降低通信系统性能,并增加系统资源开销。</p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;">Service Mesh 组件接管了网络流量,因此服务的整体稳定性依赖于 Service Mesh,同时额外引入的大量 Service Mesh 服务实例的运维和管理也是一个挑战。</p></li> </ul> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">随着服务网格的规模和复杂性不断的增长,它将会变得越来越难以理解和管理。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Service Mesh 的需求包括服务发现、负载均衡、故障恢复、度量和监控等。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Service Mesh 通常还有更复杂的运维需求,比如 A/B 测试、金丝雀发布、速率限制、访问控制和端到端认证。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Service Mesh 的出现,弥补了 Kubernetes 在微服务的连接、管理和监控方面的短板,为 Kubernetes 提供更好的应用和服务管理。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">因此,Service Mesh 的代表 Istio 一经推出,就被认为是可以和 Kubernetes 形成双剑合璧效果的微服务管理的利器,受到了业界的推崇。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Istio 提供了对整个服务网格的行为洞察和操作控制的能力,以及一个完整的满足微服务应用各种需求的解决方案。</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Istio 主要采用一种一致的方式来保护、连接和监控微服务,降低了管理微服务部署的复杂性。<br style="box-sizing: border-box;"></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width:0;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> <section style="display: inline-block;vertical-align: top;width: 33.33%;box-sizing: border-box;"> <section style="text-align: center;box-sizing: border-box;" powered-by="xiumi.us"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;width: 30%;box-sizing: border-box;"> <img data-ratio="0.8814815" data-w="1080" src="/upload/3fa901c1afa7ff2ec6661a198dc9d97c.jpg" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" width="100%" data-type="jpeg"> </section> </section> </section> <section style="display: inline-block;vertical-align: top;width: 33.33%;box-sizing: border-box;line-height: 0;"> <section style="line-height: 0;width:0;"> <svg viewbox="0 0 1 1" style="vertical-align:top;"></svg> </section> </section> </section> <section style="text-align: center;font-size: 18px;color: rgb(0, 117, 168);box-sizing: border-box;" powered-by="xiumi.us"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">初识 Istio</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Istio 发音「意丝帝欧」,重音在意上。官方给出的 Istio 的总结,简单明了:</p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">Istio lets you connect, secure, control, and observe services.</p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;">连接、安全、控制和观测服务。</p> <p style="white-spac
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.05em;" data-mpa-powered-by="yiban.io"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.05em;"> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(150, 84, 181);border-right: 1px solid rgb(150, 84, 181);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">标题仅仅作为参考,究竟是用 Datagrip、Navicat 还是 DBeaver 完全就属于个人自由了,仁者见仁智者见智。各有优点,各有缺点。工具究竟还是只是工具,选择一个适合自己的就好。</p> </blockquote> </section> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247489523&idx=1&sn=4e96972842bdcea2e05cb267d17c5e8e&chksm=cea25838f9d5d12e45a9939370eccf2bff7177038e70437ea0e01d64030118852ee66ae72284&token=2000865596&lang=zh_CN&scene=21#wechat_redirect" data-linktype="2" style="color: rgb(52, 11, 209);font-weight: bold;border-bottom: 1px solid rgb(52, 11, 209);">《再见,Navicat!同事安利的这个 IDEA 的兄弟,真香!》</a> 这篇文章发了之后很多人抱怨 Datagrip 的占用内存太大,很多人推荐了 DBeaver 这款开源免费的数据库管理工具。<br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.38242894056847543" data-s="300,640" src="/upload/b5ebf0c51d8e024a3a78a7bb96fb4048.png" data-type="png" data-w="1548"></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.07383419689119171" data-s="300,640" src="/upload/f5d68cfce0194db7d8494462d2032144.png" data-type="png" data-w="1544"></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.08354430379746836" data-s="300,640" src="/upload/c7b05824ae0073698a18b66072ba2b3e.png" data-type="png" data-w="1580"></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">于是,我昨夜简单体验了一下 DBeaver ,然后写了这篇文章。<br></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">毕竟开源免费,也不需和 Datagrip 在功能上做太多对比。总体体验的话我觉得比不上 Datagrip,但是涵盖的功能也基本够用了,内存占用也只有0.5g左右。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.12643678160919541" data-s="300,640" src="/upload/87061fdb51ea70a21659a5876e57a68b.png" data-type="png" data-w="1914" style=""></p> <h2 data-tool="mdnice编辑器" style="margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 22px;min-height: 32px;line-height: 28px;color: rgb(70, 51, 118);border-bottom: 1px solid rgb(70, 51, 118);border-top-color: rgb(70, 51, 118);border-right-color: rgb(70, 51, 118);border-left-color: rgb(70, 51, 118);text-align: center;width: 474.297px;display: flex;flex-direction: column;justify-content: center;">DBeaver 概览</h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">DBeaver 是一个基于 Java 开发 ,并且支持几乎所有的数据库产品的开源数据库管理工具。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">DBeaver 社区版不光支持关系型数据库比如 MySQL、PostgreSQL、MariaDB、SQLite、Oracle、Db2、SQL Server,还比如 SQLite、H2 这些内嵌数据库。还支持常见的全文搜索引擎比如 Elasticsearch 和 Solr、大数据相关的工具比如 Hive 和 Spark。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1" src="/upload/18578a66b0a4a73afc235e6fb3abc47d.jpg" data-type="jpeg" data-w="2000" style="margin-right: auto;margin-left: auto;display: block;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> DBeaver 支持的数据库概览 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">甚至说,DBeaver 的商业版本还支持各种 NoSQL 数据库。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8605664488017429" src="/upload/2e574815768df08e90a45d9b919a9034.png" data-type="png" data-w="1836" style="margin-right: auto;margin-left: auto;display: block;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 14px;"> DBeaver 的商业版本还支持各种 NoSQL 数据库 </figcaption> </figure> <h2 data-tool="mdnice编辑器" style="margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 22px;min-height: 32px;line-height: 28px;color: rgb(70, 51, 118);border-bottom: 1px solid rgb(70, 51, 118);border-top-color: rgb(70, 51, 118);border-right-color: rgb(70, 51, 118);border-left-color: rgb(70, 51, 118);text-align: center;width: 474.297px;display: flex;flex-direction: column;justify-content: center;">使用</h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;"><strong style="color: rgb(70, 51, 118);">DBeaver 虽然小巧,但是功能还是十分强大的。基本的表设计、SQL 执行、ER 图、数据导入导出等等常用功能都不在话下。</strong></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;"><strong style="color: rgb(70, 51, 118);">我下面只简单演示一下基本的数据库的创建以及表的创建。</strong></p> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 1em;padding-left: 10px;font-weight: bold;font-size: 20px;color: rgb(70, 51, 118);border-left: 2px solid rgb(70, 51, 118);">下载安装</h3> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">官方网提供的下载地址:https://dbeaver.io/download/ ,你可以根据自己的操作系统选择合适的版本进行下载安装。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">比较简单,这里就不演示了。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 1em;padding-left: 10px;font-weight: bold;font-size: 20px;color: rgb(70, 51, 118);border-left: 2px solid rgb(70, 51, 118);">连接数据库</h3> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;"><strong style="color: rgb(70, 51, 118);">1.选择自己想要的连接的数据库,然后点击下一步即可(第一次连接可能需要下载相关驱动)。</strong></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">我这里以 MySQL 为例。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.6302395209580839" src="/upload/cb4e80874d9e6e76e5550ab3b3538dc9.png" data-type="png" data-w="2672" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;"><strong style="color: rgb(70, 51, 118);"><br>2.输入数据库的地址、用户名和密码等信息,然后点击完成即可连接</strong></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">点击完成之前,你可以先通过左下方的测试连接来看一下数据库是否可以被成功连接上。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9577874818049491" src="/upload/6c9503bada971027d6d52c84e9e3e69f.png" data-type="png" data-w="1374" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 1em;padding-left: 10px;font-weight: bold;font-size: 20px;color: rgb(70, 51, 118);border-left: 2px solid rgb(70, 51, 118);">新建数据库</h3> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">右键-> 新建数据库(MySQL 用户记得使用 utf8mb4 而不是 utf8)</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4459574468085106" src="/upload/76502cd66ebd8dd27ca316848690e60.png" data-type="png" data-w="2350" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 1.2em;margin-bottom: 1em;padding-left: 10px;font-weight: bold;font-size: 20px;color: rgb(70, 51, 118);border-left: 2px solid rgb(70, 51, 118);">数据库表相关操作</h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: black;">新建表</h4> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7542533081285444" src="/upload/f2e19f18e89e0031b1c71f905c5536e6.png" data-type="png" data-w="1058" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: black;">新建列</h4> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.6336317135549873" src="/upload/17de5db4af2b25278a081da46073b307.png" data-type="png" data-w="3128" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: black;">创建约束(主键、唯一键)</h4> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8227488151658767" src="/upload/76152ea2fc12717ddf993a06837521b7.png" data-type="png" data-w="2110" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.227810650887574" src="/upload/99762790e39ee7cb61e6a2a14b432dd.png" data-type="png" data-w="676" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: black;">插入数据</h4> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">我们通过 SQL 编辑器插入数据:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9774436090225563" src="/upload/b09cc49d7474ea3f53b9ad10d9d0ce6e.png" data-type="png" data-w="1064" style="margin-right: auto;margin-left: auto;display: block;"> </figure> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="margin-bottom: -7px;display: block;background: url("https://mmbiz.qpic.cn/mmbiz_png/iaIdQfEric9TwlzI9H0maLAOxibM2HJsKL5MxkLtrnEkVibe1rAY4L0t3s5RiapVMMicIUtBqv2FggRbW2FfNt9WqfJg/640?wx_fmt=png") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 558px;border-radius: 5px;"></span><code style="padding: 15px 16px 16px;overflow-x: auto;color: rgb(221, 221, 221);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(39, 40, 34);border-radius: 5px;"><span style="line-height: 26px;">INSERT into <span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">user</span><span style="line-height: 26px;">(id,name,phone,password)</span> <span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">values</span> <span style="line-height: 26px;">(<span style="color: rgb(166, 226, 46);line-height: 26px;">'A00001'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'guide哥'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'181631312315'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'123456'</span>)</span></span>;<br><span style="line-height: 26px;">INSERT into <span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">user</span><span style="line-height: 26px;">(id,name,phone,password)</span> <span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">values</span> <span style="line-height: 26px;">(<span style="color: rgb(166, 226, 46);line-height: 26px;">'A00002'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'guide哥2'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'181631312313'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'123456'</span>)</span></span>;<br><span style="line-height: 26px;">INSERT into <span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">user</span><span style="line-height: 26px;">(id,name,phone,password)</span> <span style="color: rgb(166, 226, 46);font-weight: bold;line-height: 26px;">values</span> <span style="line-height: 26px;">(<span style="color: rgb(166, 226, 46);line-height: 26px;">'A00003'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'guide哥3'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'181631312312'</span>,<span style="color: rgb(166, 226, 46);line-height: 26px;">'123456'</span>)</span></span>;<br></code></pre> <h2 data-tool="mdnice编辑器" style="margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 22px;min-height: 32px;line-height: 28px;color: rgb(70, 51, 118);border-bottom: 1px solid rgb(70, 51, 118);border-top-color: rgb(70, 51, 118);border-right-color: rgb(70, 51, 118);border-left-color: rgb(70, 51, 118);text-align: center;width: 474.297px;display: flex;flex-direction: column;justify-content: center;">总结</h2> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">总的来说,简单体验之后感觉还是很不错的,占用内存也确实比 DataGrip 确实要小很多。</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;color: black;">各位小伙伴可以自行体验一下。毕竟免费并且开源,还是很香的!</p> </section> <h2 data-tool="mdnice编辑器" style="margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;font-size: 22px;min-height: 32px;line-height: 28px;color: rgb(70, 51, 118);border-bottom: 1px solid rgb(70, 51, 118);border-top-color: rgb(70, 51, 118);border-right-color: rgb(70, 51, 118);border-left-color: rgb(70, 51, 118);text-align: center;width: 558.438px;display: flex;flex-direction: column;justify-content: center;">最后</h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;"> <strong>我整理的4本PDF文档,本公众号后台回复“<span style="color: rgb(255, 76, 0);">面试突击</span>”即可免费获取。<br></strong> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;"> <strong><span style="color: rgb(255, 76, 0);"></span></strong> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;"> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.698" data-s="300,640" src="/upload/86104159376110b31e587cbe56c6c29c.png" data-type="png" data-w="2000" style=""></p> <span style="color: rgb(255, 76, 0);"><br></span> </figure> <p><span style="color: rgb(47, 48, 52);font-family: "PingFang SC", Tahoma, Helvetica, Arial, "Hiragino Sans GB", "Microsoft YaHei", "Heiti SC", "WenQuanYi Micro Hei", sans-serif;font-size: 15px;text-align: start;white-space: pre-wrap;background-color: rgb(255, 255, 255);">最近在看《增长黑客》,感觉还是挺不错的。待我看完之后,这一个简单的总结/书评分享出来。</span><span style="border-width: 0px;border-style: initial;border-color: initial;font-variant-numeric: inherit;font-variant-east-asian: inherit;font-stretch: inherit;font-size: 15px;line-height: inherit;font-family: "PingFang SC", Tahoma, Helvetica, Arial, "Hiragino Sans GB", "Microsoft YaHei", "Heiti SC", "WenQuanYi Micro Hei", sans-serif;-webkit-tap-highlight-color: transparent;height: 24px;display: inline-block;vertical-align: middle;color: rgb(47, 48, 52);text-align: start;white-space: pre-wrap;background-color: rgb(255, 255, 255);"><img data-ratio="1" src="/upload/c807b18511019c724e5c2edb0d30ee89.png" data-type="png" data-w="48" style="border-width: initial;border-style: none;border-color: initial;font: inherit;-webkit-tap-highlight-color: transparent;display: block;width: 20px;height: 20px;" title="呲牙"></span></p> <p style="text-align: center;"><img data-ratio="1.4425925925925926" src="/upload/ea70a1a6008df93706785eb10febe3a3.jpg" data-type="jpeg" data-w="540" style="width: 269px;height: 388px;"></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;white-space: normal;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.05em;box-sizing: border-box !important;overflow-wrap: break-word !important;">文章有帮助可以点个「</span><strong style="max-width: 100%;letter-spacing: 0.05em;color: rgb(70, 51, 118);box-sizing: border-box !important;overflow-wrap: break-word !important;">在看</strong><span style="max-width: 100%;letter-spacing: 0.05em;box-sizing: border-box !important;overflow-wrap: break-word !important;">」或「</span><strong style="max-width: 100%;letter-spacing: 0.05em;color: rgb(70, 51, 118);box-sizing: border-box !important;overflow-wrap: break-word !important;">分享」</strong><span style="max-width: 100%;letter-spacing: 0.05em;box-sizing: border-box !important;overflow-wrap: break-word !important;">,都是支持,我都喜欢!</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;white-space: normal;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);font-size: 16px;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;"><em style="max-width: 100%;color: rgb(227, 92, 51);box-sizing: border-box !important;overflow-wrap: break-word !important;">我是Guide哥,Java后端开发,会一点前端知识,喜欢烹饪,自由的少年。一个三观比主角还正的技术人。我们下期再见!</em></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;letter-spacing: 0.544px;white-space: normal;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"></figure>
作者:微信小助手
<section data-mpa-powered-by="yiban.io"> <p class="js_darkmode__0" style="margin-top: 0em;margin-bottom: 0em;padding-right: 0.5em;padding-left: 0.5em;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;widows: 1;text-align: center;color: rgb(62, 71, 83);letter-spacing: 0.54px;visibility: visible;"><span style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"><span style="letter-spacing: 0.544px;word-spacing: 2px;caret-color: rgb(51, 51, 51);font-size: 13px;color: rgb(136, 136, 136);"></span></span><img class="rich_pages" data-backh="371" data-backw="578" data-ratio="0.6426076833527358" data-s="300,640" src="/upload/a14e88ca809e9b397b668c2554bc5eb9.png" data-type="png" data-w="1718" style="color: rgb(51, 51, 51);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;width: 100%;"></p> <p style="color: inherit;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="color: rgb(136, 136, 136);letter-spacing: 1px;font-size: 12px;">来源:cnblogs.com/xifengxiaoma/p/9402497.html</span><br></p> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 20px;text-align: left;"><span style="line-height: inherit;color: rgb(61, 167, 66);letter-spacing: 1px;font-size: 18px;">JVisualVM 简介</span></h1> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带,能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)。在JDK_HOME/bin(默认是C:\Program Files\Java\jdk1.6.0_13\bin)目录下面,有一个jvisualvm.exe文件,双击打开,从UI上来看,这个软件是基于NetBeans开发的了。</span></p> <p style="line-height: normal;"><br></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">VisualVM 提供了一个可视界面,用于查看 Java 虚拟机 (Java Virtual Machine, JVM) 上运行的基于 Java 技术的应用程序的详细信息。VisualVM 对 Java Development Kit (JDK) 工具所检索的 JVM 软件相关数据进行组织,并通过一种使您可以快速查看有关多个 Java 应用程序的数据的方式提供该信息。您可以查看本地应用程序或远程主机上运行的应用程序的相关数据。此外,还可以捕获有关 JVM 软件实例的数据,并将该数据保存到本地系统,以供后期查看或与其他用户共享。</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">双击启动 jvisualvm.exe,启动起来后和jconsole 一样同样可以选择本地和远程,如果需要监控远程同样需要配置相关参数。</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">主界面如下;</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/b74555d797c9c0aab034a63dfdd8953.jpg" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="jpeg" data-ratio="0.6082272282076395" data-w="1021"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">VisualVM可以根据需要安装不同的插件,每个插件的关注点都不同,有的主要监控GC,有的主要监控内存,有的监控线程等。</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/f29e2a41976565a2825de5a8667b748b.jpg" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="jpeg" data-ratio="0.6136114160263447" data-w="911"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">如何安装:</span></p> <blockquote style="line-height: inherit;margin-top: 0px;padding-top: 0px;margin-bottom: 16px;padding-right: 1em;padding-left: 1em;color: rgb(106, 115, 125);border-left-width: 0.25em;border-left-color: rgb(223, 226, 229);font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, "PingFang SC", Helvetica, Arial, "Hiragino Sans GB", "Microsoft YaHei", SimSun, 宋体, Heiti, 黑体, sans-serif;font-size: 14px;white-space: normal;"> <p style="color: inherit;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">1、从主菜单中选择“工具”>“插件”。2、在“可用插件”标签中,选中该插件的“安装”复选框。单击“安装”。3、逐步完成插件安装程序。</span></p> </blockquote> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">我这里以 Eclipse(pid 22296)为例,双击后直接展开,主界面展示了系统和jvm两大块内容,点击右下方jvm参数和系统属性可以参考详细的参数信息.</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/ff2307bacc886ac73ff613262d21e304.jpg" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="jpeg" data-ratio="0.5892351274787535" data-w="1059"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">因为VisualVM的插件太多,我这里主要介绍三个我主要使用几个:监控、线程、Visual GC</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">监控的主页其实也就是,cpu、内存、类、线程的图表</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/6fe9294fb2ded296302c518a9f6771a5.jpg" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="jpeg" data-ratio="0.5388888888888889" data-w="1080"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">线程和jconsole功能没有太大的区别</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/6b573407884b2213665317b8deb2e2c0.jpg" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="jpeg" data-ratio="0.5388888888888889" data-w="1080"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">Visual GC 是常常使用的一个功能,可以明显的看到年轻代、老年代的内存变化,以及gc频率、gc的时间等。</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/ff2307bacc886ac73ff613262d21e304.jpg" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="jpeg" data-ratio="0.5892351274787535" data-w="1059"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">以上的功能其实jconsole几乎也有,VisualVM更全面更直观一些,另外VisualVM非常多的其它功能,可以分析dump的内存快照,</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">dump出来的线程快照并且进行分析等,还有其它很多的插件大家可以去探索</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/a58d9d79223ab31088a0dc25d4d3b10e.jpg" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="jpeg" data-ratio="0.4447592067988669" data-w="1059"> </figure> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 20px;text-align: left;"><span style="line-height: inherit;color: rgb(61, 167, 66);letter-spacing: 1px;font-size: 18px;">案例分析</span></h1> <h2 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 20px;text-align: left;"><span style="line-height: inherit;color: rgb(61, 167, 66);letter-spacing: 1px;font-size: 18px;">准备模拟内存泄漏样例</span></h2> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">1、定义静态变量HashMap</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">2、分段循环创建对象,并加入HashMap</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">代码如下:</span></p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 5px;padding: 0.5em;background: rgb(30, 30, 30);color: rgb(220, 220, 220);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">`<span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">import</span> java.util.HashMap; <br><span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">import</span> java.util.Map; <br><span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">class</span> <span style="line-height: inherit;color: rgb(220, 220, 220);overflow-wrap: inherit !important;word-break: inherit !important;">CyclicDependencies</span> {</span> <br> <span style="line-height: inherit;color: rgb(87, 166, 74);font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">//声明缓存对象 </span><br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">private</span> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">static</span> final Map <span style="line-height: inherit;color: rgb(78, 201, 176);overflow-wrap: inherit !important;word-break: inherit !important;">map</span> = <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">new</span> HashMap(); <br> <span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">static</span> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">void</span> <span style="line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">main(String args[])</span></span>{ <br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">try</span> { <br> Thread.sleep(<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">10000</span>);<span style="line-height: inherit;color: rgb(87, 166, 74);font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">//给打开visualvm时间 </span><br> } <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span> (InterruptedException e) { <br> e.printStackTrace(); <br> } <br> <span style="line-height: inherit;color: rgb(87, 166, 74);font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">//循环添加对象到缓存 </span><br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>(<span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">int</span> i=<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>; i<<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">1000000</span>;i++){ <br> TestMemory t = <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">new</span> TestMemory(); <br> <span style="line-height: inherit;color: rgb(78, 201, 176);overflow-wrap: inherit !important;word-break: inherit !important;">map</span>.put(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"key"</span>+i,t); <br> } <br> System.out.println(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"first"</span>); <br> <span style="line-height: inherit;color: rgb(87, 166, 74);font-style: italic;overflow-wrap: inherit !important;word-break: inherit !important;">//为dump出堆提供时间 </span><br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">try</span> { <br> Thread.sleep(<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">10000</span>); <br> } <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span> (InterruptedException e) { <br> e.printStackTrace(); <br> } <br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>(<span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">int</span> i=<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>; i<<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">1000000</span>;i++){ <br> TestMemory t = <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">new</span> TestMemory(); <br> <span style="line-height: inherit;color: rgb(78, 201, 176);overflow-wrap: inherit !important;word-break: inherit !important;">map</span>.put(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"key"</span>+i,t); <br> } <br> System.out.println(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"second"</span>); <br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">try</span> { <br> Thread.sleep(<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">10000</span>); <br> } <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span> (InterruptedException e) { <br> e.printStackTrace(); <br> } <br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>(<span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">int</span> i=<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>; i<<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">3000000</span>;i++){ <br> TestMemory t = <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">new</span> TestMemory(); <br> <span style="line-height: inherit;color: rgb(78, 201, 176);overflow-wrap: inherit !important;word-break: inherit !important;">map</span>.put(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"key"</span>+i,t); <br> } <br> System.out.println(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"third"</span>); <br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">try</span> { <br> Thread.sleep(<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">10000</span>); <br> } <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span> (InterruptedException e) { <br> e.printStackTrace(); <br> } <br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>(<span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">int</span> i=<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>; i<<span style="line-height: inherit;color: rgb(184, 215, 163);overflow-wrap: inherit !important;word-break: inherit !important;">4000000</span>;i++){ <br> TestMemory t = <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">new</span> TestMemory(); <br> <span style="line-height: inherit;color: rgb(78, 201, 176);overflow-wrap: inherit !important;word-break: inherit !important;">map</span>.put(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"key"</span>+i,t); <br> } <br> System.out.println(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"forth"</span>); <br> <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">try</span> { <br> Thread.sleep(Integer.MAX_VALUE); <br> } <span style="line-height: inherit;color: rgb(86, 156, 214);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span> (InterruptedException e) { <br> e.printStackTrace(); <br> } <br> System.out.println(<span style="line-height: inherit;color: rgb(214, 157, 133);overflow-wrap: inherit !important;word-break: inherit !important;">"qqqq"</span>); <br> } <br>} <br>`<br></span></code></pre> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">3、配置jvm参数如下:</span></p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 5px;padding: 0.5em;background: rgb(30, 30, 30);color: rgb(220, 220, 220);overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;text-align: left;"><span style="font-size: 16px;line-height: inherit;color: rgb(214, 157, 133);letter-spacing: 1px;overflow-wrap: inherit !important;word-break: inherit !important;">` -Xms512m <br> -Xmx512m <br> -XX:-UseGCOverheadLimit <br> -XX:MaxPermSize=50m <br>`<br></span></code></pre> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">4、运行程序并打卡visualvm监控</span></p> <h2 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 20px;text-align: left;"><span style="line-height: inherit;color: rgb(61, 167, 66);letter-spacing: 1px;font-size: 18px;">使用JVisualVM分析内存泄漏</span></h2> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">1、查看Visual GC标签,内容如下,这是输出first的截图</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/ab98871d47c36a73d84abb8ddb0b485e.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.562037037037037" data-w="1080"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">这是输出forth的截图:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/c758bfad235ca33be80dd6c7e5ad3e14.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.5388888888888889" data-w="1080"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">通过2张图对比发现:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/db7b5c4ad37616283738647313305ff1.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.07526881720430108" data-w="372"> </figure> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/e0859ef2666c4628019ed6da4d6d1ba5.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.05291005291005291" data-w="378"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">老生代一直在gc,当程序继续运行可以发现老生代gc还在继续:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/95766a30ad78694e24667d3b20899fd1.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.0515695067264574" data-w="446"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">增加到了7次,但是老生代的内存并没有减少。说明存在无法被回收的对象,可能是内存泄漏了。</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">如何分析是那个对象泄漏了呢?打开抽样器标签:点击后如下图:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/c33f8fe6648523f8c353d1b637e7e370.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.5027777777777778" data-w="1080"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">按照程序输出进行堆dump,当输出second时,dump一次,当输出forth时dump一次。</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">进入最后dump出来的堆标签,点击类:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/91c7eeb300179a0644e664c1fb050f45.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.13213213213213212" data-w="333"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">点击右上角:“与另一个堆存储对比”。如图选择第一次导出的dump内容比较:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/219887c060c421204220c26b457a4e95.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.8526315789473684" data-w="380"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">比较结果如下:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/b54038027b13cc8d7904e529fef25df5.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.19369369369369369" data-w="666"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">可以看出在两次间隔时间内TestMemory对象实例一直在增加并且多了,说明该对象引用的方法可能存在内存泄漏。</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">如何查看对象引用关系呢?</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">右键选择类TestMemory,选择“在实例视图中显示”,如下所示:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/703191d58cc0164fd1b7f2398640c747.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.4444444444444444" data-w="1080"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">左侧是创建的实例总数,右侧上部为该实例的结构,下面为引用说明,从图中可以看出在类CyclicDependencies里面被引用了,并且被HashMap引用。</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">如此可以确定泄漏的位置,进而根据实际情况进行分析解决。</span></p> <h2 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 20px;text-align: left;"><span style="line-height: inherit;color: rgb(61, 167, 66);letter-spacing: 1px;font-size: 18px;">JVisualVM 远程监控 Tomcat</span></h2> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">1、修改远程tomcat的catalina.sh配置文件,在其中增加:</span></p> <ol style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: 16px;color: inherit;line-height: inherit;margin-bottom: 0.5em;letter-spacing: 1px;"><p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">JAVA_OPTS="$JAVA_OPTS</span></p></li> <li style="font-size: 16px;color: inherit;line-height: inherit;margin-bottom: 0.5em;letter-spacing: 1px;"><p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">-Djava.rmi.server.hostname=192.168.122.128</span></p></li> <li style="font-size: 16px;color: inherit;line-height: inherit;margin-bottom: 0.5em;letter-spacing: 1px;"><p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">-Dcom.sun.management.jmxremote.port=18999</span></p></li> <li style="font-size: 16px;color: inherit;line-height: inherit;margin-bottom: 0.5em;letter-spacing: 1px;"><p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">-Dcom.sun.management.jmxremote.ssl=false</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">-Dcom.sun.management.jmxremote.authenticate=false"</span></p><p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">这次配置先不走权限校验。只是打开jmx端口。</span></p><p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">2、打开jvisualvm,右键远程,选择添加远程主机:</span></p></li> </ol> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/3f0761d6de2438940db47bcf1c1fc0f2.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.42328042328042326" data-w="378"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">3、输入主机的名称,直接写ip,如下:</span></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img src="/upload/bf0d84fa9e5d1c2716b0639510b0f61b.png" title="" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" data-type="png" data-ratio="0.18181818181818182" data-w="220"> </figure> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">右键新建的主机,选择添加JMX连接,输入在tomcat中配置的端口即可。</span></p> <p style="color: inherit;margin-top: 15px;margin-bottom: 15px;line-height: 2em;text-align: left;"><span style="font-size: 16px;letter-spacing: 1px;">4、双击打开。完毕!</span></p> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 20px;text-align: left;"><span style="line-height: inherit;color: rgb(61, 167, 66);letter-spacing: 1px;font-size: 18px;">参考资料</span></h1> <section style="color: inherit;margin-top: 15px;margin-bottom: 15px;text-align: left;line-height: normal;"> <span style="letter-spacing: 1px;font-size: 14px;">https://blog.csdn.net/kl28978113/article/details/53817827</span> </section> <section style="color: inherit;margin-top: 15px;margin-bottom: 15px;text-align: left;line-height: normal;"> <span style="font-size: 14px;letter-spacing: 1px;color: inherit;">https://www.cnblogs.com/ityouknow/p/6437037.html</span> </section> <h4 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;white-space: normal;text-align: left;color: rgb(0, 0, 0);background-color: rgb(255, 255, 255);widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);line-height: 1.2;"> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: normal;"> <strong style="font-size: 14px;letter-spacing: 0.544px;"></strong> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: normal;"> <strong style="font-size: 14px;letter-spacing: 0.544px;">最近热文阅读:</strong> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">1、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487873&idx=1&sn=7091ea9587e9417b0f1b76801c4570ce&chksm=f98151e4cef6d8f28e48b031b21ee712fd03cd8e690867222625f0ff401337c6da778a487a99&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2">JVM的YGC,这次被它搞惨了!</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">2、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487803&idx=1&sn=9e623af52dadf26b2756d30a4c2e0cdf&chksm=f981515ecef6d848d1762a9d4d2f935db43b0a0a73504a9990053175b41026af0da780fccf20&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">数据量很大,分页查询很慢,有什么优化方案?</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">2、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487785&idx=1&sn=a9e3c95347e930b3a1a0b26e43624a2c&chksm=f981514ccef6d85aeeda3b3dacc7e19e071b9af4cadedc89c02d650a8430bbaed0541eda2f8a&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">42 天内强制收购,还要大笔中间费,美国凭什么要求 Tiktok 出售美国业务?</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">3、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487771&idx=1&sn=e4cf279e5d4bc81c915c71854d647411&chksm=f981517ecef6d868b562e4c441bba5ace7c765d9dcc20007625ddbcb4d3dd8bb2d48bcd3e23c&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">王者荣耀为什么不使用微服务架构?</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">4、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487766&idx=1&sn=379cb232a87be92c8d21919f797af48d&chksm=f9815173cef6d865cbbf7794410ad6dd9bca70577480316876f3c142fb31198fe45676896543&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">面试官问:高并发下,你都怎么选择最优的线程数?</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">5、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487755&idx=1&sn=b2d9e324e670faad04c1348ec7db3940&chksm=f981516ecef6d878570cb8a77d7cd512bd3b1372c5e7f5539215c19f7e6ab7e8c4864e8a89bd&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">面试官:假如说我们现在要做一个千万级用户量网站,你怎么设计高并发架构?</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">6、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487747&idx=1&sn=6c6f7541ede303176dd6e4ab34dd4b71&chksm=f9815166cef6d870fa13dbf91916523f894cdc54f24baca889f9cf02e159aa916f2cf9281e1d&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">记一次由Redis分布式锁造成的重大事故,避免以后踩坑!</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">7、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487739&idx=1&sn=f6a6df4e9a883905cccbdeb4faa759ce&chksm=f981509ecef6d988334ca9747c4bf394ea1fb885c995411042798c187415cc18580d4dd84893&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">5种主要的软件架构模式</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">8、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487681&idx=1&sn=df7cdbc78362a29d6ce226f7e9870165&chksm=f98150a4cef6d9b2942c967ca326dc4b793302430f516e28468f605e4a18995e672231a35923&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">常用算法复杂度速查表,蹲坑的功夫都能背</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">9、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487674&idx=1&sn=1e383f21601c9e76c1cdcf1d3ae2e2bb&chksm=f98150dfcef6d9c90c691e58a0e90c93d962975c4e28add24b8384af3ab753ab434bede8a063&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">最棒 Spring Boot 干货总结</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;"> <span style="font-size: 14px;letter-spacing: 0.544px;">10、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxOTAxODc2Mg==&mid=2247487658&idx=1&sn=f0df2450e9d80c5acd196700334c065b&chksm=f98150cfcef6d9d93d73929cc5542c24b2a260169a88e4be60eafa9fe2668be914c50dace8d9&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">SQL查找是否"存在",别再count了,很耗费时间的</a></span> </section> <section style="margin-top: 15px;margin-bottom: 15px;letter-spacing: 0.544px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);line-height: 2em;text-align: center;"> <img data-ratio="1" data-type="jpeg" data-w="258" data-s="300,640" data-cropsely2="258" data-cropsely1="0" data-cropselx2="258" data-cropselx1="0" data-copyright="0" src="/upload/9c6744a7edd8decafdc050c3b976b194.jpg" style="max-width: 677px;background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: center center;background-repeat: no-repeat;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;visibility: visible !important;width: 258px !important;"> </section> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 677px;color: rgb(62, 62, 62);caret-color: rgb(51, 51, 51);min-height: 17px;letter-spacing: 0.48px;line-height: normal;text-align: center;"> <span style="color: rgb(136, 136, 136);font-size: 13px;">关注公众号,你想要的Java都在这里</span> </section></h4> </section>
作者:微信小助手
<p style="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;text-size-adjust: auto;color: rgb(0, 0, 0);font-size: medium;background-color: rgb(255, 255, 255);text-align: center;word-break: normal !important;" data-mpa-powered-by="yiban.io"><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;word-break: normal !important;">欢迎关注公众号“</span><span style="font-size: 13px;font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);word-break: normal !important;">码农架构</span><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;word-break: normal !important;">”</span><strong 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;text-align: right;word-break: normal !important;"></strong></p> <p style="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;text-size-adjust: auto;color: rgb(0, 0, 0);font-size: medium;background-color: rgb(255, 255, 255);text-align: center;word-break: normal !important;"><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;word-break: normal !important;">专注于高可用、高性能、高并发类技术分享!</span></p> <section style="margin-top: 5px;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;text-size-adjust: auto;color: rgb(0, 0, 0);font-size: medium;text-align: center;background-color: rgb(255, 255, 255);margin-bottom: 5px;word-break: normal !important;"> <img data-ratio="0.0625" data-w="640" data-type="png" src="/upload/f378fd8bc917b4aec1204ea03d12894c.png" style="box-sizing: border-box !important;word-break: normal !important;visibility: visible !important;width: 640px !important;"> </section> <p style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin-top: 5px;margin-bottom: 5px;"><span style="font-size: 15px;">从0到1把</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab-ci</span></code><span style="font-size: 15px;">弄好了, 彻底抛弃</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">travis-ci</span></code><span style="font-size: 15px;">, 最大的坑还是墙外的东西太慢了, 总是timeout<br></span></p> <section style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin-top: 5px;margin-bottom: 5px;"> <span style="font-size: 15px;">整个过程分为如下几步:</span> </section> <ul class="list-paddingleft-2" style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;"> <li style="font-size: 15px;"> <section style="text-align: left;margin-top: 5px;margin-bottom: 5px;"> <span style="font-size: 15px;">如何在一个1核2G的云服务器上搭建gitlab: 十分钟搭建Gitlab</span> </section></li> <li> <section style="text-align: left;margin-top: 5px;margin-bottom: 5px;"> <span style="font-size: 15px;">使用</span> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab-runner</span></code> <span style="font-size: 15px;">, 并选择正确的</span> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">executor</span></code> </section></li> <li style="font-size: 15px;"> <section style="text-align: left;margin-top: 5px;margin-bottom: 5px;"> <span style="font-size: 15px;">如何构建前端镜像</span> </section></li> <li style="font-size: 15px;"> <section style="text-align: left;margin-top: 5px;margin-bottom: 5px;"> <span style="font-size: 15px;">如何构建后端镜像</span> </section></li> <li> <section style="text-align: left;margin-top: 5px;margin-bottom: 5px;"> <span style="font-size: 15px;">编写</span> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab-ci.yml</span></code> <span style="font-size: 15px;">, 实现一个完整的前端后分离项目的构建部署</span> </section></li> </ul> <h2 style="margin-top: 24px;margin-bottom: 16px;padding-bottom: 0.3em;font-weight: 600;font-size: 1.5em;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;line-height: 1.25;border-bottom: 1px solid rgb(234, 236, 239);text-align: left;"><span style="font-size: 18px;">1. 使用gitlab-runner</span></h2> <section style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin-bottom: 5px;"> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab-runner</span></code> <span style="font-size: 15px;">跟</span> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab-ci</span></code> <span style="font-size: 15px;">是连体婴, 主要为</span> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab-ci</span></code> <span style="font-size: 15px;">打工, 使用镜像的安装方式如下:</span> </section> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(51, 51, 51);color: white;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">docker run -d --name gitlab-runner --restart always \<br> -v /srv/gitlab-runner/config:/etc/gitlab-runner \<br> -v /var/run/docker.sock:/var/run/docker.sock \<br> gitlab/gitlab-runner:latest<br></code></pre> </section> <section style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin-bottom: 5px;"> <span style="font-size: 15px;">其中挂载卷</span> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">/srv/gitlab-runner/config/config.toml</span></code> <span style="font-size: 15px;">包含了所有</span> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">runner</span></code> <span style="font-size: 15px;">的配置信息.</span> </section> <section style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin-bottom: 5px;"> <span style="font-size: 15px;">通过挂载</span> <code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">/var/run/docker.sock:/var/run/docker.sock</span></code> <span style="font-size: 15px;">,<span style="font-weight: 600;">使得容器中的进程可以通过它与Docker守护进程通信</span></span> </section> <p style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><img class="rich_pages" data-ratio="0.5275" data-s="300,640" data-type="jpeg" data-w="800" src="/upload/9d5f0ee423bdcf644b62aac6f3b104cc.jpg" style="box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-bottom: 16px;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><br></p> <p style="margin-bottom: 16px;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><span style="font-weight: 600;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;">1.1 选择Docker作为runner的executor</span></p> <p style="margin-bottom: 16px;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><span style="font-size: 15px;">在启动了</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab-runner</span></code><span style="font-size: 15px;">容器后, 执行如下命令进入容器, 注册</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">runner</span></code></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(51, 51, 51);color: white;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">docker exec -it gitlab-runner /bin/bash<br>root@492ce6ab72f9:/# gitlab-runner register<br></code></pre> </section> <p style="margin-bottom: 16px;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><span style="font-size: 15px;">接下来需要填写的信息如下:</span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;padding: 0.5em;background: rgb(51, 51, 51);color: white;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">Please enter the gitlab-ci coordinator URL:<br>你的Gitlab地址: http(s):<span style="font-size: inherit;line-height: inherit;color: rgb(136, 136, 136);overflow-wrap: inherit !important;word-break: inherit !important;">//gitlab.xxx.com</span><br>Please enter the gitlab-ci token <span style="font-size: inherit;line-height: inherit;color: rgb(252, 194, 140);overflow-wrap: inherit !important;word-break: inherit !important;">for</span> <span style="font-size: inherit;line-height: inherit;color: rgb(252, 194, 140);overflow-wrap: inherit !important;word-break: inherit !important;">this</span> runner:<br>你的Gitlab admin/runners页面中的token<br>Please enter the gitlab-ci description <span style="font-size: inherit;line-height: inherit;color: rgb(252, 194, 140);overflow-wrap: inherit !important;word-break: inherit !important;">for</span> <span style="font-size: inherit;line-height: inherit;color: rgb(252, 194, 140);overflow-wrap: inherit !important;word-break: inherit !important;">this</span> runner:<br>填写描述, 无关紧要<br>Please enter the gitlab-ci tags <span style="font-size: inherit;line-height: inherit;color: rgb(252, 194, 140);overflow-wrap: inherit !important;word-break: inherit !important;">for</span> <span style="font-size: inherit;line-height: inherit;color: rgb(252, 194, 140);overflow-wrap: inherit !important;word-break: inherit !important;">this</span> runner (comma separated):<br>填写标签, 没有标签谁都可以用, 是shared-runner, 有标签需要声明才可用, 回车就对了<br>Please enter the executor: docker-ssh, ssh, docker+machine, kubernetes, docker-ssh+machine, docker, parallels, shell, virtualbox:<br>选择你的executor: Docker应该是我观察到最常用的吧<br>Please enter the <span style="font-size: inherit;line-height: inherit;color: rgb(252, 194, 140);overflow-wrap: inherit !important;word-break: inherit !important;">default</span> Docker image (e.g. ruby:<span style="font-size: inherit;line-height: inherit;color: rgb(211, 99, 99);overflow-wrap: inherit !important;word-break: inherit !important;">2.6</span>):<br>选择一个默认镜像: 例如 docker:stable-alpine<br></code></pre> </section> <p style="margin-bottom: 16px;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><span style="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;font-size: 15px;">不出意外, 就能在</span><code style="letter-spacing: 0.544px;padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab</span></code><span style="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;font-size: 15px;">中看到了</span></p> <p style="margin-bottom: 16px;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><img data-ratio="0.4365217391304348" data-type="jpeg" data-w="1150" src="/upload/5072b2c7da664fc9d1ace1fa52ccb049.jpg" style="box-sizing: content-box;border-width: initial;border-style: none;border-color: initial;background-color: rgb(255, 255, 255);width: 677px !important;visibility: visible !important;"><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-weight: 600;letter-spacing: 0.544px;">1.2 为什么使用docker作为executor</span></p> <p style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin: 5px 0px;"><span style="font-size: 15px;">参考官方文档 - executor</span></p> <ul class="list-paddingleft-2" style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;margin-left: 0px;margin-right: 0px;"> <li><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">shell executor</span></code><span style="font-size: 15px;">: 最简单的executor, 所有依赖都必须手动安装</span></p></li> <ul class="list-paddingleft-2" style="padding-left: 30px;list-style-type: square;"> <li style="font-size: 15px;"><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">不能保证每次构建都是相同的环境</span></p></li> <li style="font-size: 15px;"><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">不方便迁移</span></p></li> <li style="font-size: 15px;"><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">需要手动配置</span></p></li> </ul> <li><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">Virtual Machine Executor</span></code><span style="font-size: 15px;">: 创建虚拟机用于构建, 如果你希望在不同的操作系统上构建, 可以选择它</span></p></li> <ul class="list-paddingleft-2" style="padding-left: 30px;list-style-type: square;"> <li style="font-size: 15px;"><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">占用资源大</span></p></li> <li style="font-size: 15px;"><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">调试构建问题困难</span></p></li> <li style="font-size: 15px;"><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">迁移较不方便</span></p></li> </ul> <li><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">Docker Executor</span></code><span style="font-size: 15px;">: 最佳的选择QAQ</span></p></li> <li><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">Docker Machine</span></code><span style="font-size: 15px;">: Docker的拓展, 工作方式与Docker类似, 不过需要额外的一些安装步骤</span></p></li> </ul> <p style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin: 5px 0px;"><span style="font-size: 15px;">最后只尝试了</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">Docker</span></code><span style="font-size: 15px;">和</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">Docker + Machine</span></code><span style="font-size: 15px;">, 只是</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">Docker + Machine</span></code><span style="font-size: 15px;">的</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">runner</span></code><span style="font-size: 15px;">一直没有连接成功</span></p> <h3 style="margin-top: 24px;margin-bottom: 16px;font-weight: 600;font-size: 1.25em;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;line-height: 1.25;text-align: left;"><span style="font-size: 17px;">1.3 什么是Docker in Docker(dind)</span></h3> <p style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">参考官方文档 - dind</span></p> <p style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">使用</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">dind</span></code><span style="font-size: 15px;">的背景是: <span style="font-weight: 600;">需要在容器内执行docker命令,</span></span></p> <p style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">在</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">1.1</span></code><span style="font-size: 15px;">中注册好了一个</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">docker executor</span></code><span style="font-size: 15px;">之后, 只需要完成两个操作, 即可使用</span></p> <ul class="list-paddingleft-2" style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;"> <li><p style="text-align: left;margin-bottom: 5px;margin-top: 5px;"><span style="font-size: 15px;">在</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">gitlab-ci.yml</span></code><span style="font-size: 15px;">中添加:</span></p></li> </ul> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">imgage: docker:stable</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">service:</span><br> - docker:dind<br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;"># 测试</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">before_script:</span><br> - docker info</code></pre> </section> <ul class="list-paddingleft-2" style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;"> <li><p style="text-align: left;">确保<code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;">config.toml</code>中该<code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;">runner</code>中设置了<code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;">privileged = true</code></p></li> </ul> <h3 style="margin-top: 24px;margin-bottom: 16px;font-weight: 600;font-size: 1.25em;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;line-height: 1.25;text-align: left;"><span style="font-size: 17px;">1.4 可能遇见的问题: 拉取镜像缓慢</span></h3> <p style="margin-bottom: 16px;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><span style="font-size: 15px;">讲道理, 我没有在官方文档中找到: <span style="font-weight: 600;">当使用docker作为runner executor时, 如何设置registry-mirror</span></span></p> <p style="margin-bottom: 16px;caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;text-align: left;"><span style="font-size: 15px;">如果使用</span><code style="padding: 0.2em 0.4em;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;"><span style="font-size: 15px;">docker + machine</span></code><span style="font-size: 15px;">的话,
作者:微信小助手
<section powered-by="xiumi.us" style="margin-top: 30px;margin-bottom: 20px;white-space: normal;box-sizing: border-box;"> <section style="display: inline-block;width: 574px;vertical-align: top;box-sizing: border-box;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="padding: 5px 10px;display: inline-block;width: 574px;vertical-align: top;border-width: 3px;border-radius: 20px;border-style: solid;border-color: rgb(226, 241, 246);overflow: hidden;background-color: rgb(226, 241, 246);box-sizing: border-box;"> <section powered-by="xiumi.us" style="transform: translate3d(1px, 0px, 0px);box-sizing: border-box;"> <section style="text-align: center;font-size: 14px;color: rgb(149, 187, 202);box-sizing: border-box;"> <p style="box-sizing: border-box;">文章来源 博客园</p> </section> </section> </section> </section> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <p style="box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section powered-by="xiumi.us" style="margin-bottom: -15px;white-space: normal;text-align: left;transform: translate3d(20px, 0px, 0px);box-sizing: border-box;"> <section style="display: inline-block;width: 55px;height: 40px;vertical-align: top;overflow: hidden;box-sizing: border-box;"> <section powered-by="xiumi.us" style="text-align: center;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;"> <img data-ratio="0.696" data-w="500" src="/upload/a040d38d88cdcfaed38ea2886a5b9df0.gif" data-type="gif" style="vertical-align: middle;box-sizing: border-box;"> </section> </section> </section> </section> <section powered-by="xiumi.us" style="white-space: normal;box-sizing: border-box;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box;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;background-color: rgb(255, 255, 255);font-size: 16px;overflow-wrap: break-word !important;"> <p style="max-width: 100%;box-sizing: border-box;min-height: 1em;text-align: center;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;text-shadow: rgb(195, 134, 234) 2px 0px 7px;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">点击蓝字:波哥的IT人生,关注我们</strong></span></p> </section> </section> <section powered-by="xiumi.us" style="margin-bottom: 10px;white-space: normal;text-align: right;box-sizing: border-box;"> <section style="display: inline-block;vertical-align: middle;width: 229.594px;box-sizing: border-box;"> <section powered-by="xiumi.us" style="text-align: center;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;width: 229.594px;box-sizing: border-box;"> <img data-ratio="0.2106667" data-w="750" src="/upload/9a990984a6b8f7f7b3c167d0a48d8599.gif" width="100%" data-type="gif" style="vertical-align: middle;width: 229.594px;box-sizing: border-box;"> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: 143.5px;box-sizing: border-box;"> <section powered-by="xiumi.us" style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;"> <section style="background-color: rgb(29, 29, 29);height: 1px;box-sizing: border-box;"> <br> </section> </section> </section> </section> <section powered-by="xiumi.us"> <p style="margin: 10px auto;font-family: Verdana, Arial, Helvetica, sans-serif;font-size: 13.3333px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">Zabbix可以通过多种方式把告警信息发送到指定人,常用的有邮件,短信报警方式,但是越来越多的企业开始使用zabbix结合微信作为主要的告警方式,这样可以及时有效的把告警信息推送到接收人,方便告警的及时处理。</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">1、注册企业微信</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">注册地址: https://work.weixin.qq.com</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> <img data-ratio="1.2954209748892171" src="/upload/ca60b53442b868e3b6ea88722201b87c.png" data-type="png" data-w="677" style="border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> </p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">2、配置企业微信</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">2.1 创建部门</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.4206611570247934" src="/upload/59a2adba8ebfc8ef1bad8fd72dc5ebff.png" data-type="png" data-w="1210" style="border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> </p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> </p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">2.2 添加成员</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> <img data-ratio="0.755868544600939" src="/upload/3c0c2fb43d1972b2e4f7f725ccdff83a.png" data-type="png" data-w="852" style="border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">也可通过二维码邀请成员</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> <img data-ratio="0.6168757126567845" src="/upload/8065234104917b5b953f4449397facbe.png" data-type="png" data-w="877" style="border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> </p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">记住成员账号(后面会用到)</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="1.0421768707482992" src="/upload/35664e9f264c0f16a148cfcda7727e6.png" data-type="png" data-w="735" style="border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> </p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> </p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">3. 创建应用</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.5495118549511855" src="/upload/e5ac375ea4b0cc70113ed6e56e73bf5a.png" data-type="png" data-w="1434" style="border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">填写应用信息(应用名字和可见成员)</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.5112400290065264" src="/upload/7662ee7d237ad55f6ca5b4c9ff27e94.png" data-type="png" data-w="1379" style="border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">记住应用(AgentId、Secret后面会用到)</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.4290301862556198" src="/upload/fd30cedc287204250be58f61a5b8f5e8.png" data-type="png" data-w="1557" style="border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"> </p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">4、配置监控脚本<br>---------------------</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">准备事项:</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 微软雅黑, PTSans, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">微信企业号 <br>企业号已经被部门成员关注 <br>企业号有一个可以发送
作者:微信小助手
<section style="display: none;" data-tools="新媒体管家" data-label="powered by xmt.cn" data-mpa-powered-by="yiban.io"> <br> </section> <p style="text-align: center;"><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;">点击上方蓝色“</span><span style="font-size: 13px;font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);">程序猿DD</span><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;">”,选择“设为星标”</span><strong style="max-width: 100%;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">回复“</span><span style="max-width: 100%;font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">资源</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">”获取独家整理的学习资料!</span></span></p> <p style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img data-backh="34" data-backw="540" 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, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible !important;width: 654px !important;"></span></p> <p style="max-width: 100%;min-height: 1em;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);text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;letter-spacing: 0.544px;font-size: 13px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;color: rgb(178, 178, 178);overflow-wrap: break-word !important;box-sizing: border-box !important;">作者 | <span style="font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;max-width: 100%;caret-color: rgb(154, 154, 154);letter-spacing: 0.544px;text-align: left;text-size-adjust: auto;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">xiaojiaqi</span></span></p> <section style="text-align: left;margin-bottom: 15px;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;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;"> <span style="max-width: 100%;letter-spacing: 0.544px;font-size: 13px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;color: rgb(178, 178, 178);overflow-wrap: break-word !important;box-sizing: border-box !important;">来源 |<span style="font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;max-width: 100%;letter-spacing: 0.544px;white-space: pre-line;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <span style="font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;max-width: 100%;caret-color: rgb(154, 154, 154);letter-spacing: 0.544px;text-align: left;text-size-adjust: auto;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">github.com/xiaojiaqi/10billionhongbaos</span></span></span> </section> <section mpa-from-tpl="t" style="caret-color: rgb(51, 51, 51);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;text-size-adjust: auto;"> <section> <section> <section> <section> <section> <section> <section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);"> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>1. 前言</h1> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">前几天,偶然看到了 《扛住100亿次请求——如何做一个“有把握”的春晚红包系统”》(http://www.infoq.com/cn/presentations/how-to-build-a-spring-festival-bonus-system)一文,看完以后,感慨良多,收益很多。正所谓他山之石,可以攻玉,虽然此文发表于2015年,我看到时已经是2016年末,但是其中的思想仍然是可以为很多后端设计借鉴,。同时作为一个工程师,看完以后又会思考,学习了这样的文章以后,是否能给自己的工作带来一些实际的经验呢?所谓纸上得来终觉浅,绝知此事要躬行,能否自己实践一下100亿次红包请求呢?否则读完以后脑子里能剩下的东西 不过就是100亿 1400万QPS整流 这样的字眼,剩下的文章将展示作者是如何以此过程为目标,在本地环境的模拟了此过程。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">实现的目标: 单机支持100万连接,模拟了摇红包和发红包过程,单机峰值QPS 6万,平稳支持了业务。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin: 10px 5px;border-left-color: rgb(53, 179, 120);border-right: 0px solid rgb(53, 179, 120);color: rgb(97, 97, 97);quotes: none;background: rgb(251, 249, 253);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">注:本文以及作者所有内容,仅代表个人理解和实践,过程和微信团队没有任何关系,真正的线上系统也不同,只是从一些技术点进行了实践,请读者进行区分。因作者水平有限,有任何问题都是作者的责任,有问题请联系 ppmsn2005#gmail.com. 全文内容 扛住100亿次请求?我们来试一试</p> </blockquote> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>2. 背景知识</h1> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">QPS: Queries per second 每秒的请求数目</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">PPS:Packets per second 每秒数据包数目</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">摇红包:客户端发出一个摇红包的请求,如果系统有红包就会返回,用户获得红包</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">发红包:产生一个红包里面含有一定金额,红包指定数个用户,每个用户会收到红包信息,用户可以发送拆红包的请求,获取其中的部分金额。</p> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>3. 确定目标</h1> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">在一切系统开始以前,我们应该搞清楚我们的系统在完成以后,应该有一个什么样的负载能力。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>3.1 用户总数:</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">通过文章我们可以了解到接入服务器638台, 服务上限大概是14.3亿用户, 所以单机负载的用户上限大概是14.3亿/638台=228万用户/台。但是目前中国肯定不会有14亿用户同时在线,参考 http://qiye.qianzhan.com/show/detail/160818-b8d1c700.html 的说法,2016年Q2 微信用户大概是8亿,月活在5.4 亿左右。所以在2015年春节期间,虽然使用的用户会很多,但是同时在线肯定不到5.4亿。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>3.2. 服务器数量:</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">一共有638台服务器,按照正常运维设计,我相信所有服务器不会完全上线,会有一定的硬件冗余,来防止突发硬件故障。假设一共有600台接入服务器。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>3.3 单机需要支持的负载数:</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">每台服务器支持的用户数:5.4亿/600 = 90万。也就是平均单机支持90万用户。如果真实情况比90万更多,则模拟的情况可能会有偏差,但是我认为QPS在这个实验中更重要。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>3.4. 单机峰值QPS:</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">文章中明确表示为1400万QPS.这个数值是非常高的,但是因为有600台服务器存在,所以单机的QPS为 1400万/600= 约为2.3万QPS, 文章曾经提及系统可以支持4000万QPS,那么系统的QPS 至少要到4000万/600 = 约为 6.6万, 这个数值大约是目前的3倍,短期来看并不会被触及。但是我相信应该做过相应的压力测试。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>3.5. 发放红包:</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">文中提到系统以5万个每秒的下发速度,那么单机每秒下发速度50000/600 =83个/秒,也就是单机系统应该保证每秒以83个的速度下发即可。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">最后考虑到系统的真实性,还至少�
作者:微信小助手
<p style="text-align: center;"><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">(给</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);">ImportNew</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">加星标,提高Java技能)</span></p> <blockquote> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">转自:</span><span style="text-align: justify;">RudeCrab</span><span style="font-size: 14px;letter-spacing: 0.544px;">,</span></p> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-size: 14px;">链接:jianshu.com/p/540c1085c5de</span></p> </blockquote> <p style="text-align: left;"><span style="font-size: 15px;"></span></p> <p><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">基本介绍</span></strong></span></p> <p><br></p> <p style="text-align: left;"><span style="font-size: 15px;">单例模式(Singleton)应该是大家接触的第一个设计模式,其写法相较于其他的设计模式来说并不复杂,核心理念也非常简单:程序从始至终只有同一个该类的实例对象。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">举一个耳熟能详的例子,比如 LOL 中的大龙,一场游戏下来无论如何只有一只,所以该类只能被实例化一次。再举一个我们应用程序开发中常见的例子,Spring 框架中的 Bean 作用范围默认也是单例的。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">我相信大家都知道单例的两种最基本的写法:饿<span style="font-size: 15px;text-align: left;">汉</span>式和懒汉式。但是这两种写法都有其弊端所在,除了这两种写法外其实还有几种写法。此时耳边仿佛听到孔乙己的声音:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="88" data-source-title=""> <section class="js_blockquote_digest"> <p>“对呀对呀!......回字有四样写法,你知道么?”。 </p> <p><br></p> <p>我愈不耐烦了,努着嘴走远。孔乙己刚用指甲蘸了酒,想在柜上写字,见我毫不热心,便又叹一口气,显出极惋惜的样子........</p> </section> </blockquote> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">大家先别着急走,回字的四样写法没必要知道,单例的五种写法还是有必要晓得滴,其他的不说,至少面试的时候还能和面试官吹下是不,况且这几种写法也不是纯吊书袋,了解过后还是能帮助我们理解其设计思想滴。所以接下来咱们由浅入深,从最容易的写法开始,一步一步的带大家掌握单例模式!</span></p> <p style="text-align: left;"><br></p> <p><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">写法介绍</span></strong></span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">1. 饿汉式</span></strong></span><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">话不多说,先直接上最简单的写法,然后咱再慢慢剖析:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <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="java"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Signleton01</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 私有构造函数,防止别人实例化</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__title">Signleton01</span><span class="code-snippet__params">()</span></span>{}</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 静态属性,指向一个实例化对象</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">final</span> Signleton01 INSTANCE = <span class="code-snippet__keyword">new</span> Signleton01();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 公共方法,以便别人获取到实例化对象属性</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> Signleton01 <span class="code-snippet__title">getINSTANCE</span><span class="code-snippet__params">()</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> INSTANCE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p><br></p> <p style="text-align: left;"><strong><span style="font-size: 15px;">单例模式三元素</span></strong><br></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">一个单例模式就这样写完了,简直不要太简单。类里面一共就三个元素:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <ol class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"><p style="text-align: left;"><span style="font-size: 15px;">私有构造函数,防止别人实例化;</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-size: 15px;">静态属性,指向一个实例化对象;</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-size: 15px;">公共方法,以便别人获取到实例化对象属性。</span></p></li> </ol> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">这三个元素就是单例模式的核心,<strong>单例无论哪种写法,都离不开这三个元素</strong>。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">这三个元素也很好理解,别人想要用我这个类的实例对象就只能通过我提供的 getINSTANCE(),他想 new 也 new 不了第二个对象,自然而然就保证了该类只有唯一对象。我们可以做个试验,跑100个线程同时获取该类的实例对象,然后打印出对象的 hashCode,看看到底是不是获取的同一个对象:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">main</span>(<span class="code-snippet__params">String[] args</span>)</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">int</span> i = <span class="code-snippet__number">0</span>; i < <span class="code-snippet__number">100</span>; i++) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">new</span> Thread(() -> {</span></code><code><span class="code-snippet_outer"> System.<span class="code-snippet__keyword">out</span>.println(Signleton01.getINSTANCE().hashCode());</span></code><code><span class="code-snippet_outer"> }).start();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">结果如下:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js"><code><span class="code-snippet_outer">...</span></code><code><span class="code-snippet_outer">834649078</span></code><code><span class="code-snippet_outer">834649078</span></code><code><span class="code-snippet_outer">834649078</span></code><code><span class="code-snippet_outer">834649078</span></code><code><span class="code-snippet_outer">834649078</span></code><code><span class="code-snippet_outer">...</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">嗯,全部都是同一个对象。</span><br><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><strong><span style="font-size: 15px;">优缺点</span></strong><span style="font-size: 15px;"></span></h3> <p><span style="font-size: 15px;"><br></span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: left;"><span style="font-size: 15px;">优点:写法简单,线程安全;</span></p></li> <li><p style="text-align: left;"><span style="font-size: 15px;">缺点:消耗资源,即使程序从没有用到过该类对象,该类也会初始化一个对象出来。</span></p></li> </ul> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">所以为了解决饿汉式的这个缺点, 我们就引出了第二种写法,懒汉式!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h2 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">2. 懒汉式</span></strong></span></h2> <p><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><strong><span style="font-size: 15px;">基本写法</span></strong><span style="font-size: 15px;"></span></h3> <p><strong><span style="font-size: 15px;"><br></span></strong></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Singleton02</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 私有构造函数,防止别人实例化</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__title">Singleton02</span>(<span class="code-snippet__params"></span>)</span> {}</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 静态属性,指向一个实例化对象(注意,这里没有实例化对象哦)</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> Singleton02 INSTANCE;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 公共方法,以便别人获取到实例化对象属性</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> Singleton02 <span class="code-snippet__title">getINSTANCE</span>(<span class="code-snippet__params"></span>)</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (INSTANCE == <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer"> INSTANCE = <span class="code-snippet__keyword">new</span> Singleton02();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> INSTANCE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p><strong><span style="font-size: 15px;"></span></strong><br></p> <p style="text-align: left;"><span style="font-size: 15px;">懒汉式的和<span style="font-size: 15px;text-align: left;">饿汉</span><span style="font-size: 15px;text-align: left;">式</span>最大的区别是什么呢,就是只有在调用 getINSTANCE 的时候,才会创建实例。如果你从来没调用过,那么就不实例化对象。这个就比<span style="font-size: 15px;text-align: left;">饿汉</span><span style="font-size: 15px;text-align: left;">式</span>更加节约资源,不过这种写法并不是懒汉式的完善写法,它有一个非常大的问题,就是线程不同步!我们可以按照之前那种方式创建100个线程测试一下结果:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js"><code><span class="code-snippet_outer">...</span></code><code><span class="code-snippet_outer">1851261656</span></code><code><span class="code-snippet_outer">868907500</span></code><code><span class="code-snippet_outer">988762476</span></code><code><span class="code-snippet_outer">1031371881</span></code><code><span class="code-snippet_outer">593800070</span></code><code><span class="code-snippet_outer">...</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">可以看到这线程一同时拿,拿的都不是同一个对象,这完全就破坏了单例模式。因为很多线程在对象没有初始化前就进入到了 if (INSTANCE == null) 判断语句块里,自然而然就会 new 出不同的对象了。要解决这个线程不安全问题,就得上线程锁!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3. synchronized 写法</span></strong></span></h3> <p><br></p> <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="java"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Singleton02</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__title">Singleton02</span><span class="code-snippet__params">()</span> </span>{}</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> Singleton02 INSTANCE;</span></code><code><span class="code-snippet_outer"> </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 注意,这里静态方法加了synchronized关键字</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">synchronized</span> <span class="code-snippet__keyword">static</span> Singleton02 <span class="code-snippet__title">getINSTANCE</span><span class="code-snippet__params">()</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (INSTANCE == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer"> INSTANCE = <span class="code-snippet__keyword">new</span> Singleton02();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> INSTANCE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">当我们在静态方法加上 synchronized 关键字后,就可以保证这个方法在同一时间只会有一个线程能成功调用,也就顺理成章的解决了线程不安全问题。我们还是测试一下:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js"><code><span class="code-snippet_outer">...</span></code><code><span class="code-snippet_outer">1226880356</span></code><code><span class="code-snippet_outer">1226880356</span></code><code><span class="code-snippet_outer">1226880356</span></code><code><span class="code-snippet_outer">1226880356</span></code><code><span class="code-snippet_outer">1226880356</span></code><code><span class="code-snippet_outer">...</span></code></pre> </section> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">不管多少个线程,拿到的都是同一个对象,达到了单例的要求!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><strong><span style="font-size: 15px;">优缺点</span></strong><span style="font-size: 15px;"></span></h3> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">懒汉式连基本的线程安全都不能保证,就不做讨论了,我们这里主要说的是 synchronized 写法:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: left;"><span style="font-size: 15px;">优点:写法简单,节约资源(只有需要该对象的时候才会实例化);</span></p></li> <li><p style="text-align: left;"><span style="font-size: 15px;">缺点:耗性能。</span></p></li> </ul> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">要知道每一次调用 getINSTANCE() 方法时都会上锁,这是非常耗性能的。那么为了解决这个好性能的问题,我们又引申出接下来的一种写法。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h2 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">4. 双重检测</span></strong></span></h2> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">每一次调用 getINSTANCE() 方法都会上锁,这是完全没有必要的嘛,因为只有对象还没有实例化的时候我才需要上锁以保证线程安全。对象都实例化了,自然也不用担心后续的调用会 new 出新的对象。所以我们这个锁,可以加在 if (INSTANCE == null) 判断语句块里面:</span></p> <p style="text-align: left;"><br></p> <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="java"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Singleton03</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__title">Singleton03</span><span class="code-snippet__params">()</span> </span>{}</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> Singleton03 INSTANCE;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> Singleton03 <span class="code-snippet__title">getINSTANCE</span><span class="code-snippet__params">()</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (INSTANCE == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 只有在对象还没有实例化的时候才上锁</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">synchronized</span> (Singleton03.class) {</span></code><code><span class="code-snippet_outer"> INSTANCE = <span class="code-snippet__keyword">new</span> Singleton03();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> INSTANCE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">这样就能节约一些性能,但是这样并没有做到线程安全哦!因为很多线程进入到if (INSTANCE == null) 判断语句后,虽说是因为锁不能同时 new 对象了,但是如果锁一旦释放,那么其他线程依然会执行到 INSTANCE = new Singleton03() 语句,从而破坏了单例。所以在 synchronized 代码块内还要加一层判断:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <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="java"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Singleton03</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__title">Singleton03</span><span class="code-snippet__params">()</span> </span>{}</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 注意,使用双重检验写法要加上volatile关键字,避免指令重排(有个印象就行,这不是本文的重点)</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">volatile</span> Singleton03 INSTANCE;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> Singleton03 <span class="code-snippet__title">getINSTANCE</span><span class="code-snippet__params">()</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (INSTANCE == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 只有在对象还没有实例化的时候才上锁</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">synchronized</span> (Singleton03.class) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 额外加一层判断</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (INSTANCE == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer"> INSTANCE = <span class="code-snippet__keyword">new</span> Singleton03();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> INSTANCE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">synchronized 代码块外面一层判断,里面一层判断,就是有名的双重检测(DCL)了!里面的这一层判断加了之后呢,第一个线程的锁一旦释放也不用担心了,因为此时对象已经实例化,后续的线程也执行不了 new 语句,从而保证了线程安全!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><strong><span style="font-size: 15px;">优缺点</span></strong><span style="font-size: 15px;"></span></h3> <p><span style="font-size: 15px;"><br></span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: left;"><span style="font-size: 15px;">优点:节约资源(只有需要该对象的时候才会实例化);</span></p></li> <li><p style="text-align: left;"><span style="font-size: 15px;">缺点:写法复杂,耗性能(还是上了锁,还是耗性能)。</span></p></li> </ul> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">虽然双重校验比 synchronized 懒汉式写法减少了很多锁性能消耗,但毕竟还是上了锁,所以为了解决这个锁性能消耗问题了,又引申出下一种写法。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h2 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">5. 内部类</span></strong></span></h2> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">话不多说,直接上代码:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <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="java"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Singleton04</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 老套路,将构造函数私有化</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__title">Singleton04</span><span class="code-snippet__params">()</span> </span>{}</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 声明一个内部类,内部类里持有实例的引用</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">Inner</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">final</span> Singleton04 INSTANCE = <span class="code-snippet__keyword">new</span> Singleton04();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 公共方法</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> Singleton04 <span class="code-snippet__title">getINSTANCE</span><span class="code-snippet__params">()</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> Inner.INSTANCE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">这个写法非常像饿汉式写法,单例三元素还是那三元素,只不过多加了一个内部类,将实例引用放到内部类里而已。为啥要这样写呢?因为 JVM 保证了内部类的线程安全,即一个内部类在整个程序中不会被重复加载,并且如果你没有使用到内部类的话,是不会加载这个内部类的。这就非常巧妙的实现了线程安全以及节约资源的好处!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><strong><span style="font-size: 15px;">优缺点</span></strong><span style="font-size: 15px;"></span></h3> <p><span style="font-size: 15px;"><br></span></p> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: left;"><span style="font-size: 15px;">优点:写法简单、节约资源(只有调用了 getINSTANCE() 方法才会加载内部类,才会实例化对象)、线程安全(JVM 保证了内部类的线程安全);</span></p></li> <li><p style="text-align: left;"><span style="font-size: 15px;">缺点:会被序列化或者反射破坏单例。</span></p></li> </ul> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">这个缺点可以说是吹毛求疵,因为之前所有写法都会被序列化、反射破坏单例。虽然说是吹毛求疵,但咱们搞技术的还是得做到了解全部细节,我来演示一下怎样破坏这个单例。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><strong><span style="font-size: 15px;">通过反射破坏单例</span></strong><span style="font-size: 15px;"></span></h3> <p><br></p> <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="typescript"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__built_in">void</span> main(<span class="code-snippet__built_in">String</span>[] args) throws Exception {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 创建100个线程同时访问实例</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (int i = <span class="code-snippet__number">0</span>; i < <span class="code-snippet__number">100</span>; i++) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">new</span> Thread(() -> {</span></code><code><span class="code-snippet_outer"> System.out.println(Singleton04.getINSTANCE().hashCode());</span></code><code><span class="code-snippet_outer"> }).start();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 反射破坏单例</span></span></code><code><span class="code-snippet_outer"> Class<Singleton04> clazz = Singleton04.class;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 拿到无参构造函数并将其设置为可访问,无视private</span></span></code><code><span class="code-snippet_outer"> Constructor<Singleton04> <span class="code-snippet__keyword">constructor</span> = clazz.getDeclaredConstructor(<span class="code-snippet__params"></span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">constructor</span>.setAccessible(<span class="code-snippet__params"><span class="code-snippet__literal">true</span></span>);</span></code><code><span class="code-snippet_outer"> // 创建对象</span></code><code><span class="code-snippet_outer"> Singleton04 singleton04 = <span class="code-snippet__keyword">constructor</span>.newInstance(<span class="code-snippet__params"></span>);</span></code><code><span class="code-snippet_outer"> System.out.println(<span class="code-snippet__params">"反射:" + singleton04.hashCode()</span>);</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">运行结果如下:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js"><code><span class="code-snippet_outer">...</span></code><code><span class="code-snippet_outer">2115147268</span></code><code><span class="code-snippet_outer">2115147268</span></code><code><span class="code-snippet_outer">反射:1078694789</span></code><code><span class="code-snippet_outer">2115147268</span></code><code><span class="code-snippet_outer">2115147268</span></code><code><span class="code-snippet_outer">...</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">如果是通过正常的访问实例方法,是完全可以做到单例的要求。但是如果用反射的形式来创建一个对象,则就破坏了单例,一个程序中就出现了多个不同的实例对象。那么为了解决这个吹毛求疵的问题,聪明的前辈们想到了一个完美的写法!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h2 style="text-align: left;"><strong><span style="font-size: 15px;">枚举</span></strong><span style="font-size: 15px;"></span></h2> <p><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__comment">// 注意,这里是枚举</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">enum</span> Singleton05 {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 实例</span></span></code><code><span class="code-snippet_outer"> INSTANCE;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 公共方法</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> Singleton05 <span class="code-snippet__title">getINSTANCE</span>(<span class="code-snippet__params"></span>)</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> INSTANCE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">哎嘿,不是说所有单例都是那三元素吗,这里怎么只有两个元素呀!这是因为枚举就没有构造方法,自然而然就做到了私有化构造函数的效果,而且比私有化构造函数效果更好!因为都没有构造函数了,连序列化和反射都破坏不了这种写法的单例!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">眼见为实,我们做个试验:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <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="typescript"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__built_in">void</span> main(<span class="code-snippet__built_in">String</span>[] args) throws Exception {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 创建100个线程同时访问实例</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (int i = <span class="code-snippet__number">0</span>; i < <span class="code-snippet__number">100</span>; i++) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">new</span> Thread(() -> {</span></code><code><span class="code-snippet_outer"> System.out.println(Singleton05.getINSTANCE().hashCode());</span></code><code><span class="code-snippet_outer"> }).start();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 反射破坏单例</span></span></code><code><span class="code-snippet_outer"> Class<Singleton05> clazz = Singleton05.class;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 拿到无参构造函数并将其设置为可访问,无视private</span></span></code><code><span class="code-snippet_outer"> Constructor<Singleton05> <span class="code-snippet__keyword">constructor</span> = clazz.getDeclaredConstructor(<span class="code-snippet__params"></span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">constructor</span>.setAccessible(<span class="code-snippet__params"><span class="code-snippet__literal">true</span></span>);</span></code><code><span class="code-snippet_outer"> // 创建对象</span></code><code><span class="code-snippet_outer"> Singleton05 singleton05 = <span class="code-snippet__keyword">constructor</span>.newInstance(<span class="code-snippet__params"></span>);</span></code><code><span class="code-snippet_outer"> System.out.println(<span class="code-snippet__params">"反射:" + singleton05.hashCode()</span>);</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">运行结果如下:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <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="css"><code><span class="code-snippet_outer">...</span></code><code><span class="code-snippet_outer">422057313</span></code><code><span class="code-snippet_outer">422057313</span></code><code><span class="code-snippet_outer">422057313</span></code><code><span class="code-snippet_outer">422057313</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__selector-tag">Exception</span> <span class="code-snippet__selector-tag">in</span> <span class="code-snippet__selector-tag">thread</span> "<span class="code-snippet__selector-tag">main</span>" <span class="code-snippet__selector-tag">java</span><span class="code-snippet__selector-class">.lang</span><span class="code-snippet__selector-class">.NoSuchMethodException</span>: <span class="code-snippet__selector-tag">Singleton05</span>.<<span class="code-snippet__selector-tag">init</span>>()</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__selector-tag">at</span> <span class="code-snippet__selector-tag">java</span><span class="code-snippet__selector-class">.lang</span><span class="code-snippet__selector-class">.Class</span><span class="code-snippet__selector-class">.getConstructor0</span>(<span class="code-snippet__selector-tag">Class</span><span class="code-snippet__selector-class">.java</span><span class="code-snippet__selector-pseudo">:3082)</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__selector-tag">at</span> <span class="code-snippet__selector-tag">java</span><span class="code-snippet__selector-class">.lang</span><span class="code-snippet__selector-class">.Class</span><span class="code-snippet__selector-class">.getDeclaredConstructor</span>(<span class="code-snippet__selector-tag">Class</span><span class="code-snippet__selector-class">.java</span><span class="code-snippet__selector-pseudo">:2178)</span></span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">当运行到反射那一块代码的时候,程序直接报错,原因就是我之前所说的一样,枚举没有构造方法,你自然就无法通过反射来创建对象了!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><strong><span style="font-size: 15px;">优缺点</span></strong></h3> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">此方法乃是最完美的方法,真是佩服想出这种写法的前辈!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h1 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">总结</span></strong></span></h1> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">五个写法全部介绍完毕,每个写法都有其特点,根据自己的需求来写就好了!每种写法理解其特点后,写出来也就非常轻松。就像我一开始说的一样,理解这五种写法也不是吊书袋,每一种写法都有其背后的思考,有些写法思路真的让人叹服,至少我了解到内部类和枚举写法的时候我心里就是:我靠!这都能想出来,太牛逼了吧......</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">好的代码就是艺术作品,希望我们都能码出好的艺术出来!</span></p> <section donone="shifuMouseDownCard('shifu_c_030')" label="Copyright Reserved by PLAYHUDONG." style="text-align: start;white-space: normal;margin-top: 1em;margin-bottom: 1em;caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);border-width: 0px;border-style: initial;border-color: initial;"> <section style="margin-left: 1em;line-height: 1.4;"> <span style="padding: 3px 8px;border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;color: rgb(255, 255, 255);background-color: rgb(255, 105, 31);font-family: inherit;text-align: inherit;text-decoration: inherit;font-size: 16px;">推荐阅读</span> <span style="margin-left: 4px;padding: 3px 8px;border-top-left-radius: 1.2em;border-top-right-radius: 1.2em;border-bottom-right-radius: 1.2em;border-bottom-left-radius: 1.2em;color: rgb(255, 255, 255);line-height: 1.2;background-color: rgb(204, 204, 204);font-family: inherit;text-align: inherit;text-decoration: inherit;border-color: rgb(249, 110, 87);font-size: 12px;">点击标题可跳转</span> </section> <section style="margin-top: -11px;padding: 22px 16px 16px;border-width: 1px;border-style: solid;border-color: rgb(255, 105, 31);color: rgb(51, 51, 51);font-size: 1em;font-family: inherit;text-align: inherit;text-decoration: inherit;"> <p><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651481504&idx=1&sn=cef6a8ba51c42ffd0763ff2994c56c6c&chksm=bd2509df8a5280c970a87e6a9c9d743cc180d27787a6cd98b9845d7a1f6b452eefd995954902&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 12px;" data-linktype="2"><span style="font-size: 12px;">深入理解单例模式 ( 上 )</span></a></p> <p><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651481512&idx=2&sn=2fa55d7235cd4cde46bccd1e0329ce18&chksm=bd2509d78a5280c15000c0b265aff8ed41728cd279aa3b263dabcf8705260b84a28d3d584aa2&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 12px;" data-linktype="2"><span style="font-size: 12px;">深入理解单例模式 ( 下 )</span></a><br></p> <p><span style="font-size: 12px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651485135&idx=2&sn=b4bf292b7b0df63eb36f75c2bf234d21&chksm=bd251fb08a5296a62ef07485ba1c94d54c3bd9019bd2ff72158c7cb5c5e339183b92ae014b8e&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 12px;" data-linktype="2">Java 单例列表对比:Collections::singletonList 与 List::of 比较</a></span></p> </section> </section> <p style="caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);text-align: start;white-space: normal;"><br></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">看完本文有收获?请转发分享给更多人</span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">关注「ImportNew」,提升Java技能</strong></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.9166666666666666" data-s="300,640" data-type="jpeg" data-w="600" width="auto" src="/upload/899866149276fa5fddb73c61ae04be64.jpg" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 600px !important;"></p> <p style="text-align: right;"><span style="font-size: 14px;text-align: right;">好文章,我</span><span style="font-size: 14px;text-align: right;color: rgb(255, 41, 65);">在看</span><span style="font-size: 14px;text-align: right;">❤️</span></p>
作者:微信小助手
<section style="display: none;" data-tools="新媒体管家" data-label="powered by xmt.cn" data-mpa-powered-by="yiban.io"> <br> </section> <p style="text-align: center;"><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;">点击上方蓝色“</span><span style="font-size: 13px;font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);">程序猿DD</span><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;">”,选择“设为星标”</span><strong style="max-width: 100%;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">回复“</span><span style="max-width: 100%;font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">资源</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">”获取独家整理的学习资料!</span></span></p> <p style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img data-backh="34" data-backw="540" 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, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible !important;width: 654px !important;"></span></p> <section style="text-align: left;margin-bottom: 15px;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;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;"> <span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;">来源 |<span style="white-space: pre-line;"> https://www.cnblogs.com/littlecharacter/p/9342129.html</span></span> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);"> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>一、数据库瓶颈</h1> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">不管是IO瓶颈,还是CPU瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值。在业务Service来看就是,可用数据库连接少甚至无连接可用。接下来就可以想象了吧(并发量、吞吐量、崩溃)。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>1、IO瓶颈</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">第一种:磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的IO,降低查询速度 -> <strong style="color: rgb(53, 179, 120);">分库和垂直分表</strong>。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">第二种:网络IO瓶颈,请求的数据太多,网络带宽不够 -> <strong style="color: rgb(53, 179, 120);">分库</strong>。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>2、CPU瓶颈</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">第一种:SQL问题,如SQL中包含join,group by,order by,非索引字段条件查询等,增加CPU运算的操作 -> SQL优化,建立合适的索引,在业务Service层进行业务计算。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">第二种:单表数据量太大,查询时扫描的行太多,SQL效率低,CPU率先出现瓶颈 -> <strong style="color: rgb(53, 179, 120);">水平分表</strong>。</p> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>二、分库分表</h1> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>1、水平分库</h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4046242774566474" src="/upload/40e167489a241b93c9704a8bbf99c284.png" data-type="png" data-w="692" style="display: block;margin-right: auto;margin-left: auto;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> img </figcaption> </figure> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 概念:以 <strong style="color: rgb(53, 179, 120);">字段</strong>为依据,按照一定策略(hash、range等),将一个 <strong style="color: rgb(53, 179, 120);">库</strong>中的数据拆分到多个 <strong style="color: rgb(53, 179, 120);">库</strong>中。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 结果: </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 每个 <strong style="color: rgb(53, 179, 120);">库</strong>的 <strong style="color: rgb(53, 179, 120);">结构</strong>都一样; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 每个 <strong style="color: rgb(53, 179, 120);">库</strong>的 <strong style="color: rgb(53, 179, 120);">数据</strong>都不一样,没有交集; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 所有 <strong style="color: rgb(53, 179, 120);">库</strong>的 <strong style="color: rgb(53, 179, 120);">并集</strong>是全量数据; </section></li> </ul> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 场景:系统绝对并发量上来了,分表难以根本上解决问题,并且还没有明显的业务归属来垂直分库。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 分析:库多了,io和cpu的压力自然可以成倍缓解。 </section></li> </ol> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>2、水平分表</h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8746177370030581" src="/upload/ca20bfebd8766e4a91744e85fc04107.png" data-type="png" data-w="327" style="display: block;margin-right: auto;margin-left: auto;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> img </figcaption> </figure> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 概念:以 <strong style="color: rgb(53, 179, 120);">字段</strong>为依据,按照一定策略(hash、range等),将一个 <strong style="color: rgb(53, 179, 120);">表</strong>中的数据拆分到多个 <strong style="color: rgb(53, 179, 120);">表</strong>中。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 结果: </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 每个 <strong style="color: rgb(53, 179, 120);">表</strong>的 <strong style="color: rgb(53, 179, 120);">结构</strong>都一样; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 每个 <strong style="color: rgb(53, 179, 120);">表</strong>的 <strong style="color: rgb(53, 179, 120);">数据</strong>都不一样,没有交集; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 所有 <strong style="color: rgb(53, 179, 120);">表</strong>的 <strong style="color: rgb(53, 179, 120);">并集</strong>是全量数据; </section></li> </ul> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 场景:系统绝对并发量并没有上来,只是单表的数据量太多,影响了SQL效率,加重了CPU负担,以至于成为瓶颈。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 分析:表的数据量少了,单次SQL执行效率高,自然减轻了CPU的负担。 </section></li> </ol> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>3、垂直分库</h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4924406047516199" src="/upload/22d8e3386452c117f548a00e8a79a0a7.png" data-type="png" data-w="463" style="display: block;margin-right: auto;margin-left: auto;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> img </figcaption> </figure> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 概念:以 <strong style="color: rgb(53, 179, 120);">表</strong>为依据,按照业务归属不同,将不同的 <strong style="color: rgb(53, 179, 120);">表</strong>拆分到不同的 <strong style="color: rgb(53, 179, 120);">库</strong>中。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 结果: </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 每个 <strong style="color: rgb(53, 179, 120);">库</strong>的 <strong style="color: rgb(53, 179, 120);">结构</strong>都不一样; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 每个 <strong style="color: rgb(53, 179, 120);">库</strong>的 <strong style="color: rgb(53, 179, 120);">数据</strong>也不一样,没有交集; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 所有 <strong style="color: rgb(53, 179, 120);">库</strong>的 <strong style="color: rgb(53, 179, 120);">并集</strong>是全量数据; </section></li> </ul> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 场景:系统绝对并发量上来了,并且可以抽象出单独的业务模块。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 分析:到这一步,基本上就可以服务化了。例如,随着业务的发展一些公用的配置表、字典表等越来越多,这时可以将这些表拆到单独的库中,甚至可以服务化。再有,随着业务的发展孵化出了一套业务模式,这时可以将相关的表拆到单独的库中,甚至可以服务化。 </section></li> </ol> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>4、垂直分表</h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.37050359712230213" src="/upload/feffc7eae9ee79531c047ede9365cb98.png" data-type="png" data-w="556" style="display: block;margin-right: auto;margin-left: auto;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> img </figcaption> </figure> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 概念:以 <strong style="color: rgb(53, 179, 120);">字段</strong>为依据,按照字段的活跃性,将 <strong style="color: rgb(53, 179, 120);">表</strong>中字段拆到不同的 <strong style="color: rgb(53, 179, 120);">表</strong>(主表和扩展表)中。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 结果: </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 每个 <strong style="color: rgb(53, 179, 120);">表</strong>的 <strong style="color: rgb(53, 179, 120);">结构</strong>都不一样; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 每个 <strong style="color: rgb(53, 179, 120);">表</strong>的 <strong style="color: rgb(53, 179, 120);">数据</strong>也不一样,一般来说,每个表的 <strong style="color: rgb(53, 179, 120);">字段</strong>至少有一列交集,一般是主键,用于关联数据; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 所有 <strong style="color: rgb(53, 179, 120);">表</strong>的 <strong style="color: rgb(53, 179, 120);">并集</strong>是全量数据; </section></li> </ul> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 场景:系统绝对并发量并没有上来,表的记录并不多,但是字段多,并且热点数据和非热点数据在一起,单行数据所需的存储空间较大。以至于数据库缓存的数据行减少,查询时会去读磁盘数据产生大量的随机读IO,产生IO瓶颈。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 分析:可以用列表页和详情页来帮助理解。垂直分表的拆分原则是将热点数据(可能会冗余经常一起查询的数据)放在一起作为主表,非热点数据放在一起作为扩展表。这样更多的热点数据就能被缓存下来,进而减少了随机读IO。拆了之后,要想获得全部数据就需要关联两个表来取数据。但记住,千万别用join,因为join不仅会增加CPU负担并且会讲两个表耦合在一起(必须在一个数据库实例上)。关联数据,应该在业务Service层做文章,分别获取主表和扩展表数据然后用关联字段关联得到全部数据。 </section></li> </ol> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>三、分库分表工具</h1> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> sharding-sphere:jar,前身是sharding-jdbc; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> TDDL:jar,Taobao Distribute Data Layer; </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> Mycat:中间件。 </section></li> </ol> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">注:工具的利弊,请自行调研,官网和社区优先。</p> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>四、分库分表步骤</h1> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">根据容量(当前容量和增长量)评估分库或分表个数 -> 选key(均匀)-> 分表规则(hash或range等)-> 执行(一般双写)-> 扩容问题(尽量减少数据的移动)。</p> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>五、分库分表问题</h1> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>1、非partition key的查询问题</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">基于水平分库分表,拆分策略为常用的hash法。</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">端上</strong>除了partition key只有一个非partition key作为条件查询</p> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">映射法</strong><img data-ratio="0.5647058823529412" src="/upload/6f7b9249dce4a61c3400d043cfa887d1.png" data-type="png" data-w="510" style="display: block;margin-right: auto;margin-left: auto;"></p> </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">基因法</strong><img data-ratio="0.40668523676880225" src="/upload/3bea1cace3d6a40e812f860e75eb4b6e.png" data-type="png" data-w="718" style="display: block;margin-right: auto;margin-left: auto;"></p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">注:写入时,基因法生成user_id,如图。关于xbit基因,例如要分8张表,23=8,故x取3,即3bit基因。根据user_id查询时可直接取模路由到对应的分库或分表。根据user_name查询时,先通过user_name_code生成函数生成user_name_code再对其取模路由到对应的分库或分表。id生成常用<strong style="color: rgb(53, 179, 120);">snowflake算法</strong>。</p> </section></li> </ul> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">端上</strong>除了partition key不止一个非partition key作为条件查询</p> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">映射法</strong><img data-ratio="0.5079365079365079" src="/upload/2b8c837d4b4e049baf409e31610a94b1.png" data-type="png" data-w="567" style="display: block;margin-right: auto;margin-left: auto;"></p> </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">冗余法</strong><img data-ratio="0.5095890410958904" src="/upload/bfa2d33cb46665cad1e6640b9e0710eb.png" data-type="png" data-w="730" style="display: block;margin-right: auto;margin-left: auto;"></p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">注:按照order_id或buyer_id查询时路由到db_o_buyer库中,按照seller_id查询时路由到db_o_seller库中。感觉有点本末倒置!有其他好的办法吗?改变技术栈呢?</p> </section></li> </ul> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(53, 179, 120);">后台</strong>除了partition key还有各种非partition key组合条件查询</p> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> NoSQL法 <img data-ratio="0.9614325068870524" src="/upload/2938c7ce88dc14c05822e919cca4e83.png" data-type="png" data-w="363" style="display: block;margin-right: auto;margin-left: auto;"> </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 冗余法 <img data-ratio="0.8106235565819861" src="/upload/c792e61bb7307c664a8d1ead89ede67.png" data-type="png" data-w="433" style="display: block;margin-right: auto;margin-left: auto;"> </section></li> </ul> </ol> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>2、非partition key跨库跨表分页查询问题</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">基于水平分库分表,拆分策略为常用的hash法。</p> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">注:用**NoSQL法**解决(ES等)。</p> <h2 data-tool="mdnice编辑器" style="line-height: 32px;color: rgb(53, 179, 120);display: inline-block;border-bottom: 0px solid rgb(53, 179, 120);border-top-color: rgb(53, 179, 120);border-right-color: rgb(53, 179, 120);border-left-color: rgb(53, 179, 120);font-size: 23px;margin-top: 1em;margin-bottom: 0rem;padding-top: 0.5em;padding-bottom: 0.5em;font-weight: bold;"><span style="display: none;"></span>3、扩容问题</h2> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">基于水平分库分表,拆分策略为常用的hash法。</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">水平扩容库(升级从库法)<img data-ratio="1.5122324159021407" src="/upload/346b9ccc5c7a15c63f805ba90a2f230f.png" data-type="png" data-w="654" style="display: block;margin-right: auto;margin-left: auto;"></p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">注:扩容是成倍的。</p> </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">水平扩容表(双写迁移法)<img data-ratio="0.44550408719346046" src="/upload/7462d9548cc351cd13414fa1726b2377.png" data-type="png" data-w="734" style="display: block;margin-right: auto;margin-left: auto;">第一步:(同步双写)修改应用配置和代码,加上双写,部署;第二步:(同步双写)将老库中的老数据复制到新库中;第三步:(同步双写)以老库为准校对新库中的老数据;第四步:(同步双写)修改应用配置和代码,去掉双写,部署;</p> </section></li> </ol> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">注:<strong style="color: rgb(53, 179, 120);">双写</strong>是通用方案。</p> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>六、分库分表总结</h1> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 分库分表,首先得知道瓶颈在哪里,然后才能合理地拆分(分库还是分表?水平还是垂直?分几个?)。且不可为了分库分表而拆分。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 选key很重要,既要考虑到拆分均匀,也要考虑到非partition key的查询。 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 只要能满足需求,拆分规则越简单越好。 </section></li> </ol> <h1 data-tool="mdnice编辑器" style="font-size: 24px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(53, 179, 120);"><span style="display: none;"></span>七、分库分表示例</h1> <p data-tool="mdnice编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">示例GitHub地址:https://github.com/littlecharacter4s/study-sharding</p> </section> </section> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;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;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><br style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"></p> <section data-recommend-type="list-title" data-recommend-tid="6" 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%;padding: 14px;background: rgb(255, 255, 255);border-radius: 3px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 235);" data-mid=""> <section style="width: 100%;display: flex;justify-content: center;align-items: center;align-items: flex-end;" data-mid=""> <section data-mid="" style="height: 28px;padding: 4px 22px;font-size: 14px;font-weight: 500;color: rgb(19, 52, 86);line-height: 20px;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/sUbvrqLicbpzB81mjeBxPuxnYdalGxNnJo30L2Hq3WwGficcq8w5YJkLeXnsNHocN53k55TfN5mBpCdicGRyfDg1g/640?wx_fmt=png");background-repeat: no-repeat;background-size: 100% 100%;margin-bottom: -14px;z-index: 10;"> <p data-mid="">往期推荐</p> </section> </section> <section style="width: 100%;border-width: 1px;border-style: solid;border-color: rgb(198, 226, 255);padding: 17px 16px 9px;" data-mid=""> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247499663_2" data-recommend-article-time="1598067060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkE5PANdQJ6CXQ3t5CkHqsJlYOm6w8cKHt4tuNkDdBiavx0403nrm5ptfplicXroJjlYkNdmsPsKshBg/0?wx_fmt=jpeg" data-recommend-article-title="Apache Shiro 1.6.0 发布!修复绕过授权高危漏洞" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499663&idx=2&sn=2fd783fe23598c4eb6db7c507d7a790d&chksm=9bd35217aca4db015b42dc8325f9c889d6c41d609d1c80d2cea969c0678f250077a1d185bc4f#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499663&idx=2&sn=2fd783fe23598c4eb6db7c507d7a790d&chksm=9bd35217aca4db015b42dc8325f9c889d6c41d609d1c80d2cea969c0678f250077a1d185bc4f&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">Apache Shiro 1.6.0 发布!修复绕过授权高危漏洞</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247499663_3" data-recommend-article-time="1598067060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkE5PANdQJ6CXQ3t5CkHqsJl7z5ibvibNACHdUEREzHB1GkCzohdHKUqibfefple1ERX56bszIdD5ul8Q/0?wx_fmt=jpeg" data-recommend-article-title="ES 在数据量很大的情况下(数十亿级别)如何提高查询效率?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499663&idx=3&sn=66902c32d5a43e07b8a7c9bc145faa85&chksm=9bd35217aca4db01b6dd8dda02d96867e603397e8793076640db7113697f6ecbc06565fbf7e2#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499663&idx=3&sn=66902c32d5a43e07b8a7c9bc145faa85&chksm=9bd35217aca4db01b6dd8dda02d96867e603397e8793076640db7113697f6ecbc06565fbf7e2&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">ES 在数据量很大的情况下(数十亿级别)如何提高查询效率?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247499663_4" data-recommend-article-time="1598067060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkE5PANdQJ6CXQ3t5CkHqsJlh8VtN4IIhKbIw5RYm1OjBpFfv0MxNiaVdMvick3JkCmnmLThYFOAK1mQ/0?wx_fmt=jpeg" data-recommend-article-title="Mybatis是如何实现SQL语句复用功能的?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499663&idx=4&sn=1d86b7edbba41f66224a3059383f272f&chksm=9bd35217aca4db01eb9fe726653d743eacad1ec76ccb89303c6a7009e49ad64a14ba72ca46ef#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499663&idx=4&sn=1d86b7edbba41f66224a3059383f272f&chksm=9bd35217aca4db01eb9fe726653d743eacad1ec76ccb89303c6a7009e49ad64a14ba72ca46ef&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">Mybatis是如何实现SQL语句复用功能的?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247499595_1" data-recommend-article-time="1597969860" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkHqea8vK2BibUd5mKGLX5Vadz2ujetAOwr42bhGfMxu7NXSibJOIz0cCf6zEeFt9rsnYANWshOBbJeA/0?wx_fmt=jpeg" data-recommend-article-title="扛住100亿次请求?我们来试一试!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499595&idx=1&sn=4252289dde3fb7776ea316d10182c52b&chksm=9bd352d3aca4dbc51d5447e9af11a22b528e93391c597b8bd5594b7dd3330e7472c17e86ff7c#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499595&idx=1&sn=4252289dde3fb7776ea316d10182c52b&chksm=9bd352d3aca4dbc51d5447e9af11a22b528e93391c597b8bd5594b7dd3330e7472c17e86ff7c&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">扛住100亿次请求?我们来试一试!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247499595_3" data-recommend-article-time="1597969860" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkHqea8vK2BibUd5mKGLX5VadHwVoRTeSR4VBglicDicZs4Kh4wic4gO89y20ibS8E1zYLJqcmkF9vaiasmQ/0?wx_fmt=jpeg" data-recommend-article-title="SpringBoot + Mybatis + Druid + PageHelper 实现多数据源分页" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499595&idx=3&sn=aa6e182776de53fa686efbe628928751&chksm=9bd352d3aca4dbc574f7cc985632662c780e876317a5a4db42fdb5f06ec74989bd08366c9fee#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499595&idx=3&sn=aa6e182776de53fa686efbe628928751&chksm=9bd352d3aca4dbc574f7cc985632662c780e876317a5a4db42fdb5f06ec74989bd08366c9fee&scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;border-bottom:none !important;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">SpringBoot + Mybatis + Druid + PageHelper 实现多数据源分页</p> </section></a> </section> </section> </section> </section> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;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;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><br></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;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;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ==&mid=2247499496&idx=2&sn=f57251bcba361a0eab7dfc679baf0c88&chksm=9bd35370aca4da66ae43e2172e929acb5267738fba8c89589aa37b9b8d0c62d27154836bd50d&scene=21#wechat_redirect" textvalue="星球限时拼团优惠进行中" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;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: center;white-space: normal;background-color: rgb(255, 255, 255);"><span style="color: rgb(217, 33, 66);text-decoration: underline;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;font-size: 14px;"><strong style="color: rgb(255, 104, 39);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;"><span style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">星球限时拼团优惠进行中</span></strong></span></a></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;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;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><br></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;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;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img src="/upload/f7f418ec5d0483ff3a935bc09553a1ea.png" data-type="png" data-ratio="0.5453333333333333" data-w="750"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;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;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><br></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;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;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 14px;overflow-wrap: break-word !important;box-sizing: border-box !important;">我的星球是否适合你?</span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;font-size: 14px;overflow-wrap: break-word !important;box-sizing: border-box !important;">点击</span><strong style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(255, 104, 39);font-size: 14px;overflow-wrap: break-word !important;box-sizing: border-box !important;">阅读原文</span></strong><span style="max-width: 100%;font-size: 14px;overflow-wrap: break-word !important;box-sizing: border-box !important;">看看我们都聊过啥?</span></p>
作者:微信小助手
<p style="text-align: center;"><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">(给</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);">ImportNew</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;text-align: center;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">加星标,提高Java技能)</span></p> <blockquote> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">转自:一枝花算不算浪漫</span></p> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-size: 14px;"></span></p> </blockquote> <h3><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">前言</span></strong></span></h3> <p><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;"><br></span></strong></span></p> <p style="text-align: left;"><span style="font-size: 15px;">先抛一个问题给我聪明的读者,如果你们使用微服务 SpringCloud-Netflix 进行业务开发,那么线上注册中心肯定也是用了集群部署,问题来了:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><strong><span style="font-size: 15px;">你了解 Eureka 注册中心集群如何实现客户端请求负载及故障转移吗?</span></strong><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">可以先思考一分钟,我希望你能够带着问题来阅读此篇文章,也希望你看完文章后会有所收获!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">背景</span></strong></span></h3> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">前段时间线上 Sentry 平台报警,多个业务服务在和注册中心交互时,例如续约和注册表增量拉取等都报了 <strong>Request execution failed with message : Connection refused</strong> 的警告:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5984375" data-s="300,640" src="/upload/b689de4768102d47a21c682b2ec33926.png" data-type="png" data-w="1280" style=""></p> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">紧接着又看到 <strong>Request execution succeeded on retry #2</strong> 的日志。</span></p> <p style="text-align: left;"><br></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.32109375" data-s="300,640" src="/upload/882d3ba1fc35816ab83e49d8c9423aff.png" data-type="png" data-w="1280" style=""></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">看到这里,表明我们的服务在尝试两次重连后和注册中心交互正常了。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">一切都显得那么有惊无险,这里报 <strong>Connection refused</strong> 是注册中心网络抖动导致的,接着触发了我们服务的重连,重连成功后一切又恢复正常。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">这次的报警虽然没有对我们线上业务造成影响,并且也在第一时间恢复了正常,但作为一个爱思考的小火鸡,我很好奇这背后的一系列逻辑:<strong>Eureka 注册中心集群如何实现客户端请求负载及故障转移?</strong></span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.52265625" data-s="300,640" src="/upload/92f46489974e04f0ff117c935f4d12d.png" data-type="png" data-w="1280" style=""></p> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <h3 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">注册中心集群</span></strong></span><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">负载测试</span></strong></span></h3> <p><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;"><br></span></strong></span></p> <p style="text-align: left;"><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><span style="font-size: 15px;">线上注册中心是由三台机器组成的集群,都是4c8g的配置,业务端配置注册中心地址如下(这里的 peer 来代替具体的 IP 地址):</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="ruby"><code><span class="code-snippet_outer">eureka.client.serviceUrl.defaultZone=<span class="code-snippet__symbol">http:</span>/<span class="code-snippet__regexp">/peer1:8080/eureka</span><span class="code-snippet__regexp">/,http:/</span><span class="code-snippet__regexp">/peer2:8080/eureka</span><span class="code-snippet__regexp">/,http:/</span><span class="code-snippet__regexp">/peer3:8080/eureka</span><span class="code-snippet__regexp">/</span></span></code></pre> </section> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">我们可以写了一个 Demo 进行测试:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h4 style="text-align: left;"><strong><span style="font-size: 15px;">注册中心集群负载测试</span></strong><span style="font-size: 15px;"></span></h4> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">1. 本地通过修改 EurekaServer 服务的端口号来模拟注册中心集群部署,分别以8761和8762两个端口进行启动;</span></p> <p style="text-align: left;"><span style="font-size: 15px;">2. 启动客户端 SeviceA,配置注册中心地址为:http://localhost:8761/eureka,http://localhost:8762/eureka。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.3138888888888889" data-s="300,640" src="/upload/43abc829ebad0468bdcb311b8dc70aed.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">3. 启动SeviceA时在发送注册请求的地方打断点:AbstractJerseyEurekaHttpClient.register(),如下图所示:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.2518518518518518" data-s="300,640" src="/upload/7925390d1c8f43ea158d0ae95932c97b.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">这里看到请求注册中心时,连接的是8761这个端口的服务。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">4. 更改 ServiceA 中注册中心的配置:http://localhost:8762/eureka,http://localhost:8761/eureka<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">5.重新启动SeviceA然后查看端口,如下图所示:</span></p> <p style="text-align: left;"><br></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.25462962962962965" data-s="300,640" src="/upload/9e69851d4ee1b2d84078184ea15a6fac.png" data-type="png" data-w="1080" style=""></p> <h5 style="text-align: left;"><br></h5> <h5 style="text-align: left;"><strong><span style="font-size: 15px;">注册中心故障转移测试</span></strong></h5> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">以两个端口分别启动 EurekaServer 服务,再启动一个客户端 ServiceA。启动成功后,关闭一个8761端口对应的服务,查看此时客户端是否会自动迁移请求到8762端口对应的服务:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">1. 以8761和8762两个端口号启动 EurekaServer;<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. 启动 ServiceA,配置注册中心地址为:http://localhost:8761/eureka,http://localhost:8762/eureka;<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">3. 启动成功后,关闭8761端口的 EurekaServer<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">4. 在 EurekaClient 端发送心跳请求的地方打上断点:AbstractJerseyEurekaHttpClient.sendHeartBeat();<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">5. 查看断点处数据,第一次请求的 EurekaServer 是8761端口的服务,因为该服务已经关闭,所以返回的 response 是 null。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6111111111111112" data-s="300,640" src="/upload/43eac6d9d942bc068dd7503226244a78.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">6. 第二次会重新请求8762端口的服务,返回的 response 为状态为200,故障转移成功,如下图:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.725925925925926" data-s="300,640" src="/upload/50913841546da90f2b8ba30654460523.png" data-type="png" data-w="1080" style=""></p> <h4 style="text-align: left;"><br></h4> <h4 style="text-align: left;"><strong><span style="font-size: 15px;">思考</span></strong><span style="font-size: 15px;"></span></h4> <p><strong><span style="font-size: 15px;"><br></span></strong></p> <p style="text-align: left;"><span style="font-size: 15px;">通过这两个测试 Demo,我以为 EurekaClient 每次都会取 defaultZone 配置的第一个 host 作为请求 EurekaServer 的请求的地址,如果该节点故障时,会自动切换配置中的下一个 EurekaServer 进行重新请求。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">那么疑问来了,EurekaClient 每次请求真的是以配置的 defaultZone 配置的第一个服务节点作为请求的吗?这似乎也太弱了!!?</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">EurekaServer 集群不就成了伪集群!!?除了客户端配置的第一个节点,其它注册中心的节点都只能作为备份和故障转移来使用!!?</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">真相是这样吗?NO!我们眼见也不一定为实,源码面前毫无秘密!</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><strong><span style="font-size: 15px;">翠花,上干货!</span></strong><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">客户端请求负载原理</span></strong></span></h3> <h4 style="text-align: left;"><br></h4> <h4 style="text-align: left;"><strong><span style="font-size: 15px;">原理图解</span></strong><span style="font-size: 15px;"></span></h4> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">还是先上结论,负载原理如图所示:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.4101851851851852" data-s="300,640" src="/upload/edcff7690d5dedefa1b94b8749145656.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">这里会以 EurekaClient 端的 IP 作为随机的种子,然后随机打乱 serverList,例如我们在商品服务(192.168.10.56)中配置的注册中心集群地址为:peer1、peer2、peer3,打乱后的地址可能变成 peer3、peer2、peer1。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">用户服务(192.168.22.31)中配置的注册中心集群地址为:peer1、peer2、peer3,打乱后的地址可能变成 peer2、peer1、peer3。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">EurekaClient 每次请求 serverList 中的第一个服务,从而达到负载的目的。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h4 style="text-align: left;"><strong><span style="font-size: 15px;">代码实现</span></strong></h4> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">我们直接看最底层负载代码的实现,具体代码在<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">com.netflix.discovery.shared.resolver.ResolverUtils.randomize() 中:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;"></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.3840425531914894" data-s="300,640" src="/upload/95ce54d9b294ef827a0acea63e43e1d8.png" data-type="png" data-w="940" style=""></p> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">这里面 random 是通过我们 EurekaClient 端的 ipv4 做为随机的种子,生成一个重新排序的 serverList,也就是对应代码中的 randomList。所以每个 EurekaClient 获取到的 serverList 顺序可能不同。在使用过程中,取列表的第一个元素作为 server 端 host,从而达到负载的目的。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6768518518518518" data-s="300,640" src="/upload/de593b45a09fcd45202c0dcd3cf3f173.png" data-type="png" data-w="1080" style=""></p> <h4 style="text-align: left;"><br></h4> <h4 style="text-align: left;"><strong><span style="font-size: 15px;">思考</span></strong><span style="font-size: 15px;"></span></h4> <p><strong><span style="font-size: 15px;"><br></span></strong></p> <p style="text-align: left;"><span style="font-size: 15px;">原来代码是通过 EurekaClient 的 IP 进行负载的,所以刚才通过 Demo 程序结果就能解释的通了。因为我们做实验都是用的同一个 IP,所以每次都是会访问同一个 Server 节点。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">既然说到了负载,这里肯定会有另一个疑问:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><strong><span style="font-size: 15px;">通过 IP 进行的负载均衡,每次请求都会均匀分散到每一个 Server 节点吗?</span></strong><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">比如第一次访问 Peer1,第二次访问 Peer2,第三次访问 Peer3,第四次继续访问 Peer1 等,循环往复……</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">我们可以继续做个试验,假如我们有10000个 EurekaClient 节点,3个 EurekaServer 节点。</span><span style="font-size: 15px;">Client </span><span style="font-size: 15px;">节点的 </span><span style="font-size: 15px;">IP </span><span style="font-size: 15px;">区间为:</span><span style="font-size: 15px;">192.168.0.0 ~ 192.168.255.255</span><span style="font-size: 15px;">,这里面共覆盖6w多个 </span><span style="font-size: 15px;">IP</span><span style="font-size: 15px;">段,测试代码如下:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 模拟注册中心集群负载,验证负载散列算法</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> *</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * @author 一枝花算不算浪漫</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * @date 2020/6/21 23:36</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">class</span> <span class="code-snippet__title">EurekaClusterLoadBalanceTest</span> {</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">main</span>(<span class="code-snippet__params">String[] args</span>)</span> {</span></code><code><span class="code-snippet_outer"> testEurekaClusterBalance();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 模拟ip段测试注册中心负载集群</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">testEurekaClusterBalance</span>(<span class="code-snippet__params"></span>)</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">int</span> ipLoopSize = <span class="code-snippet__number">65000</span>;</span></code><code><span class="code-snippet_outer"> String ipFormat = <span class="code-snippet__string">"192.168.%s.%s"</span>;</span></code><code><span class="code-snippet_outer"> TreeMap<String, Integer> ipMap = Maps.newTreeMap();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">int</span> netIndex = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">int</span> lastIndex = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">int</span> i = <span class="code-snippet__number">0</span>; i < ipLoopSize; i++) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (lastIndex == <span class="code-snippet__number">256</span>) {</span></code><code><span class="code-snippet_outer"> netIndex += <span class="code-snippet__number">1</span>;</span></code><code><span class="code-snippet_outer"> lastIndex = <span class="code-snippet__number">0</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> String ip = String.format(ipFormat, netIndex, lastIndex);</span></code><code><span class="code-snippet_outer"> randomize(ip, ipMap);</span></code><code><span class="code-snippet_outer"> System.<span class="code-snippet__keyword">out</span>.println(<span class="code-snippet__string">"IP: "</span> + ip);</span></code><code><span class="code-snippet_outer"> lastIndex += <span class="code-snippet__number">1</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> printIpResult(ipMap, ipLoopSize);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 模拟指定ip地址获取对应注册中心负载</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">randomize</span>(<span class="code-snippet__params">String eurekaClientIp, TreeMap<String, Integer> ipMap</span>)</span> {</span></code><code><span class="code-snippet_outer"> List<String> eurekaServerUrlList = Lists.newArrayList();</span></code><code><span class="code-snippet_outer"> eurekaServerUrlList.<span class="code-snippet__keyword">add</span>(<span class="code-snippet__string">"http://peer1:8080/eureka/"</span>);</span></code><code><span class="code-snippet_outer"> eurekaServerUrlList.<span class="code-snippet__keyword">add</span>(<span class="code-snippet__string">"http://peer2:8080/eureka/"</span>);</span></code><code><span class="code-snippet_outer"> eurekaServerUrlList.<span class="code-snippet__keyword">add</span>(<span class="code-snippet__string">"http://peer3:8080/eureka/"</span>);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> List<String> randomList = <span class="code-snippet__keyword">new</span> ArrayList<>(eurekaServerUrlList);</span></code><code><span class="code-snippet_outer"> Random random = <span class="code-snippet__keyword">new</span> Random(eurekaClientIp.hashCode());</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">int</span> last = randomList.size() - <span class="code-snippet__number">1</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">int</span> i = <span class="code-snippet__number">0</span>; i < last; i++) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">int</span> pos = random.nextInt(randomList.size() - i);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (pos != i) {</span></code><code><span class="code-snippet_outer"> Collections.swap(randomList, i, pos);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (String eurekaHost : randomList) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">int</span> ipCount = ipMap.<span class="code-snippet__keyword">get</span>(eurekaHost) == <span class="code-snippet__literal">null</span> ? <span class="code-snippet__number">0</span> : ipMap.<span class="code-snippet__keyword">get</span>(eurekaHost);</span></code><code><span class="code-snippet_outer"> ipMap.put(eurekaHost, ipCount + <span class="code-snippet__number">1</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">printIpResult</span>(<span class="code-snippet__params">TreeMap<String, Integer> ipMap, <span class="code-snippet__keyword">int</span> totalCount</span>)</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (Map.Entry<String, Integer> entry : ipMap.entrySet()) {</span></code><code><span class="code-snippet_outer"> Integer count = entry.getValue();</span></code><code><span class="code-snippet_outer"> BigDecimal rate = <span class="code-snippet__keyword">new</span> BigDecimal(count).divide(<span class="code-snippet__keyword">new</span> BigDecimal(totalCount), <span class="code-snippet__number">2</span>, BigDecimal.ROUND_HALF_UP);</span></code><code><span class="code-snippet_outer"> System.<span class="code-snippet__keyword">out</span>.println(entry.getKey() + <span class="code-snippet__string">":"</span> + count + <span class="code-snippet__string">":"</span> + rate.multiply(<span class="code-snippet__keyword">new</span> BigDecimal(<span class="code-snippet__number">100</span>)).setScale(<span class="code-snippet__number">0</span>, BigDecimal.ROUND_HALF_UP) + <span class="code-snippet__string">"%"</span>);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">负载测试结果如下:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.18518518518518517" data-s="300,640" src="/upload/864109a29e52890ba92d4fe1d5194b9c.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">可以看到第二个机器会有50%的请求,最后一台机器只有17%的请求,负载的情况并不是很均匀,我认为通过IP负载并不是一个好的方案。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">还记得我们之前讲过Ribbon默认的轮询算法RoundRobinRule,</span><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=Mzg5ODA5NDIyNQ==&mid=2247483919&idx=1&sn=d841b134196288eb7ac8b5740825aa3e&chksm=c06687f1f7110ee7b60a1ae3e4d4b361ba75aab326260f2bee03109184f5c04ba726862748f6&scene=21#wechat_redirect" textvalue="【一起学源码-微服务】Ribbon 源码四:进一步探究Ribbon的IRule和IPing" tab="innerlink" data-linktype="2"><span style="font-size: 15px;">【一起学源码-微服务】Ribbon 源码四:进一步探究Ribbon的IRule和IPing</span></a><span style="font-size: 15px;"> 。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">这种算法就是一个很好的散列算法,可以保证每次请求都很均匀,原理如下图:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.9733201581027668" data-s="300,640" src="/upload/48b8ebbee78551eaa12edf52faa24e57.png" data-type="png" data-w="1012" style=""></p> <h3 style="text-align: left;"><span style="font-size: 15px;"><br></span></h3> <h3 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">故障转移原理</span></strong></span></h3> <p><span style="font-size: 15px;"><br></span></p> <h4 style="text-align: left;"><strong><span style="font-size: 15px;">原理图解</span></strong><span style="font-size: 15px;"></span></h4> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">还是先上结论,如下图:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.5694444444444444" data-s="300,640" src="/upload/fc55247737d02b7a8fedf19f26475c3c.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">我们的 serverList 按照 client 端的 IP 进行重排序后,每次都会请求第一个元素作为和 Server 端交互的 host,如果请求失败,会尝试请求 serverList 列表中的第二个元素继续请求,这次请求成功后,会将此次请求的 host 放到全局的一个变量中保存起来,下次 client 端再次请求 就会直接使用这个 host。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">这里最多会重试请求两次。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h4 style="text-align: left;"><strong><span style="font-size: 15px;">代码实现</span></strong><span style="font-size: 15px;"></span></h4> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">直接看底层交互的代码,位置在<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute() 中:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.6592592592592592" data-s="300,640" src="/upload/c0dd47dd6a63332e1cc1257fbb2c2cb2.png" data-type="png" data-w="1080" style=""></p> <p style="text-align: left;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: left;"><span style="font-size: 15px;">我们来分析下这个代码:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">1. 第101行,获取 client 上次成功 server 端的 host,如果有值则直接使用这个 host;</span></p> <p style="text-align: left;"><span style="font-size: 15px;">2. 第105行,getHostCandidates() 是获取 client 端配置的 serverList 数据,且通过 IP 进行重排序的列表;</span></p> <p style="text-align: left;"><span style="font-size: 15px;">3. 第114行,candidateHosts.get(endpointIdx++),初始 endpointIdx=0,获取列表中第1个元素作为 host 请求;</span></p> <p style="text-align: left;"><span style="font-size: 15px;">4. 第120行,获取返回的 response 结果。如果返回的状态码是200,则将此次请求的 host 设置到全局的 delegate 变量中;</span></p> <p style="text-align: left;"><span style="font-size: 15px;">5. 第133行,执行到这里说明第120行执行的 response 返回的状态码不是200,也就是执行失败,将全局变量 delegate 中的数据清空;</span></p> <p style="text-align: left;"><span style="font-size: 15px;">6. 再次循环第一步,此时 endpointIdx=1,获取列表中的第二个元素作为 host 请求;</span></p> <p style="text-align: left;"><span style="font-size: 15px;">7. 依次执行,第100行的循环条件 numberOfRetries=3,最多重试2次就会跳出循环。</span></p> <p style="text-align: left;"><span style="font-size: 15px;">我们还可以看123和129行,这也正是我们业务抛出来的日志信息,所有的一切都对应上了。</span></p> <p style="text-align: left;"><br></p> <h3 style="text-align: left;"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">总结</span></strong></span></h3> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">感谢你看到这里,相信你已经清楚了开头提问的问题。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">上面已经分析完了 Eureka 集群下 Client 端请求时负载均衡的选择以及集群故障时自动重试请求的实现原理。</span></p> <section donone="shifuMouseDownCard('shifu_c_030')" label="Copyright Reserved by PLAYHUDONG." style="text-align: start;white-space: normal;margin-top: 1em;margin-bottom: 1em;caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);border-width: 0px;border-style: initial;border-color: initial;"> <section style="margin-left: 1em;line-height: 1.4;"> <span style="padding: 3px 8px;border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;color: rgb(255, 255, 255);background-color: rgb(255, 105, 31);font-family: inherit;text-align: inherit;text-decoration: inherit;font-size: 16px;">推荐阅读</span> <span style="margin-left: 4px;padding: 3px 8px;border-top-left-radius: 1.2em;border-top-right-radius: 1.2em;border-bottom-right-radius: 1.2em;border-bottom-left-radius: 1.2em;color: rgb(255, 255, 255);line-height: 1.2;background-color: rgb(204, 204, 204);font-family: inherit;text-align: inherit;text-decoration: inherit;border-color: rgb(249, 110, 87);font-size: 12px;">点击标题可跳转</span> </section> <section style="margin-top: -11px;padding: 22px 16px 16px;border-width: 1px;border-style: solid;border-color: rgb(255, 105, 31);color: rgb(51, 51, 51);font-size: 1em;font-family: inherit;text-align: inherit;text-decoration: inherit;"> <p><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651488837&idx=1&sn=40a59c9ed17dbe8dff945145190e5020&chksm=bd25ee3a8a52672c164956f296a781cbf0a3f5e0445d36fa640e9366de108ddda3320bd9e030&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" style="font-family: inherit;text-align: inherit;font-size: 12px;" data-linktype="2">手写负载均衡算法</a><br></p> <p><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651486900&idx=2&sn=91ac157f9b6d2d6b565f6d83aea6ae96&chksm=bd2516cb8a529fdd40c00d4a59cc87d3c82961cbb652791cadc3e37e3393422ccf00b98feae7&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-family: inherit;text-align: inherit;font-size: 12px;" data-linktype="2">一致性 Hash 在负载均衡中的应用</a><br></p> <p><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651479286&idx=1&sn=efd88f67404d2f70eb3db0eb898207a4&chksm=bd2530898a52b99fc0b7165f66d4353def1834cbd5a94efb787b8f7d94dc03298df63fd94ba5&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="text-align: start;white-space: normal;caret-color: rgb(0, 0, 0);font-size: 12px;" data-linktype="2">使用 Eureka 实现服务注册与发现</a></p> </section> </section> <p style="caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);text-align: start;white-space: normal;"><br></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">看完本文有收获?请转发分享给更多人</span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">关注「ImportNew」,提升Java技能</strong></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.9166666666666666" data-s="300,640" data-type="jpeg" data-w="600" width="auto" src="/upload/899866149276fa5fddb73c61ae04be64.jpg" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 600px !important;"></p> <p style="text-align: right;"><span style="font-size: 14px;text-align: right;">好文章,我</span><span style="font-size: 14px;text-align: right;color: rgb(255, 41, 65);">在看</span><span style="font-size: 14px;text-align: right;">❤️</span></p>