作者:微信小助手
<section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="display: block;width: auto;vertical-align: top;font-size: 15px;line-height: 2;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <section class="mp_profile_iframe_wrp" powered-by="xiumi.us" style="box-sizing: border-box;"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzIyMTUwMDMyOQ==" data-headimg="//img.xiumi.us/xmi/ua/pZrj/i/c11e39f16bf9d10a6ad57108b216b78a-sz_19101.png" data-nickname="RancherLabs" data-signature="Rancher Labs由CloudStack之父梁胜创建。旗舰产品Rancher是一个开源的企业级Kubernetes管理平台,实现了Kubernetes集群在混合云+本地数据中心的集中部署与管理。" style="box-sizing: border-box;"></mpprofile> </section> <section style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span style="font-size: 13px;color: rgb(136, 136, 136);box-sizing: border-box;">点击上方卡片关注公众号并设为星标🌟</span></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span style="font-size: 13px;color: rgb(136, 136, 136);box-sizing: border-box;">即可及时获取K8S干货哟</span><br style="box-sizing: border-box;"></p> </section> <section style="text-align: unset;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">Kubernetes jobs主要是针对短时和批量的工作负载。它是为了结束而运行的,而不是像deployment、replicasets、replication controllers和DaemonSets等其他对象那样持续运行。<br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">本文将介绍如何创建Kubernetes jobs和cronjobs,以及一些小技巧。</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">Kubernetes Jobs会一直运行到Job中指定的任务完成。也就是说,如果pods给出退出代码0,那么Job就会退出。而在正常的Kubernetes中,无论退出代码是什么,deployment对象在终止或出现错误时都会创建新的pod,以保持deployment的理想状态。</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">在job运行过程中,如果托管pod的节点发生故障,Job pod将被自动重新安排到另一个节点。</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 33.33%;max-width: 100%;box-sizing: border-box;"> <section style="max-width: 100%;width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 100%;box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> <section style="display: inline-block;vertical-align: top;width: 33.33%;max-width: 100%;box-sizing: border-box;"> <section style="max-width: 100%;width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 100%;box-sizing: border-box;"> <section style="display: inline;max-width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="max-width: 100%;box-sizing: border-box;"> <section style="text-align: center;box-sizing: border-box;max-width: 100%;"> <section style="display: inline;max-width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;width: 30%;box-sizing: border-box;"> <img src="/upload/1dbf67d102a240a6aded61e5847d0a5f.jpg" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" data-type="jpeg" data-ratio="0.8814814814814815" data-w="1080"> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section style="display: inline-block;vertical-align: top;width: 33.33%;max-width: 100%;box-sizing: border-box;"> <section style="max-width: 100%;width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 100%;box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> <section style="text-align: unset;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="font-size: 18px;color: rgb(0, 117, 168);box-sizing: border-box;">Kubernetes Jobs用例</span></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: unset;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">对于Kubernetes Jobs最好的用例实践是:</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="text-align: unset;list-style-type: decimal;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <ol class="list-paddingleft-2" style="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><p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p></li> <li style="box-sizing: border-box;"><p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;">运维/ad-hoc任务:</strong>比如你想要运行一个脚本/代码,该脚本/代码会运行一个数据库清理活动,甚至备份一个Kubernetes集群。</p></li> </ol> </section> <section style="text-align: unset;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 33.33%;max-width: 100%;box-sizing: border-box;"> <section style="max-width: 100%;width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 100%;box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> <section style="display: inline-block;vertical-align: top;width: 33.33%;max-width: 100%;box-sizing: border-box;"> <section style="max-width: 100%;width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 100%;box-sizing: border-box;"> <section style="display: inline;max-width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="max-width: 100%;box-sizing: border-box;"> <section style="text-align: center;box-sizing: border-box;max-width: 100%;"> <section style="display: inline;max-width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;width: 30%;box-sizing: border-box;"> <img src="/upload/1dbf67d102a240a6aded61e5847d0a5f.jpg" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" data-type="jpeg" data-ratio="0.8814814814814815" data-w="1080"> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section style="display: inline-block;vertical-align: top;width: 33.33%;max-width: 100%;box-sizing: border-box;"> <section style="max-width: 100%;width: 100%;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;vertical-align: top;width: 100%;box-sizing: border-box;"> <section> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> </section> <section style="text-align: unset;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="font-size: 18px;color: rgb(0, 117, 168);box-sizing: border-box;">如何创建Kubernetes Job</span></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: unset;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;max-width: 100%;" powered-by="xiumi.us"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">在本例中,我们将使用Ubuntu 容器来运行一个带有for循环的shell脚本,并根据你传递给容器的参数来呼应消息。这个参数是一个数字,决定shell脚本循环应该运行多少次。</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">例如,如果你传递了参数100,那么shell脚本将呼应消息100次然后容器将会退出。</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">你可以访问以下链接查看Dockerfile和shell脚本:</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span style="text-decoration: underline;box-sizing: border-box;">https://github.com/devopscube/Kubernetes-jobs-example/tree/master/Docker</span></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">我们先从一个简单设置的job开始。</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span style="color: rgb(0, 117, 168);box-sizing: border-box;"><strong style="box-sizing: border-box;">Step1:</strong></span>使用自定义的Docker镜像创建一个<span style="color: rgb(0, 117, 168);background-color: rgba(0, 0, 0, 0.05);box-sizing: border-box;">job.yaml</span>文件,命令参数为100。100将会作为参数传递给docker ENTRYPOINT脚本。</p> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> <section style="text-align: unset;box-sizing: border-box;" powered-by="xiumi.us"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="properties"><code><span class="code-snippet_outer"><span class="code-snippet__attr">apiVersion</span>: <span class="code-snippet__string">batch/v1 </span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">kind</span>: <span class="code-snippet__string">Job </span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">metadata</span>: <span class="code-snippet__string"></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">name</span>: <span class="code-snippet__string">kubernetes-job-example </span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">labels</span>: <span class="code-snippet__string"></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">jobgroup</span>: <span class="code-snippet__string">jobexample </span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">spec</span>: <span class="code-snippet__string"></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">template</span>: <span class="code-snippet__string"></span></span></code><code><span class="code-snippet_outer
作者:じ☆ve不哭
> 如题,MySQL获取随机的指定条目数据,SQL应该这么实现呢? ``` SELECT * FROM wx_tuwan ORDER BY RAND(), 10 ```
作者:微信小助手
<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> </blockquote> <p style="text-align: center;"><img data-ratio="0.47275031685678076" data-type="png" data-w="789" src="/upload/a0b4acafe93878d856f2b99589f7736e.png" style="text-align: left;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;word-spacing: 0.8px;margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"><span style="font-size: 15px;text-align: left;"></span><span style="color: rgb(136, 136, 136);font-size: 12px;text-align: center;background-color: rgb(255, 255, 255);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.8px;word-spacing: 0.8px;">本文主要内容</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> <span style="color: black;background-color: rgb(255, 245, 227);letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;"></span> </figcaption> </figure> <h2 data-tool="mdnice编辑器"><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></h2> <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> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">1.1 大白话解释</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> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <p style="text-align: left;"><span style="font-size: 15px;text-align: left;">性能压测是什么:就是考察当前软件和硬件环境下,系统所能承受的最大负荷,并帮助找出系统的瓶颈所在;</span></p> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <p style="text-align: left;"><span style="font-size: 15px;text-align: left;">性能压测的目的:为了系统在线上的处理能力和稳定性维持在一个标准范围内,做到知己知彼,百战不殆。还可以发现内存泄漏、并发与同步的问题。</span></p> </section></li> </ul> <section style="text-align: left;"> <p style="text-align: left;"><br></p> </section> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">1.2 性能指标</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> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">RepsonseTime - RT:响应时间,用户从客户端发起一个请求开始计算,到客户端接收到服务端的响应结束,整个过程所耗费的时间;</span> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">Hits Per Second - HPS:用户每秒点击次数,也就是每秒向后台发送的请求次数;</span> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">QPS:系统每秒内处理查询的次数;</span> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">MaxRT:最大响应时间,指用户发出请求到服务端返回响应的最大时间;</span> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">MiniRT:最少响应时间,指用户发出请求到服务端返回响应的最少时间;</span> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">90%响应时间:将所有用户的响应时间进行升序排序,取 90 % 的位置;</span> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">性能测试关注点:</span> </section></li> <ul class="list-paddingleft-2" style="text-align: left;list-style-type: square;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">吞吐量:每秒钟系统能处理的请求数、任务数;</span> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">响应时间:服务处理一个请求或一个任务的耗时;</span> </section></li> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">错误率:一批请求中结果出过错的请求所占比例。</span> </section></li> </ul> </ul> <section style="text-align: left;"> <br> </section> <h2 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">2 Jmeter 压测工具</span></strong></span></h2> <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> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">2.1 Jmeter 工具</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> <ul data-tool="mdnice编辑器" class="list-paddingleft-2"> <li> <section> <span style="font-size: 15px;">下载和安装 Jmeter 工具</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">下载地址:</span></p> <p data-tool="mdnice编辑器" 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="javascript"><code><span class="code-snippet_outer">https:<span class="code-snippet__comment">//jmeter.apache.org/download_jmeter.cgi</span></span></code></pre> </section> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">我下载的版本是 apache-jmeter-5.3。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.7049345417925479" data-type="png" data-w="993" src="/upload/2fbfca16650f9a8929c7d90940056680.png" style="margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">运行 JMeter 程序</span> </section></li> </ul> <p data-tool="mdnice编辑器"><br></p> <p data-tool="mdnice编辑器"><span style="font-size: 15px;">打开批处理文件:\apache-jmeter-5.3\bin\jmeter.bat。如下图所示:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.5740740740740741" data-type="png" data-w="1080" src="/upload/552fedc245f8bea48b4f9a551d251c74.png" style="margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">添加线程组,如下图所示:</span> </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.6574257425742575" data-type="png" data-w="505" src="/upload/bb9819154a769c920546a42fed0f7b6.png" style="margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 505px !important;visibility: visible !important;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 添加线程组 </figcaption> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">1s 内启动 200 个线程,循环次数 100 次。2 万个请求。如下图所示:</span> </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.9870848708487084" data-type="png" data-w="542" src="/upload/1f9aa18b8e12904eb7c4e00709627f0d.png" style="margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 542px !important;visibility: visible !important;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">测试 HTTP 请求,如下图所示:</span> </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.9319213313161876" data-type="png" data-w="661" src="/upload/40ba8726f0a0331fede6a90cb1d823f5.png" style="margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 661px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">配置要测试的协议、服务器地址、端口号。配置信息如下:</span></p> <p data-tool="mdnice编辑器" 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="css"><code><span class="code-snippet_outer">协议:使用 <span class="code-snippet__selector-tag">http</span> 协议。</span></code><code><span class="code-snippet_outer">服务器名称或 <span class="code-snippet__selector-tag">IP</span>: <span class="code-snippet__selector-tag">www</span><span class="code-snippet__selector-class">.baidu</span><span class="code-snippet__selector-class">.com</span> (只是为了演示)。</span></code><code><span class="code-snippet_outer">端口号:80 端口。</span></code></pre> </section> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"></span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">如下图所示:</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.4291433146517214" data-type="png" data-w="1249" src="/upload/2209a9459f79eaa22069e3ef70d9a11f.png" style="text-align: left;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2"> <li> <section> <span style="font-size: 15px;">添加查看结果树、汇总报告和聚合报告。如下图所示:</span> </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.9244505494505495" data-type="png" data-w="728" src="/upload/f91d433e1a9378e34bb2dfd72c94669a.png" style="margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <p style="text-align: left;"><span style="font-size: 15px;text-align: left;">开始压力测试。</span></p> <p style="text-align: left;"><br></p> </section></li> </ul> <p><span style="font-size: 15px;">点击播放按钮就开始启动了。</span><span style="font-size: 15px;">注意启动之前需要先设置线程组的参数配置和 HTTP 请求的配置。</span><span style="font-size: 15px;">如下图所示:</span><br></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.553409090909091" data-type="png" data-w="880" src="/upload/7b04570f0ee5016d3ac3df444168cd60.png" style="margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">查看每个请求结果,如下图所示:</span> </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.8220064724919094" data-type="png" data-w="927" src="/upload/9e5b5d6475bd2f7768f180c363afec48.png" style="margin: 20px auto;border-radius: 3px;display: block;object-fit: contain;box-shadow: rgb(210, 210, 210) 0em 0em 0.5em 0px;box-sizing: border-box !important;width: 677px !important;visibility: visible !important;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <p style="text-align: left;"><span style="font-size: 15px;text-align: left;">查看汇总报告。</span></p> </section></li> </ul> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;text-align: left;">主要关心平均值和吞吐量。200 个线程,每个线程调用 100 次,总共 2 万 次,可以看到下图中表格中的样本列也是 2 万,请求所耗费的时间是 151 ms,吞吐量是 880 个请求每秒。如下图所示:</span></p> <p style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.30758426966292135" data-type="png" data-w="1424" src="/upload/fedf5ec15938a2cf043bb2452ad3c7e4.png" style="text-align: left;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">查看聚合报告。</span> </section></li> </ul> <section style="text-align: left;"> <br> </section> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">主要看中位数和 90% 百分位,</span><span style="font-size: 15px;">中位数</span><span style="font-size: 15px;">是 59 ms,说明大部分请求的响应时间是 59 ms。</span><span style="font-size: 15px;">90 % 的请求</span><span style="font-size: 15px;"> 都是在 271 ms 以内响应完成的。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">异常 0.41% 说明 2 万 个请求中有 82 个请求异常(20000 * 0.0041 = 82 )。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">吞吐量 880.2/sec 说明百度这个网站每秒能处理 880 个请求,性能一般(可能跟本地机器性能有关)。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">如下图所示:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.3319838056680162" data-type="png" data-w="988" src="/upload/6968b11e14cb88707422d063312d1fb3.png" style="text-align: left;"> </figure> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"> <section style="text-align: left;"> <span style="font-size: 15px;text-align: left;">查看汇总图。</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">查看汇总图时,需要先勾选想要查看的信息,如下图所示:</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"></figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.5723684210526315" data-type="png" data-w="1216" src="/upload/aaad18189a2b9a537bbf1952a3f52ad9.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"></figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">然后查看图形汇总:</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.37012369172216936" data-type="png" data-w="2102" src="/upload/e93c2691a3651e54ec083db1aa63f829.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"></figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">可以看到勾选的几列在图表中是用不同颜色表示的,比如绿色的柱状条就是 90 % 百分位。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">我们来测试下 PassJava(佳必过)的管理后台的性能,吞吐量接近 2000/s。如下图所示:</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.33866666666666667" data-type="png" data-w="1125" src="/upload/308ef18cbdd8a52a1bd3d83bf7908139.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"></figure> <h2 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3 性能监控之 jconsole</span></strong></span></h2> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">jconsole 和 jvisualvm 是 Java JDK 的两个小工具,用来监控内存泄漏、跟踪垃圾回收、执行时的内存情况、对 CPU 进行分析、线程的分析。都可以通过命令行启动,而且可以监控本地和远程应用。而 jvisualvm 是升级版的 jconsole。我们先来看下 jconsole 的使用。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">首先用 cmd 命令行的方式启动 jconsole。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3.1 启动 jconsole</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> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.6402753872633391" data-type="png" data-w="1162" src="/upload/380f08de4ff84d9811bc0410a1d2b7b0.png"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 命令行启动 jconsole </figcaption> </figure> <h3 data-tool="mdnice编辑器"><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></h3> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3.2 选择监控哪个应用</span></strong></span></h3> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">然后选择 passjava 项目的 question 服务。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.6926406926406926" data-type="png" data-w="693" src="/upload/31391ebd9380ff854c1cf02332c20b23.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 选择 passjava-question 微服务 </figcaption> </figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">对应的就是下面这个微服务:passjava-question。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.5464362850971922" data-type="png" data-w="463" src="/upload/610179db2faf2874846b855b842e61cc.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 对应 passjava-question 微服务 </figcaption> </figure> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3.3 概览</span></strong></span></h3> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">从监控界面上有 6 个菜单,首先看到的是概览功能,上面有堆内存使用量、线程数、类的使用情况、CPU 占用率,都是用趋势图来表示的,能很方便的看出当前性能的概览。注意:这些监控都是实时的。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.8386004514672686" data-type="png" data-w="886" src="/upload/fa47801892977b58d73666698adf9184.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 概览 </figcaption> </figure> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3.4 内存</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 data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">下面是内存的使用情况,可以从下图中看到有个下拉框,里面可以选择不同的内存维度,然后下面的图标和柱状图也会跟着选择的维度而展示不同。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.831081081081081" data-type="png" data-w="888" src="/upload/122dfcc78acfa6009862360bb0c81958.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"></figure> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3.5 线程</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 data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">下面是线程的使用情况,可以看到线程峰值和活动线程的总数量,目前看到的峰值是59,活动线程数是 57。下半部分可以看到具体是哪些线程,以及线程的堆栈信息,非常详细。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.8386004514672686" data-type="png" data-w="886" src="/upload/2be4697fbb726a5105b0d2b31a23ea9e.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 线程使用情况 </figcaption> </figure> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3.6 类</span></strong></span></h3> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">下面是类的加载和卸载情况,已加载类总数是 10679,而已卸载的类是 1 个,所以当前已加装当前类的总数是 10679 - 1 = 10678 个。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.8386004514672686" data-type="png" data-w="886" src="/upload/7ecc813600e18938e68b1cd7ae2c2ca7.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> 类的加载和卸载情况 </figcaption> </figure> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3.7 VM 概要</span></strong></span></h3> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br></span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">我们再来看下 VM(虚拟机)的情况。如下图所示,</span><span style="font-size: 15px;">可以看到虚拟机情况,线程、类、堆的概要信息,以及 VM 的参数,是不是很方便呀~</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img data-ratio="0.8318181818181818" data-type="png" data-w="880" src="/upload/842cd5040c8b76179fb110ad235799cd.png" style="text-align: left;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.8px;text-align: left;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;"> VM 概要 </figcaption> </figure> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">3.8 MBean 信息</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 data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;">接下来我们来看下 MBean 信息。对于 MBean,可能很多同学不知道是啥,下面做个解释:</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;text-align: left;"><br>
作者:微信小助手
<section style="color: rgb(63, 63, 63);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 14px;white-space: normal;box-sizing: border-box;text-align: left;"> <img data-ratio="0.66640625" src="/upload/3685cd22093e6f5e1c597528d9ed9551.jpg" data-type="jpeg" data-w="1280" style="width: 1255.33px;border-radius: 4px;margin-bottom: 25px;"> </section> <section style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 14px;white-space: normal;box-sizing: border-box;color: rgb(145, 145, 145);text-align: left;line-height: 1em;margin-top: 13px;padding-left: 14px;"> 作者 | 李立坤 </section> <section style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;white-space: normal;box-sizing: border-box;font-size: 15px;line-height: 27px;color: rgb(89, 89, 89);background-color: rgb(239, 239, 239);padding: 19px;margin-top: 40px;margin-right: 8px;margin-left: 8px;"> 当项目中在使用到诸如 Elasticsearch 的中间件时,客户端对不同数据模型的 CRUD 操作存在着大量模版式的冗余代码,每次有新的业务数据需要 Elasticsearch 的管理时都会重写类似的 CRUD 逻辑,这些 CRUD 代码除了数据模型不同,通用功能的代码逻辑几乎一样。显然,在这种情况下,我们完全可以抽取出通用功能的代码,将其定义成一个模版。当接入具体的业务数据时,只需要进行模版实例化的代码书写,把因业务不同的数据模型嵌入到模版中,从而避免重复书写功能相同的代码,最终达到提高开发效率,降低开发成本的目的。 </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">在实际的项目开发中,如何解决模板式的冗余代码?</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">首先,考虑到 Java 语言以及 ElasticSerarch 在项目开发中的普及性,我选择基于 Java 语言使用 Elasticsearch 的技术场景来澄清以及解决模板式的代码冗余问题。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">其次,为了使得问题的澄清和解决更具象化,我以简单的用户信息和订单信息为例,来阐述澄清和解决问题的具体过程。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">那么,我们先定义一下简单用户信息和订单信息的数据模型:</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__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__keyword">public</span> <span class="code-snippet__keyword">class</span> UserInfo {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__built_in">String</span> id; <span class="code-snippet__comment">// ID</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__built_in">String</span> nickName; <span class="code-snippet__comment">// 昵称</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> Integer age; <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__built_in">String</span> introduction; <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__built_in">String</span> signature; <span class="code-snippet__comment">// 签名</span></span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="typescript"><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__meta">@Data</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">class</span> OrderInfo {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__built_in">String</span> id; </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__built_in">String</span> productId; <span class="code-snippet__comment">// 产品 ID</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> Integer productNum; <span class="code-snippet__comment">// 产品数据量</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> Integer status; <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__built_in">String</span> remark; <span class="code-snippet__comment">// 备注</span></span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;white-space: normal;box-sizing: border-box;font-size: 20px;color: rgb(0, 179, 139);text-align: left;line-height: 35px;margin-top: 40px;margin-right: 8px;margin-left: 8px;background-image: url("https://mmbiz.qpic.cn/mmbiz_jpg/FE4VibF0SjfOUvRY5VTGcXkXOh3freSjjwWGib7Ooupz0PZ9GibMlS5YJfWSWCIrMDKFu7cWxbafx0BpaNKm4EN5g/640?wx_fmt=jpeg");background-position: left 28px;background-size: 100% 6px;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;"> <span style="display: block;font-size: 32px;margin-bottom: 10px;padding-left: 22px;">1</span>什么是模板式的冗余代码? </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">接下来,我们澄清一下模版式的冗余代码问题。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">当用户信息和订单信息接受 Elasticsearch 的管理时,直接使用 Elasticsearch 客户端 API 创建索引的代码如下:</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__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * ES 创建用户信息文档。</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> ServiceResponse<<span class="code-snippet__built_in">Boolean</span>> create(UserInfo userInfo) {</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__built_in">String</span> userInfoId = userInfo.getId();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (StringUtils.isEmpty(userInfoId)) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ServiceResponse.FAIL_RESPONSE;</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"> IndexRequest indexRequest = <span class="code-snippet__keyword">new</span> IndexRequest(<span class="code-snippet__string">"user_info_index"</span>, <span class="code-snippet__string">"user_info_type"</span>, userInfoId);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__built_in">String</span> documentData = <span class="code-snippet__built_in">JSON</span>.toJSONString(userInfo);</span></code><code><span class="code-snippet_outer"> indexRequest.source(documentData, XContentType.JSON);</span></code><code><span class="code-snippet_outer"> indexRequest.opType(DocWriteRequest.OpType.INDEX);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 调用客户端 API。</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer"> InitESRestClient.getClient().index(indexRequest, RequestOptions.DEFAULT);</span></code><code><span class="code-snippet_outer"> } <span class="code-snippet__keyword">catch</span> (Exception e) {</span></code><code><span class="code-snippet_outer"> log.error(<span class="code-snippet__string">"error when save document:{}."</span>, <span class="code-snippet__built_in">JSON</span>.toJSONString(userInfo), e);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ServiceResponse.FAIL_RESPONSE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ServiceResponse.SUCCESS_RESPONSE;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code></pre> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="typescript"><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"> * ES 创建订单信息文档。</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> ServiceResponse<<span class="code-snippet__built_in">Boolean</span>> create(OrderInfo orderInfo) {</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__built_in">String</span> orderInfoId = orderInfo.getId();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (StringUtils.isEmpty(orderInfoId)) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ServiceResponse.FAIL_RESPONSE;</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"> IndexRequest indexRequest = <span class="code-snippet__keyword">new</span> IndexRequest(<span class="code-snippet__string">"order_info_index"</span>, <span class="code-snippet__string">"order_info_type"</span>, orderInfoId);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__built_in">String</span> documentData = <span class="code-snippet__built_in">JSON</span>.toJSONString(orderInfo);</span></code><code><span class="code-snippet_outer"> indexRequest.source(documentData, XContentType.JSON);</span></code><code><span class="code-snippet_outer"> indexRequest.opType(DocWriteRequest.OpType.INDEX);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 调用客户端 API。</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer"> InitESRestClient.getClient().index(indexRequest, RequestOptions.DEFAULT);</span></code><code><span class="code-snippet_outer"> } <span class="code-snippet__keyword">catch</span> (Exception e) {</span></code><code><span class="code-snippet_outer"> log.error(<span class="code-snippet__string">"error when save document:{}."</span>, <span class="code-snippet__built_in">JSON</span>.toJSONString(orderInfo), e);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ServiceResponse.FAIL_RESPONSE;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> ServiceResponse.SUCCESS_RESPONSE;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code></pre> </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">为了让大家更清晰地关注到代码中的重点,这里说明一下代码上的约定:</p> <ol class="list-paddingleft-2" style="list-style-type: decimal;"> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">ServiceResponse 是一个通用的业务对象,用来表达业务逻辑执行成功或失败的信息;</p></li> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">InitESRestClient.getClient() 用来获取默认的 Elasticsearch 集群客户端;</p></li> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">其他未特别说明的都是标准的 Java 语言和 Elasticsearch 客户端 API。</p></li> </ol> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">从上面的代码我们可以看出,无论对于用户信息的索引创建还是订单信息的索引创建,我们无可避免地要写参数检查、创建索引请求、调用客户端 API 的相同逻辑。这些逻辑的代码看着似乎都是不一样的,但整体的逻辑都是相同的,就像是一个执行流程的模板,只是模板实例化时传递的参数不一样而已。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">从代码冗余的角度讲,我们完全没有必要,对用户信息和订单信息索引创建都写一份逻辑相似的代码,即使他们看上去并不是一摸一样。像上面这样,看上去并不是一摸一样的代码,但是存在着一样的处理逻辑,使用着相同形式的代码,我们就叫做模板式的冗余代码。</p> <section style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;white-space: normal;box-sizing: border-box;font-size: 20px;color: rgb(0, 179, 139);text-align: left;line-height: 35px;margin-top: 40px;margin-right: 8px;margin-left: 8px;background-image: url("https://mmbiz.qpic.cn/mmbiz_jpg/FE4VibF0SjfOUvRY5VTGcXkXOh3freSjjwWGib7Ooupz0PZ9GibMlS5YJfWSWCIrMDKFu7cWxbafx0BpaNKm4EN5g/640?wx_fmt=jpeg");background-position: left 28px;background-size: 100% 6px;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;"> <span style="display: block;font-size: 32px;margin-bottom: 10px;padding-left: 22px;">2</span>定义模板 </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">从用户信息与订单信息的索引创建过程中,我们发现模板式的冗余代码主要由两部分构成。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">一个是不变的部分,即对任意的数据模型,这些部分的处理都是一样的,主要有以下几点:</p> <ol class="list-paddingleft-2" style="list-style-type: decimal;"> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">对数据中的唯一标识做合法性检查,即通用参数的检查逻辑;</p></li> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">构建 Elasticsearch API 的 IndexRequest,即构建索引创建请求;</p></li> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">获取 Elasticsearch 的集群客户端发送索引创建请求并进行异常处理,即通用的发送请求并进行异常处理的逻辑。</p></li> </ol> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">另一个是变化的部分,这些部分都是根据不同的数据模型而变化的,主要有以下几点:</p> <ol class="list-paddingleft-2" style="list-style-type: decimal;"> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">传入参数不同,用户信息传入的是 UserInfo,而订单信息是 OrderInfo;</p></li> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">数据配置不同,用户信息进入的 user_info_index 索引的 user_info_type,而订单信息进入的是 order_info_index 索引的 order_info_type;</p></li> <li><p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">集群选择可能不同,这里用户信息和订单信息都采用的默认的集群,但实际项目开发中可能用户信息在集群 1,订单信息在集群 2。</p></li> </ol> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">所以,我们想要避免模板式的冗余代码,那么必然要将上述变化的部分和不变的部分定义在一个模板里,这样相似的代码只会存在于模板内。然而,上述不变的部分我们可以直接定义在模板内,而变化的部分我们怎么在模板内抽象表达呢?下面我就基于 Java 语言以 Elasticsearch 索引创建的过程为例具体定义一个包含上述不变和变化部分的模板。</p> <section style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;white-space: normal;box-sizing: border-box;margin-top: 40px;margin-right: 8px;margin-left: 8px;font-size: 16px;color: rgb(25, 182, 215);text-align: left;"> <span style="height: 19px;display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_jpg/FE4VibF0SjfOUvRY5VTGcXkXOh3freSjj1iarYpIToT2GpZN3DZqWQMQ64gciaf6AzInsqzFOUicjia2BgDyjIJlmDw/640?wx_fmt=jpeg");background-position: left top;background-size: 100%;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;"></span>方法定义 </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">首先我们在模板中定义创建索引的方法,在 Java 语言中想要实现上述模板的功能,最好的语言组件自然是 Java 中的抽象类了,同时这里为了在模板中描述方法中变化的参数,即 UserInfo、OrderInfo 等数据模型,我们必然要使用到 Java 中的泛型参数在抽象类对数据模型进行抽象统一。所以我们初步定义的包含创建索引功能的抽象类就是下面这个样子了:</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="cpp"><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"> * DOC 泛型参数的定义是对模板中变化部分的抽象,</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 对接受 Elasticsearch 管理的数据进行统一表示。</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__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">AbstractBaseESServiceImpl</span><DOC> {</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"> */</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">public</span> ServiceResponse<Boolean> create(DOC doc) {}</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">上述代码基于 Java 中的抽象类和泛型参数对模板做了一个初步的定义,该模板暂时只包含创建索引的功能,但是具体的创建索引的方法并没有实现,为什么呢?因为我们要想实现上述创建索引的参数检查,创建索引请求,发送请求的逻辑,我们必须先知道数据模型中那些通用字段需要做参数检查,该数据要去那个索引和那个类型,该数据要进入那个集群这些信息,显然我们仅仅根据 Doc 类型的 doc 参数是无法获取这些信息的。<br></p> <section style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;white-space: normal;box-sizing: border-box;margin-top: 40px;margin-right: 8px;margin-left: 8px;font-size: 16px;color: rgb(25, 182, 215);text-align: left;"> <span style="height: 19px;display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_jpg/FE4VibF0SjfOUvRY5VTGcXkXOh3freSjj1iarYpIToT2GpZN3DZqWQMQ64gciaf6AzInsqzFOUicjia2BgDyjIJlmDw/640?wx_fmt=jpeg");background-position: left top;background-size: 100%;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;"></span>元数据初始化 </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">那么如何获取上述所述的信息呢?这时我们就可以利用 Java 语言强大的元语言编程能力,在对象初始化的时候,获取到泛型参数实例化后实际数据模型的元数据。当有了这些准备好的元数据后,就可以在方法运行时,根据实际参数和元数据获取到相关的信息从而完成创建索引的逻辑。所以,接下来我们要做的就是如何准备元数据可以获取到上述那些通用字段需要做参数检查,数据要进入那个索引和那个类型的信息。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">在 Java 语言中,元数据信息都是存放在 Class 类型的对象中,所以我们可以在对象初始化的时候先获取到上述 DOC 泛型参数所表示的数据模型的 Class 对象,代码如下:</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"> * DOC 数据模型的 Class 对象。</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> Class<DOC> docClass;</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"> */</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__title">AbstractBaseESServiceImpl</span>(<span class="code-snippet__params"></span>)</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">this</span>.docClass = <span class="code-snippet__keyword">this</span>.getDocClass();</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__comment"> * 获取 DOC 数据模型的元数据。</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 这里主要是获取子类泛型参数实例化后实际数据类型的 Class 对象。</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> Class<DOC> <span class="code-snippet__title">getDocClass</span>(<span class="code-snippet__params"></span>)</span> {</span></code><code><span class="code-snippet_outer"> Type genericSuperclass = <span class="code-snippet__keyword">this</span>.getClass().getGenericSuperclass();</span></code><code><span class="code-snippet_outer"> Type docType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[<span class="code-snippet__number">0</span>];</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (!(docType instanceof ParameterizedType)) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> (Class<DOC>) docType; </span></code><code><span class="code-snippet_outer"> } </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> (Class<DOC>)((ParameterizedType)docType).getRawType();</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">上述代码都是基于 Java 语言反射机制的实现,具体 API 这里就不细说了。大概思路就是在对象初始化时,使获取到元数据,即在模板中获取到实际数据类型的元数据,为后面获取具体变化的部分信息做准备。变化部分的信息主要包括两方面,一是哪些通用字段需要做参数校验,二是数据进入哪个 Elasticsearch 索引和类型。<br></p> <section style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;white-space: normal;box-sizing: border-box;font-size: 16px;text-align: left;margin-top: 30px;margin-left: 8px;color: rgb(0, 179, 138);"> <span style="display: inline-block;width: 15px;height: 15px;background-image: url("https://mmbiz.qpic.cn/mmbiz_jpg/FE4VibF0SjfOUvRY5VTGcXkXOh3freSjj3NGrFKia2Urd7uFtKVRqCrdHmPZrPo9TK61Gvdf1DDFFVHC7Zqmc5Vw/640?wx_fmt=jpeg");background-position: center center;background-size: 100% 100%;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;margin-right: 10px;"></span> 通用字段元数据的准备 </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">这里我们先解决获取通用字段元数据信息的问题,从而为通用字段的参数校验做准备。Java 语言中,我们可以通过注解,在各个组件中添加一些标记信息。自然而然地,我们可以自定义注解在实际数据模型定义中标记那些通用字段,根据该标记信息我们可以获取到需要做参数校验地通用字段的元数据信息。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">例如上述我们要求任何接受 Elastic 管理的数据都要定义唯一标识,且要求唯一标识是不为空的字符串类型。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">如何实现这个需求呢?这时候我们就可发挥 Java 中注解的强大功能了,比如我们自定义一个 DocID 的注解,该注解只能加在 Java 类的字段上,而且必须是不为空的字符串类型。</p> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">那么,我们先自定义一个 DocID 的注解,代码如下:</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 class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 定义 DOC 数据模型中的唯一标识字段。</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 该注解用于在实际的数据模型中标记 Elasticsearch 文档的唯一标识。</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">Target</span>({<span class="code-snippet__selector-tag">ElementType</span><span class="code-snippet__selector-class">.FIELD</span>})</span></code><code><span class="code-snippet_outer">@<span class="code-snippet__keyword">Retention</span>(<span class="code-snippet__keyword">RetentionPolicy</span>.<span class="code-snippet__keyword">RUNTIME</span>)</span></code><code><span class="code-snippet_outer">public @interface DocID{}</span></code></pre> </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;padding-top: 23px;padding-right: 8px;padding-left: 8px;color: rgb(74, 74, 74);">显然,该注解的处理逻辑必然是要在模板对象即上述抽象类对象初始化时存在,也就是说,我们要在上述抽象类初始化时,根据数据模型的元数据获取到标记了该注解的字段的元数据,从而为后面通用参数的校验做准备,这段逻辑具体的代码如下:<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="kotlin"><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__keyword">protected</span> <span class="code-snippet__keyword">final</span> Field idField;</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"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> AbstractBaseESServiceImpl() {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">this</span>.docClass = <span class="code-snippet__keyword">this</span>.getDocClass();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">this</span>.idField = <span class="code-snippet__keyword">this</span>.getIDField();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">this</span>.idField.setAccessible(<span class="code-snippet__literal">true</span>);</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__comment"> * 获取文档的 ID 字段元数据。</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 要求用户在使用时,必须通过自定义注解 DocID,告诉我们实际数据模型</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 哪个字段是 ID 字段,从而获取到 ID 字段的具体值,用于通用参数的逻辑检查以及和唯一标识</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__keyword">private</span> Field getIDField() {</span></code><code><span class="code-snippet_outer"> Field[] declaredFields = <span class="code-snippet__keyword">this</span>.docClass.getDeclaredFields();</span></code><code><span class="code-snippet_outer"> Field idField = <span class="code-snippet__literal">null</span>;</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">for</span> (Field declaredField : declaredFields) {</span></code><code><span class="code-snippet_outer"> DocID docID =declaredField.getAnnotation(DocID.<span class="code-snippet__keyword">class</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (<span class="code-snippet__literal">null</span> == docID) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">continue</span>;</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> idField = declaredField;</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 class="code-snippet__comment">// 要求数据模型中必须定义 ID 字段。</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (<span class="code-snippet__literal">null</span> == idField) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">throw</span> new DocIDUndefineException();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 要求 ID 字段的类型为字符串。</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (idField.getType() != String.<span class="code-snippet__keyword">class</span>) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">throw</span> new DocIDNotStringException();</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> idField;</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;box-sizing: border-box;font-size: 16px;white-space: pre-line;line-height: 27px;pa
作者:微信小助手
<p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;color: rgb(62, 62, 62);font-size: 15px;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;" data-mpa-powered-by="yiban.io"><span style="max-width: 100%;font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !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;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></span></p> <pre style="letter-spacing: 0.544px;color: rgb(62, 62, 62);text-align: center;background-color: rgb(255, 255, 255);font-size: 15px;"><p style="letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-size-adjust: auto;word-spacing: 2px;"><span style="letter-spacing: 0.544px;color: rgb(136, 136, 136);font-size: 14px;">点击蓝色“</span><span style="letter-spacing: 0.544px;font-size: 14px;color: rgb(0, 128, 255);">架构文摘</span><span style="letter-spacing: 0.544px;color: rgb(136, 136, 136);font-size: 14px;">”关注我哟</span></p><p style="margin-bottom: 10px;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-size-adjust: auto;word-spacing: 2px;"><span style="font-size: 14px;color: rgb(136, 136, 136);">加个“</span><span style="color: rgb(0, 128, 255);font-size: 14px;">星标</span><span style="font-size: 14px;color: rgb(136, 136, 136);">”,每天上午 09:25,干货推送!</span></p><p style="letter-spacing: 0.544px;white-space: normal;font-size: 14px;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"><img data-backh="36" data-backw="578" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.jpg" style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;widows: 1;word-spacing: 2px;color: rgb(136, 136, 136);box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p></pre> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;letter-spacing: 0.544px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 10px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">作者:java架构师阿松</span></span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;letter-spacing: 0.544px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 10px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">原文:toutiao.com/i6869621037831717387</span></span></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">前言</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;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);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">官网:</p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-left-color: rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;text-align: left;white-space: normal;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgb(255, 249, 249);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;font-size: 16px;color: black;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">https://baomidou.com/</p> </blockquote> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">创建数据库</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;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);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">数据库名为mybatis_plus</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">创建表</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;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);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">创建user表</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;max-width: 100%;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;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">DROP</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">TABLE</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">IF</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">EXISTS</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">user</span>;<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">CREATE</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">TABLE</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">user</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">id</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">BIGINT</span>(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">20</span>) <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">NOT</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">NULL</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">COMMENT</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'主键ID'</span>,<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">name</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">VARCHAR</span>(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">30</span>) <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">NULL</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">DEFAULT</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">NULL</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">COMMENT</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;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;">age <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">INT</span>(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">11</span>) <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">NULL</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">DEFAULT</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">NULL</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">COMMENT</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;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;">email <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">VARCHAR</span>(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">50</span>) <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">NULL</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">DEFAULT</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">NULL</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">COMMENT</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;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;">PRIMARY <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">KEY</span> (<span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">id</span>)<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">);<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">INSERT</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">INTO</span> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">user</span> (<span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">id</span>, <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">name</span>, age, email) <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">VALUES</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">1</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'Jone'</span>, <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">18</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'test1@baomidou.com'</span>),<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">2</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'Jack'</span>, <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">20</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'test2@baomidou.com'</span>),<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">3</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'Tom'</span>, <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">28</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'test3@baomidou.com'</span>),<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'Sandy'</span>, <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">21</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'test4@baomidou.com'</span>),<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">5</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'Billie'</span>, <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">24</span>, <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'test5@baomidou.com'</span>);<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;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);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">注意:-- 真实开发中往往都会有这四个字段,version(乐观锁)、deleted(逻辑删除)、gmt_create(创建时间)、gmt_modified(修改时间)</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">初始化项目</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;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);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">使用SpringBoot器 初始化!</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">导入依赖</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;max-width: 100%;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;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;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;"><span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">dependency</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">groupId</span>></span>mysql<span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">groupId</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">artifactId</span>></span>mysql-connector-java<span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">artifactId</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">dependency</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><!-- lombok --></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">dependency</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">groupId</span>></span>org.projectlombok<span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">groupId</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">artifactId</span>></span>lombok<span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">artifactId</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">dependency</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><!-- mybatis-plus --></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><!-- mybatis-plus 是自己开发,并非官方的! --></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">dependency</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">groupId</span>></span>com.baomidou<span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">groupId</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">artifactId</span>></span>mybatis-plus-boot-starter<span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">artifactId</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">version</span>></span>3.0.5<span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">version</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></<span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">dependency</span>></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;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);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">注意:尽量不要同时导入 mybatis 和 mybatis-plus!避免版本的差异造成无法预知的问题。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">连接数据库</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;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);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">创建application.yml</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;max-width: 100%;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;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">spring:</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">profiles:</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">active:</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">dev</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">datasource:</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"># 驱动不同 mysql 5 com.mysql.jdbc.Driver</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"># mysql 8 com.mysql.cj.jdbc.Driver、需要增加时区的配置serverTimezone=GMT%2B8</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">url:</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">driver-class-name:</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">com.mysql.cj.jdbc.Driver</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">username:</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">root</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">password:</span> <span style="max-width: 100%;color: rgb(166, 226, 46);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">root</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 1.3em;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">业务代码</span><span style="max-width: 100%;display: inline-block;vertical-align: bottom;border-bottom: 36px solid rgb(239, 235, 233);border-right: 20px solid transparent;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;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);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">实体类</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;color: rgb(0, 0, 0);font-size: 16px;text-align: left;background-color: rgb(255, 255, 255);border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;max-width: 100%;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;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@Data</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@AllArgsConstructor</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(117, 113, 94);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@NoArgsConstructor</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">public</span> <span style="max-width: 100%;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">class</span> <span style="max-width: 100%;font-weight: bold;color: white;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">User</span> </span>{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(249, 38, 114);font-weight: bold;line-height:
作者:微信小助手
<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> <p><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;text-align: left;"></span></strong></span></p> <blockquote style="padding: 15px 15px 15px 1rem;border-left-width: 5px;border-left-color: rgb(239, 112, 96);color: rgb(0, 0, 0);font-size: 0.9em;max-width: 100%;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 2px;white-space: normal;word-spacing: 2px;line-height: inherit;background: rgb(239, 235, 233);overflow: auto;word-break: normal;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: inherit;font-size: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">不知道你们经历过这种问题没有,比如问你遇到过线上性能问题没有,GC频繁,CPU飙高,任务队列积压,线程池任务拒绝等等,对于看重项目经验的面试官,这种问题基本是标配,问线上问题处理的经过,问题定位,排查的思路,怎么做的业务快速止血。</span><span style="max-width: 100%;color: inherit;font-size: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">一方面考察候选人项目的真实性,一般遇到线上问题大部分时候是系统主要负责人着手处理的,所以如果你处理过线上问题,也从侧面反映你的重要性。</span><span style="max-width: 100%;color: inherit;font-size: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">另外还能知道面试者是不是真的从原理上掌握了问题的根本原因,对技术的热忱等。</span><span style="max-width: 100%;color: inherit;font-size: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">另外建议大家处理完线上问题,排查了原因之后不要停,把排查过程和问题原因记录下来,一方面以后遇到类似问题可以基于已有的经验快速反应,另外就是一定让自己的知识</span><strong style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(233, 105, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">体系化</strong><span style="max-width: 100%;color: inherit;font-size: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">,怎么体系化呢? 就需要把日常的技术问题做归类总结。</span></p> </blockquote> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">这篇文章主要是给大家一个参考,讲讲安琪拉在上家公司遇到的线上问题以及排查思路,你们可能会好奇为什么不讲在阿里遇到的线上问题,这个我也会讲,但是因为很多数据要脱敏(马赛克),所以暂时先讲之前的,这篇是很早之前写的了,发布在博客园上。</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">铺垫太长了,下面进入正题。</p> <h3><span style="color: rgb(123, 12, 0);"><strong>问题</strong></span></h3> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">一个在普通不过的周末,安琪拉在家里玩安琪拉,蹲在草丛正准备给妲己一顿暴击,手机突然收到线上告警短信,吓得我一激灵,二技能放空,被妲己一套带走,趁着复活间隙,赶紧从床上爬起来打开电脑。</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">起因: 消息队列积压了十几万消息,第一反应,什么情况。。</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.9789029535864979" data-type="png" data-w="474" title="在这里插入图片描述" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 474px !important;visibility: visible !important;" src="/upload/3d935ff8ea929e202c775dbc7bf969e4.png"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">赶紧穿衣服,对待线上问题要严肃。</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">如下图,“待处…” 那一列就是指队列中“待处理的”消息。</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">消息积压,指的是消息的消费速度跟不上生产的速度,消息在消息队列中。</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.75" data-type="png" data-w="1280" title="img" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;" src="/upload/51b9e64e44051618fc7550ecad8f1a5c.png"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">可以看到有好几个分区已经积压了上万条消息;</p> <h3><span style="color: rgb(123, 12, 0);"><strong>问题排查</strong></span></h3> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">立即开始问题排查,遇到线上问题,一定是保证最快速度止血,降低对业务的影响,然后再是排查原因,当然有的问题也需要快速找到原因。</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">第一反应是不是入口流量太大,处理消息的线程池核心线程数满了,任务都在排队,但是看了入口流量并没有尖刺。</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">看监控的消息消费任务耗时,如下图:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.35539437896645515" data-type="png" data-w="2206" title="img" src="/upload/362d063e0870967145689c5d8c3cce4b.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">可以看到耗时在不断增加。那就需要看处理耗时增加原因了,为什么处理任务的耗时上涨了。</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">查看消息消费日志,如下:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.46770833333333334" data-type="png" data-w="1920" title="img" src="/upload/12a6314177047c49778db0bcea0b0f2f.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> img </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">发现有很多网络接口超时的。</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.1892605633802817" data-type="png" data-w="1136" title="img" src="/upload/74e6ac6f2df7c4915fc4ed55554531b1.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">大致得出结论:消息处理任务依赖下游系统接口,连接下游接口超时,连接下游接口设置的超时时间不算短,为什么下游接口如此多SocketTimeOut呢?</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.49783549783549785" data-type="png" data-w="1386" title="img" src="/upload/48fa94702691ec89df2984b790e1b5d7.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">下游系统也是我负责的系统,那重点开始看下游的系统监控,发现相关的接口调用的单机耗时时间极不规律,如下图所示:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.4891696750902527" data-type="png" data-w="2216" title="img" src="/upload/ec134acf68b12e74766e9c434f5e701c.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">对比一下日常这个接口的耗时时间,如下图,日常都没有超过100ms的:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.456071076011846" data-type="png" data-w="2026" title="img" src="/upload/5b3bb39bc8d5b4316bcaa73eab73a980.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">查看下游系统的监控大盘,发现了问题:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.4789473684210526" data-type="png" data-w="3040" title="img" src="/upload/896b01a0a31c98dd9c5776d3d0fec88c.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">老年代GC次数暴涨,而且gc耗时都到了秒级别,1分钟5~10秒,太恐怖了。</p> <h3><span style="color: rgb(123, 12, 0);"><strong>分析GC问题</strong></span></h3> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">找一台机器,把GC回收dump下来分析,使用mat查看,如下图所示:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.6211180124223602" data-type="png" data-w="1932" title="img" src="/upload/255456f856219ee52acac782ffad6308.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">一共七百多M空间,一个对象就占了640M空间,找到原因了,有内鬼(大对象)。</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="1" data-type="png" data-w="376" title="在这里插入图片描述" src="/upload/b0a18353faf3d9c36dcb64a0e8481ccc.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 376px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">继续往下,看这个对象为什么会这么大,从GC Roots最短路径如下,MAT的使用,以及JVM相关分析,感兴趣可以微信公众号【安琪拉的博客】回复JVM,拉你进JVM交流群。</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.5945611866501854" data-type="png" data-w="1618" title="img" src="/upload/835202ad87df12bab80029898ef4f33a.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">解释下,上面主要有三列,第一列是内存对象的类,重点在2,3列,Shallow Heap指的是对象本身占据的内存大小, Retained Heap = 本身本身占据内存大小 + 当前对象可直接或间接引用到的对象的大小总和,换句话说,就是当前对象如果被回收,能够回收的内存大小。</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">继续看,第一步,查看谁引用了这个对象,找到自己代码中的类,</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.2065081351689612" data-type="png" data-w="1598" title="img" src="/upload/5b595831060cf89934025c182984e5fb.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">第二步,查看这个对象TaggedMetricRegistry都引用了谁,为什么会占用这么大的内存空间,如下图所示,</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.15660184237461616" data-type="png" data-w="1954" title="img" src="/upload/d374b9781e9a0650257570ddcde6d7da.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">找到罪魁祸首了,metrics这个 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: inherit;line-height: inherit;border-radius: 4px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);box-sizing: border-box !important;overflow-wrap: break-word !important;">ConcurrentHashMap</code> 占了671M内存,现在开始可以看下代码,找到 TaggedMetricRegistry继承自MetricRegistry,metrics 是MetricRegistry的成员变量,如下图:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.19327731092436976" data-type="png" data-w="952" title="img" src="/upload/35c6500c970cabe9c9912c07a2ae944a.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="1.090289608177172" data-type="png" data-w="1174" title="img" src="/upload/426c396b8395185e18b31a5ca487d715.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">那为什么这个 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: inherit;line-height: inherit;border-radius: 4px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);box-sizing: border-box !important;overflow-wrap: break-word !important;">ConcurrentHashMap</code> 占了这么大的内存空间,并且GC也回收不掉呢?</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">我们继续看MAT,分析 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: inherit;line-height: inherit;border-radius: 4px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);box-sizing: border-box !important;overflow-wrap: break-word !important;">ConcurrentHashMap</code> 占有的详细内存分布:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.6775280898876405" data-type="png" data-w="1780" title="img" src="/upload/40c046f9e4d95d6262cac6cd9cf5838a.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">发现<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: inherit;line-height: inherit;border-radius: 4px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);box-sizing: border-box !important;overflow-wrap: break-word !important;">ConcurrentHashMap</code>有几个Node节点尤其大,</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">追下去,继续</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.4703389830508475" data-type="png" data-w="1888" title="img" src="/upload/28cfd74e9845f455e528008af42ed704.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">看到这个key,对应在代码中的位置,</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.12646566164154105" data-type="png" data-w="2388" title="img" src="/upload/518cc7264256e50aff0bf37246e88810.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">你们可能好奇这段代码是干嘛的呢?</p> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">这个代码的作用是统计接口每次的执行时间,它内部update的源码如下:</p> <figure style="max-width: 100%;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.623342175066313" data-type="png" data-w="1508" title="在这里插入图片描述" src="/upload/d6384d8564d4da986c7ba78e26d70c8d.png" style="margin-right: auto;margin-left: auto;font-size: inherit;color: inherit;line-height: inherit;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <figcaption style="margin-top: 10px;max-width: 100%;line-height: inherit;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br> </figcaption> </figure> <p style="margin-top: 1.7em;margin-bottom: 1.7em;max-width: 100%;min-height: 1em;color: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;letter-spacing: 2px;white-space: normal;word-spacing: 2px;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">这个方法是统计接口的耗时、调用次数的,它内部有一个measurements 的跳跃表,存放时间戳和统计指标(耗时、调用次数)的键值对,设置的时间窗口是1分钟,也就是它会存放1分钟的统计数据在内存中,当然这里面有个采样比,不是1分钟的全量数据,可以看到采样比是COLLISION_BUFFER决定的,然后1分钟上报一次内存数据到远端。问题就出现在这,因为这个耗时统计的函数的QPS非常高,1分钟有数据频繁产生的时候,会导致在一个时间窗口(1分钟)measurements极速增长,导致内存占用快速增长,但是因为有强引用,GC的时候也不会把这个回收掉,所有才出现了上面的那个情况。</p> <p><br></p> <p style="white-space: normal;text-align: center;"><span style="font-size: 15px;color: rgb(136, 136, 136);">- EOF -</span></p> <section donone="shifuMouseDownCard('shifu_c_030')" label="Copyright Reserved by PLAYHUDONG." style="margin-top: 1em;margin-bottom: 1em;white-space: normal;text-align: start;max-width: 100%;caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-left: 1em;max-width: 100%;line-height: 1.4;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="padding: 3px 8px;max-width: 100%;border-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;box-sizing: border-box !important;overflow-wrap: break-word !important;">推荐阅读</span> <span style="margin-left: 4px;padding: 3px 8px;max-width: 100%;border-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;box-sizing: border-box !important;overflow-wrap: break-word !important;">点击标题可跳转</span> </section> <section style="margin-top: -11px;padding: 22px 16px 16px;max-width: 100%;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;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651489951&idx=2&sn=27bd28409c14282108a8bbfa5521e6de&chksm=bd25eae08a5263f66ca1fb8db183a85e444dfa02d4d6a74f6e80bece03568e22b9005d330814&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 12px;" data-linktype="2"><span style="font-size: 12px;">JAVA 线上故障排查完整套路,从 CPU、磁盘、内存、网络、GC 一条龙!</span></a><br></p> <p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651489337&idx=1&sn=a110786585dae7cf83b346b617ea472e&chksm=bd25e8468a526150784fbd63e6852cd66eea35c1df8a4a5e1da7d87ac00810f123d2cfe2cfae&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" style="font-size: 12px;" data-linktype="2"><span style="font-size: 12px;">一个线上问题的思考:Eureka注册中心集群如何实现客户端请求负载及故障转移?</span></a><br></p> <p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-size: 12px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651489176&idx=1&sn=372225b68021cd8e19380527dfc985c8&chksm=bd25efe78a5266f156f6235d221c674ad13e6c49e6133869806a283a7760bbe427a8a0273525&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" style="font-size: 12px;" data-linktype="2">线程池运用不当的一次线上事故</a></span><span style="font-size: 13px;text-decoration: underline;font-family: inherit;text-align: inherit;"></span></p> </section> </section> <p style="white-space: normal;caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);text-align: start;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="text-align: center;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">看完本文有收获?请转发分享给更多人</span><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;"><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="max-width: 100%;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;text-align: center;font-size: 14px;overflow-wrap: break-word !important;box-sizing: border-box !important;">点赞和在看就是最大的支持</span><span style="max-width: 100%;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;text-align: center;font-size: 14px;overflow-wrap: break-word !important;box-sizing: border-box !important;">❤️</span><span style="font-size: 14px;text-align: right;"></span></p> <p><br></p>
作者:微信小助手
<p style="padding-right: 0.5em;padding-left: 0.5em;white-space: normal;" data-mpa-powered-by="yiban.io"><img class="rich_pages" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="48" data-ratio="0.10078125" data-s="300,640" src="/upload/4dbe1debe51138f467e6ce57d61bcbd7.png" data-type="png" data-w="1280" style="height: 58px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;width: 578px;"><br></p> <p style="padding-right: 0.5em;padding-left: 0.5em;white-space: normal;text-align: center;"><strong style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"><span style="color: rgb(136, 136, 136);font-size: 12px;letter-spacing: 1px;">总第442</span></strong><strong style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"><span style="color: rgb(136, 136, 136);font-size: 12px;letter-spacing: 1px;">篇</span></strong></p> <p style="padding-right: 0.5em;padding-left: 0.5em;white-space: normal;text-align: center;"><strong><span style="color: rgb(136, 136, 136);font-size: 12px;letter-spacing: 1px;">2021年 第012篇</span></strong></p> <section data-role="outer" label="Powered by 135editor.com" style="margin-right: 0.5em;margin-left: 0.5em;padding-right: 0.5em;padding-left: 0.5em;white-space: normal;"> <section data-role="outer" label="Powered by 135editor.com"> <section data-tools="135编辑器" data-id="127" style="border-width: 0px;border-style: none;border-color: initial;"> <section data-tools="135编辑器" data-id="127" style="border-width: 0px;border-style: none;border-color: initial;"> <section style="margin: 60px 16px 16px;border-width: 1px;border-style: solid;border-color: rgb(235, 234, 225);text-align: center;border-radius: 8px;"> <section style="margin-top: -3.3em;margin-right: 5px;margin-left: 5px;font-weight: inherit;text-decoration: inherit;font-size: 18px;color: inherit;"> <p style="margin-right: auto;margin-bottom: 15px;margin-left: auto;border-width: 2px;border-style: solid;border-color: rgb(235, 234, 225);width: 108px;height: 108px;border-radius: 50%;box-shadow: rgb(201, 201, 201) 0px 2px 2px 2px;background-color: rgb(254, 254, 254);"><img border="0" data-cropselx1="0" data-cropselx2="93" data-cropsely1="0" data-cropsely2="93" data-ratio="0.9966329966329966" src="/upload/c1f9e58a75e676cd4bee8d68e9fe8659.png" data-type="png" data-w="594" data-width="100%" opacity="" title="undefined" style="height: 103px;border-radius: 50%;color: inherit;display: inline-block;width: 103px;visibility: visible !important;"></p> </section> <section data-brushtype="text" data-style="text-align: left; font-size: 14px; color: inherit;" style="margin: 8px 15px;line-height: 1.4;"> <section style="text-align: justify;"> <span style="font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 14px;color: rgb(136, 136, 136);">图数据结构,能够更好地表征现实世界。美团业务相对较复杂,存在<span style="color: rgb(136, 136, 136);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 14px;">比较多的图数据存储及多跳查询需求,亟需一种组件来对千亿量级图数据进行管理</span>,<span style="color: rgb(136, 136, 136);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 14px;">海量图数据的高效存储和查询是图数据库研究的核心课题</span>。本文介绍了美团在图数据库选型及平台建设方面的一些工作。</span> </section> <section style="text-align: justify;"> <span style="font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 14px;color: rgb(136, 136, 136);"></span> </section> </section> </section> </section> </section> </section> </section> <section style="padding-right: 0.5em;padding-left: 0.5em;letter-spacing: 0px;white-space: normal;color: rgb(62, 62, 62);line-height: 1.6;"> <section style="line-height: 1.6;letter-spacing: 0px;"> <section style="line-height: 1.6;letter-spacing: 0px;"> <section style="line-height: 1.6;letter-spacing: 0px;"> <section style="padding-right: 0em;padding-left: 0em;line-height: 1.6;letter-spacing: 0px;"> <section style="font-size: 16px;line-height: 1.6;letter-spacing: 0px;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;color: black;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="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;"> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li style="font-size: 12px;"><p style="text-align: justify;"><span style="font-size: 12px;">1 前言</span></p></li> <li style="font-size: 12px;"><p style="text-align: justify;"><span style="font-size: 12px;">2 图数据库选型</span></p></li> <li style="font-size: 12px;"><p style="text-align: justify;"><span style="font-size: 12px;">3 NebulaGraph架构</span></p></li> <li style="font-size: 12px;"><p style="text-align: justify;"><span style="font-size: 12px;">4 图数据库平台建设</span></p></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-2"> <li style="font-size: 12px;"><p style="text-align: justify;"><span style="font-size: 12px;">4.1 高可用模块设计</span></p></li> <li style="font-size: 12px;"><p style="text-align: justify;"><span style="font-size: 12px;">4.2 每小时百亿量级数据导入模块设计</span></p></li> <li style="font-size: 12px;"><p style="text-align: justify;"><span style="font-size: 12px;">4.3 实时写入多集群数据同步模块设计</span></p></li> <li style="font-size: 12px;"><p style="text-align: justify;"><span style="font-size: 12px;">4.4 图可视化模块设计</span></p></li> </ul> <li style="font-size: 12px;"><p style=
作者:微信小助手
<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> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzU2MTM4NDAwMw==&mid=2247488603&idx=1&sn=468a4f698607dac659ddb0d2b2d6c7c2&chksm=fc78cb77cb0f4261434cc8b1d214b11f3b1596f935536e092f5a9e10573fd569331ca3e614d3&scene=21#wechat_redirect" textvalue="上一篇文章中 " data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">上一篇文章中 </strong></span></a><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">谈到了</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">《吃透系列<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">》</span>的讲解思路:先找到每个技术栈最本质的东西,然后以此为出发点,逐渐延伸出其他核心知识。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">所以,整个系列侧重于思考力的训练,不仅仅是讲清楚 What,而是更关注 Why 和 How,以帮助大家构建出牢固的知识体系。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">回到正文,<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这是技术系列《吃</span></span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">透 MQ》的开篇。本文主要讲解 MQ 的通用知识,让大家先弄明白:</span><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果让你来设计一个 MQ,该如何下手?需要考虑哪些问题?又有哪些技术挑战?</span></strong></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">有了这个基础后,我相信后面几篇文章再讲 Kafka 和 RocketMQ 这两种具体的消息中间件时,大家能很快地抓住主脉络,同时分辨出它们各自的特点。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">对于 MQ 来说,不管是 RocketMQ、Kafka 还是其他消息队列,</span><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 76, 0);font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">它们的本质都是:一发一存一消费。</span></strong><span style="max-width: 100%;color: rgb(62, 62, 62);font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">下面我们以这个本质作为根,一起由浅入深地聊聊 MQ。</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <p><span style="color: rgb(123, 12, 0);"><strong> 01 从 MQ 的本质说起 </strong></span></p> </section> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">将 MQ 掰开了揉碎了来看,都是<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">「</span>一发一存一消费<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">」</span>,再直白点就是一个<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">「</span>转发器<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">」。</span></span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">生产者先将消息投递一个叫做<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">「</span>队列<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">」</span>的容器中,然后再从这个容器中取出消息,最后再转发给消费者,仅此而已。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-ratio="0.26564003849855633" data-s="300,640" data-type="png" data-w="1039" src="/upload/d70305689879270351e0244e3ea6b1da.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <section style="margin-top: 25px;margin-bottom: 15px;max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">上面这个图便是消息队列最原始的模型,</span>它</span>包含了两个关键词:消息和队列。</span> </section> <blockquote data-tool="mdnice编辑器" style="margin-top: 0px;margin-bottom: 20px;padding: 8px 10px 4px 15px;border-left-width: 2px;border-left-color: rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;white-space: normal;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgb(255, 249, 249);letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="margin-bottom: 15px;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;color: rgb(74, 74, 74);line-height: 30px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">1、消息:就是要传输的数据,可以是最简单的文本字符串,也可以是自定义的复杂格式(只要能按预定格式解析出来即可)。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;color: rgb(74, 74, 74);line-height: 30px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">2、队列:<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">大家应该再熟悉不过了</span>,是一种先进先出数据结构。它是存放消息的容器,消息从队尾入队,从队头出队,入队即发消息的过程,出队<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">即</span>收消息的过程。</span></p> </blockquote> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <p><span style="color: rgb(123, 12, 0);"><strong> 02 原始模型的进化 </strong></span></p> </section> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">再看今天我们最常用的消息队列产品(RocketMQ、Kafka 等等),你会发现:</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;color: rgb(255, 76, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">它们都在最原始的消息模型上做了扩展</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">,同时提出了一些新名词,比如:主题(topic)、分区(partition)、队列(queue)等等。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">要彻底理解这些五花八门的新概念,我们化繁为简,先从消息模型的演进说起(</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">道理好比:架构从来不是设计出来的,而是演进而来的</strong></span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></p> <h2 data-tool="mdnice编辑器"><span style="color: rgb(123, 12, 0);"><strong>2.1 队列模型</strong></span></h2> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">最初的消息队列就是上一节讲的原始模型,它是一个严格意义上的队列(Queue)。消息按照什么顺序写进去,就按照什么顺序读出来。不过,队列没有 “读<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">”</span> 这个操作,读就是出队,从队头中 <span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">“</span>删除<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">”</span> 这个消息。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-ratio="0.26882661996497376" data-s="300,640" data-type="png" data-w="1142" src="/upload/e52d2bc1f98c572dfdbc9ba08ccdaa9d.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">便是队列模型</span>:它允许多个生产者往同一个队列发送消息。</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">但是,如果有多个消费者,实际上是竞争的关系,</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;color: rgb(255, 76, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">也就是一条消息只能被其中一个消费者接收到,读完即被删除。</span></p> <h2 data-tool="mdnice编辑器"><span style="color: rgb(123, 12, 0);"><strong>2.2 发布-订阅模型</strong></span></h2> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果需要将一份消息数据分发给多个消费者,并且每个消费者都要求收到全量的消息。很显然,队列模型无法满足这个需求。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">一个可行的方案是:为每个消费者创建一个单独的队列,让生产者发送多份。这种做法比较笨,而且同一份数据会被复制多份,也很浪费空间。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了解决这个问题,就演化出了另外一种消息模型:发布-订阅模型。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-backh="242" data-backw="578" data-ratio="0.418200408997955" data-s="300,640" data-type="png" data-w="978" src="/upload/99ef4aa6c85b447f199ad8b6a8b343ef.png" style="width: 677px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;"></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">在发布-订阅模型中,存放消息的容器变成了 “主题”,订阅者在接收消息之前需要先 “订阅主题”。最终,每个订阅者都可以收到同一个主题的全量消息。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">仔细对比下它和 “队列模式” 的异同:生产者就是发布者,队列就是主题,消费者就是订阅者,无本质区别。</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;color: rgb(255, 76, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">唯一的不同点在于:一份消息数据是否可以被多次消费。</span></p> <h2 data-tool="mdnice编辑器"><span style="color: rgb(123, 12, 0);"><strong>2.3 小结</strong></span></h2> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">最后做个小结,</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">上面两种模型说白了就是:</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;color: rgb(255, 76, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">单播和广播的区别</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">。而且,当发布-订阅模型中只有 1 个订阅者时,它和队列模型<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">就</span>一样了,因此在功能上是完全兼容队列模型的。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这也解释了为什么现代主流的 RocketMQ、Kafka 都是直接基于发布-订阅模型实现的?</span><span style="max-width: 100%;letter-spacing: 0.5444px;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">此外,RabbitMQ 中之所以有一个 Exchange 模块?其实也是为了解决消息的投递问题,可以变相实现发布-订阅模型。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">包括大家接触到的 “消费组<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">”、“集群消费”、“广播消费” 这些概念,都和上面这两种模型相关</span></span><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">,以及在应用层面</span>大家</span><span style="max-width: 100%;letter-spacing: 0.5444px;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">最常见的情</span></span><span style="max-width: 100%;letter-spacing: 0.5444px;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">形:组间广播、组内单播,</span><span style="max-width: 100%;letter-spacing: 0.5444px;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">也属于此范畴。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.5444px;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">所以,先掌握一些共性的理论,对于大家再去学习各个消息中间件的<span style="max-width: 100%;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">具体</span>实现原理时,其实能更好地抓住本质,分清概念。</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <p><span style="color: rgb(123, 12, 0);"><strong> 03 透过模型看 MQ 的应用场景 </strong></span></p> </section> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">目前,MQ 的应用场景非常多,大家能倒背如流的是:</span><span style="max-width: 100%;font-size: 16px;color: rgb(255, 76, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">系统解耦、异步通信和流量削峰。</span><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">除此之外,还有延迟通知、最终一致性保证、顺序消息、流式处理等等。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">那到底是先有消息模型,还是先有应用场景呢?答案肯定是:</span><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">先有应用场景(也就是先有问题),再有消息模型,因为消息模型只是解决方案的抽象而已。</span></p> <p style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;box-sizing: border-box !important;overflow-wrap: break-word !important;">MQ 经过 30 多年的发展,能从最原始的队列模型发展到今天百花齐放的各种消息中间件(平台级的解决方案),我觉得万变不离其宗,还是得益于:</span><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.5444px;color: rgb(255, 76, 0);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 style="margin-top: 25px;margin-bottom: 25px;max-width: 100%;min-height: 1em;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.5444px;line-height: 30px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">我们试着重新理解下消息队列的模型。它其实解决的是:生产者和消费者的通信问题。那它对比 RPC 有什么联系和区别呢?</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-backh="323" data-backw="578" data-ratio="0.559410234171726" data-s="300,640" data-type="png" data-w="1153" src="/upload/
作者:微信小助手
<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><span style="font-size: 14px;">转自:大数据之路,</span></p> <p><span style="font-size: 14px;">链接:my.oschina.net/leejun2005/blog/1524687</span></p> </blockquote> <p><span style="color: rgb(123, 12, 0);"><strong>背景</strong></span></p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;color: inherit;font-size: inherit;letter-spacing: 0.544px;white-space: normal;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;">经常做后端服务开发的同学,或多或少都遇到过 CPU 负载特别高的问题。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;color: inherit;font-size: inherit;letter-spacing: 0.544px;white-space: normal;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;">尤其是在周末或大半夜,突然群里有人反馈线上机器负载特别高,不熟悉定位流程和思路的同学可能登上服务器一通手忙脚乱,定位过程百转千回。</p> <figure style="max-width: 100%;color: inherit;font-size: inherit;letter-spacing: 0.544px;white-space: normal;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.6666666666666666" data-type="png" data-w="936" src="/upload/7dcf3b0dedae4bd76d2fbe8b0e741474.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> </figure> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;color: inherit;font-size: inherit;letter-spacing: 0.544px;white-space: normal;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;">对此,也有不少同学曾经整理过相关流程或方法论,类似把大象放进冰箱要几步</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;color: inherit;font-size: inherit;letter-spacing: 0.544px;white-space: normal;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(123, 12, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">传统的方案一般是4步</strong>:</span></p> <pre style="margin-top: 0.5em;margin-bottom: 0.5em;padding: 0.4em 0.6em;max-width: 100%;color: inherit;font-size: inherit;letter-spacing: 0.544px;border-radius: 8px;background: rgb(255, 255, 255);line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="margin-right: 2px;margin-left: 2px;padding: 0.5em;max-width: 100%;min-height: 1em;font-size: 11px;word-spacing: -3px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);line-height: 2em;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(104, 151, 187);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">1.</span> top oder by <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(204, 120, 50);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">with</span> P:<span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(104, 151, 187);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">1040</span> <span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">// 首先按进程负载排序找到 axLoad(pid)</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;line-height: inherit;col
作者:微信小助手
<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;" data-mpa-powered-by="yiban.io"><span data-mce-style="font-size: 10px" style="font-size: 13px;color: rgb(136, 136, 136);">点击上方蓝色“</span><span style="color: rgb(24, 144, 255);font-size: 13px;" data-mce-style="font-size: 10px">后端面试那些事儿</span><span data-mce-style="font-size: 10px" style="font-size: 13px;color: rgb(136, 136, 136);">”,选择“设为星标”</span></p> <p data-lake-id="eca2a1864e13b3e1b84aafe9cb4abdff" 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;" data-mce-style="font-size: 10px">学最好的别人,做最好的自己</span></p> <p data-lake-id="b4f10076adf2228ecaccd921f627ed69" style="text-align: right;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;" data-mce-style="font-size: 10px">来自:r6d.cn/V9T7</span></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">没啥深入实践的理论系同学,在使用并发工具时,总是认为把HashMap改为ConcurrentHashMap,就完美解决并发了呀。或者使用写时复制的CopyOnWriteArrayList,性能更佳呀!技术言论虽然自由,但面对魔鬼面试官时,我们更在乎的是这些真的正确吗?</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">线程重用导致用户信息错乱</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">生产环境中,有时获取到的用户信息是别人的。查看代码后,发现是使用了ThreadLocal缓存获取到的用户信息。</p> <p style="text-align: center;"><img class="rich_pages" data-backh="209" data-backw="578" data-ratio="0.3613678373382625" data-s="300,640" src="/upload/b064d5353492c53420fcf8650a457800.png" data-type="png" data-w="1082" style="width: 100%;height: auto;"></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">ThreadLocal适用于变量在线程间隔离,而在方法或类间共享的场景。若用户信息的获取比较昂贵(比如从DB查询),则在ThreadLocal中缓存比较合适。问题来了,为什么有时会出现用户信息错乱?</p> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">案例</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">使用ThreadLocal存放一个Integer值,代表需要在线程中保存的用户信息,初始null。先从ThreadLocal获取一次值,然后把外部传入的参数设置到ThreadLocal中,模拟从当前上下文获取用户信息,随后再获取一次值,最后输出两次获得的值和线程名称。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">固定思维认为,在设置用户信息前第一次获取的值始终是null,但要清楚程序运行在Tomcat,执行程序的线程是Tomcat的工作线程,其基于线程池。而线程池会重用固定线程,一旦线程重用,那么很可能首次从ThreadLocal获取的值是之前其他用户的请求遗留的值。这时,ThreadLocal中的用户信息就是其他用户的信息。</p> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">bug 重现</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">在配置文件设置Tomcat参数-工作线程池最大线程数设为1,这样始终是同一线程在处理请求:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">server.tomcat.max-threads=1<br></code></pre> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 先让用户1请求接口,第一、第二次获取到用户ID分别是null和1,符合预期 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 用户2请求接口,bug复现!第一、第二次获取到用户ID分别是1和2,显然第一次获取到了用户1的信息,因为Tomcat线程池重用了线程。两次请求线程都是同一线程:http-nio-45678-exec-1。 </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">写业务代码时,首先要理解代码会跑在什么线程上:</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> Tomcat服务器下跑的业务代码,本就运行在一个多线程环境(否则接口也不可能支持这么高的并发),并不能认为没有显式开启多线程就不会有线程安全问题 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 线程创建较昂贵,所以Web服务器会使用线程池处理请求,线程会被重用。使用类似ThreadLocal工具存放数据时,需注意在代码运行完后,显式清空设置的数据。 </section></li> </ul> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">解决方案</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">在finally代码块显式清除ThreadLocal中数据。即使新请求过来,使用了之前的线程,也不会获取到错误的用户信息。修正后代码:</p> <p style="text-align: center;"><img class="rich_pages" data-backh="235" data-backw="578" data-ratio="0.4066543438077634" data-s="300,640" src="/upload/74c8e26969f7269ab1c04dc43bf3ed98.png" data-type="png" data-w="1082" style="width: 100%;height: auto;"></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">ThreadLocal利用独占资源的解决线程安全问题,若就是要资源在线程间共享怎么办?就需要用到线程安全的容器。使用了线程安全的并发工具,并不代表解决了所有线程安全问题。</p> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">ThreadLocalRandom 可将其实例设置到静态变量,在多线程下重用吗?</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">current()的时候初始化一个初始化种子到线程,每次nextseed再使用之前的种子生成新的种子:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">UNSAFE.putLong(t = Thread.currentThread(), SEED,<br>r = UNSAFE.getLong(t, SEED) + GAMMA);<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">如果你通过主线程调用一次current生成一个ThreadLocalRandom实例保存,那么其它线程来获取种子的时候必然取不到初始种子,必须是每一个线程自己用的时候初始化一个种子到线程。可以在nextSeed设置一个断点看看:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">UNSAFE.getLong(Thread.currentThread(),SEED);<br></code></pre> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">ConcurrentHashMap真的安全吗?</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">我们都知道ConcurrentHashMap是个线程安全的哈希表容器,但它仅保证提供的原子性读写操作线程安全。</p> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">案例</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">有个含900个元素的Map,现在再补充100个元素进去,这个补充操作由10个线程并发进行。开发人员误以为使用ConcurrentHashMap就不会有线程安全问题,于是不加思索地写出了下面的代码:在每一个线程的代码逻辑中先通过size方法拿到当前元素数量,计算ConcurrentHashMap目前还需要补充多少元素,并在日志中输出了这个值,然后通过putAll方法把缺少的元素添加进去。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">为方便观察问题,我们输出了这个Map一开始和最后的元素个数。</p> <p style="text-align: center;"><img class="rich_pages" data-backh="338" data-backw="578" data-ratio="0.5853432282003711" data-s="300,640" src="/upload/360c78b89c19b0052b36c190ff6fa2d9.png" data-type="png" data-w="1078" style="width: 100%;height: auto;"></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 访问接口 </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">分析日志输出可得:</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 初始大小900符合预期,还需填充100个元素 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> worker13线程查询到当前需要填充的元素为49,还不是100的倍数 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 最后HashMap的总项目数是1549,也不符合填充满1000的预期 </section></li> </ul> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">bug 分析</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">ConcurrentHashMap就像是一个大篮子,现在这个篮子里有900个桔子,我们期望把这个篮子装满1000个桔子,也就是再装100个桔子。有10个工人来干这件事儿,大家先后到岗后会计算还需要补多少个桔子进去,最后把桔子装入篮子。ConcurrentHashMap这篮子本身,可以确保多个工人在装东西进去时,不会相互影响干扰,但无法确保工人A看到还需要装100个桔子但是还未装时,工人B就看不到篮子中的桔子数量。你往这个篮子装100个桔子的操作不是原子性的,在别人看来可能会有一个瞬间篮子里有964个桔子,还需要补36个桔子。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">ConcurrentHashMap对外提供能力的限制:</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 使用不代表对其的多个操作之间的状态一致,是没有其他线程在操作它的。如果需要确保需要手动加锁 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 诸如size、isEmpty和containsValue等聚合方法,在并发下可能会反映ConcurrentHashMap的中间状态。因此在并发情况下,这些方法的返回值只能用作参考,而不能用于流程控制。显然,利用size方法计算差异值,是一个流程控制 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 诸如putAll这样的聚合方法也不能确保原子性,在putAll的过程中去获取数据可能会获取到部分数据 </section></li> </ul> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">解决方案</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">整段逻辑加锁:</p> <p style="text-align: center;"><img class="rich_pages" data-backh="292" data-backw="578" data-ratio="0.5055555555555555" data-s="300,640" src="/upload/54ddac1d2aab588a0ddd21014c04fb66.png" data-type="png" data-w="1080" style="width: 100%;height: auto;"></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 只有一个线程查询到需补100个元素,其他9个线程查询到无需补,最后Map大小1000 </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">既然使用ConcurrentHashMap还要全程加锁,还不如使用HashMap呢?不完全是这样。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">ConcurrentHashMap提供了一些原子性的简单复合逻辑方法,用好这些方法就可以发挥其威力。这就引申出代码中常见的另一个问题:在使用一些类库提供的高级工具类时,开发人员可能还是按照旧的方式去使用这些新类,因为没有使用其真实特性,所以无法发挥其威力。</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">知己知彼,百战百胜</h3> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">案例</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">使用Map来统计Key出现次数的场景。</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 使用ConcurrentHashMap来统计,Key的范围是10 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 使用最多10个并发,循环操作1000万次,每次操作累加随机的Key </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 如果Key不存在的话,首次设置值为1。 </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">show me code:</p> <p style="text-align: center;"><img class="rich_pages" data-backh="285" data-backw="578" data-ratio="0.4921077065923863" data-s="300,640" src="/upload/ef71175c9dc1636a1b2d85180c80c25b.png" data-type="png" data-w="1077" style="width: 100%;height: auto;"></p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">有了上节经验,我们这直接锁住Map,再做</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 判断 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 读取现在的累计值 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> +1 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 保存累加后值 </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">这段代码在功能上的确毫无没有问题,但却无法充分发挥ConcurrentHashMap的性能,优化后:</p> <p style="text-align: center;"><img class="rich_pages" data-backh="249" data-backw="578" data-ratio="0.43068391866913125" data-s="300,640" src="/upload/7bdb511851aec6c35e5e10489acd8b1.png" data-type="png" data-w="1082" style="width: 100%;height: auto;"></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> ConcurrentHashMap的原子性方法computeIfAbsent做复合逻辑操作,判断K是否存在V,若不存在,则把Lambda运行后结果存入Map作为V,即新创建一个LongAdder对象,最后返回V 因为computeIfAbsent返回的V是LongAdder,是个线程安全的累加器,可直接调用其increment累加。这样在确保线程安全的情况下达到极致性能,且代码行数骤减。 </section></li> </ul> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">性能测试</h4> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 使用StopWatch测试两段代码的性能,最后的断言判断Map中元素的个数及所有V的和是否符合预期来校验代码正确性 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 性能测试结果:比使用锁性能提升至少5倍。 </section></li> </ul> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">computeIfAbsent高性能之道</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">Java的Unsafe实现的CAS。它在JVM层确保写入数据的原子性,比加锁效率高:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;">static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,<br> Node<K,V> c, Node<K,V> v) {<br> <span style="color: rgb(230, 192, 123);line-height: 26px;">return</span> U.compareAndSetObject(tab, ((long)i << ASHIFT) + ABASE, c, v);<br>}<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">所以不要以为只要用了ConcurrentHashMap并发工具就是高性能的高并发程序。</p> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">辨明 computeIfAbsent、putIfAbsent</h4> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 当Key存在的时候,如果Value获取比较昂贵的话,putIfAbsent就白白浪费时间在获取这个昂贵的Value上(这个点特别注意) </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> Key不存在的时候,putIfAbsent返回null,小心空指针,而computeIfAbsent返回计算后的值 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 当Key不存在的时候,putIfAbsent允许put null进去,而computeIfAbsent不能,之后进行containsKey查询是有区别的(当然了,此条针对HashMap,ConcurrentHashMap不允许put null value进去) </section></li> </ul> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">CopyOnWriteArrayList 之殇</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">再比如一段简单的非 DB操作的业务逻辑,时间消耗却超出预期时间,在修改数据时操作本地缓存比回写DB慢许多。原来是有人使用了CopyOnWriteArrayList缓存大量数据,而该业务场景下数据变化又很频繁。CopyOnWriteArrayList虽然是一个线程安全版的ArrayList,但其每次修改数据时都会复制一份数据出来,所以只适用读多写少或无锁读场景。所以一旦使用CopyOnWriteArrayList,一定是因为场景适宜而非炫技。</p> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">CopyOnWriteArrayList V.S 普通加锁ArrayList读写性能</h4> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 测试并发写性能 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 测试结果:高并发写,CopyOnWriteArray比同步ArrayList慢百倍 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 测试并发读性能 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 测试结果:高并发读(100万次get操作),CopyOnWriteArray比同步ArrayList快24倍 </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">高并发写时,CopyOnWriteArrayList为何这么慢呢?因为其每次add时,都用Arrays.copyOf创建新数组,频繁add时内存申请释放性能消耗大。</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">总结</h3> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">Don't !!!</h4> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;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.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 不要只会用并发工具,而不熟悉线程原理 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 不要觉得用了并发工具,就怎么都线程安全 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 不熟悉并发工具的优化本质,就难以发挥其真正性能 </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 不要不结合当前业务场景,就随意选用并发工具,可能导致系统性能更差 </section></li> </ul> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;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;white-space: normal;background-color: rgb(255, 255, 255);">Do !!!</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;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;white-space: normal;background-color: rgb(255, 255, 255);">认真阅读官方文档,理解并发工具适用场景及其各API的用法,并自行测试验证,最后再使用 并发bug本就不易复现, 多自行进行性能压力测试</p> <p data-lake-id="b4f10076adf2228ecaccd921f627ed69" 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;"><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <section mpa-from-tpl="t" style="margin-top: 10px;margin-bottom: 10px;"> <p style="margin-right: auto;margin-left: auto;width: 231.1875px;"><img data-ratio="0.16666666666666666" src="/upload/89aa6c9fe16e0dfcf56dad1a9f9078ff.png" data-type="gif" data-w="300" style="width: auto;"></p> </section> </section> <p data-lake-id="098b923ca3e65e99528d2c30d6cf4c26" 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;"><br></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="2247493708_1" data-recommend-article-time="1617686400" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkFlK4ENeh94JAxoZZRYz6dGTeD0tQScMauibXXuriaD9djse4XN8jPTSxC5VYAM9ibprplImNbIMwgmQ/0?wx_fmt=jpeg" data-recommend-article-title="90%的开发都不太考虑这个,但只要出问题直接公司完蛋!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493708&idx=1&sn=c2408f6d4029f98d0756b3561cf34f39&chksm=97b47654a0c3ff4219976ee91de14989b1ae3b8f143a3d575fefb49f39300d018a12887ef9bc#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493708&idx=1&sn=c2408f6d4029f98d0756b3561cf34f39&chksm=97b47654a0c3ff4219976ee91de14989b1ae3b8f143a3d575fefb49f39300d018a12887ef9bc&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="">90%的开发都不太考虑这个,但只要出问题直接公司完蛋!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247493708_2" data-recommend-article-time="1617686400" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/8cpIYdAicCct4AnaECAgWicR7ZEWJicBffchMF0xib0grrJxsSQiaZYrWJ2Nk81bujsTvNpFHBewPVYSzlRic16zJicwQ/0?wx_fmt=jpeg" data-recommend-article-title="又在GitHub上挖到个宝藏:Switch模拟器!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493708&idx=2&sn=642fab82cdf1c822bfa37649e4498da9&chksm=97b47654a0c3ff42fc9b66315f400eab10dae45dd226855fc57b68cf3f8626ae7ffa2d6718ea#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493708&idx=2&sn=642fab82cdf1c822bfa37649e4498da9&chksm=97b47654a0c3ff42fc9b66315f400eab10dae45dd226855fc57b68cf3f8626ae7ffa2d6718ea&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="">又在GitHub上挖到个宝藏:Switch模拟器!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247493703_1" data-recommend-article-time="1617426060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtZuZ9XFXCsTCGkLnHsibyUgK2SDibJkqibg4lW3FU5ajNVFxeFmaltnK4XImBaUWmicp8XM4jgY2rWy0w/0?wx_fmt=jpeg" data-recommend-article-title="955 不加班的公司名单!2021 最新版!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493703&idx=1&sn=ed4ccd76875bb07108c889404faff010&chksm=97b4765fa0c3ff498cf055b52aa1abbdd45a5293a4c098bf09544c07d7a3d32f963b2ae620c7#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493703&idx=1&sn=ed4ccd76875bb07108c889404faff010&chksm=97b4765fa0c3ff498cf055b52aa1abbdd45a5293a4c098bf09544c07d7a3d32f963b2ae620c7&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="">955 不加班的公司名单!2021 最新版!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247493703_2" data-recommend-article-time="1617426060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkFasVRlHA3OKGSD4U2ibFpb42b5s9QdGs94AklicC5XVAEMhazM3r54ZQvWtG9QViaibExawFI3QbxaYw/0?wx_fmt=jpeg" data-recommend-article-title="苹果开源代码中惊现“wechat”,老外注释的吐槽亮了!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493703&idx=2&sn=e7c7e51000f53648d384456421e714fb&chksm=97b4765fa0c3ff497122a74b546dab03fa823de2d05a0d42e21f0ae3bb4bd19c4c8b1fe446c9#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493703&idx=2&sn=e7c7e51000f53648d384456421e714fb&chksm=97b4765fa0c3ff497122a74b546dab03fa823de2d05a0d42e21f0ae3bb4bd19c4c8b1fe446c9&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="">苹果开源代码中惊现“wechat”,老外注释的吐槽亮了!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247493689_1" data-recommend-article-time="1617339660" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtZ8hkazCWYtrJeicRRwZSNlVWdmtLBW3xJTq5f2mZcJR7dibptu1Ij4gmCj2ranMqcwzfNwyl86pI0w/0?wx_fmt=jpeg" data-recommend-article-title="为何 IntelliJ IDEA 比 Eclipse 更好?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493689&idx=1&sn=2a05082c472a145a6e14433616d04255&chksm=97b47621a0c3ff37368fc6312b4af4cc5e5ca54b5b458d7ad576fa76913153f6aa3154e020d6#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493689&idx=1&sn=2a05082c472a145a6e14433616d04255&chksm=97b47621a0c3ff37368fc6312b4af4cc5e5ca54b5b458d7ad576fa76913153f6aa3154e020d6&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="">为何 IntelliJ IDEA 比 Eclipse 更好?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247493689_2" data-recommend-article-time="1617339660" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkFvYQqWLMCj7X7sn6Twc712VNmHHwdNGia9ZQlwaTkEKdx6EiajxwOyL2CfDzyQkDKCZZrEhGMeCMgg/0?wx_fmt=jpeg" data-recommend-article-title="日本政府用AI分配对象了!给你分一个的话,敢不敢要?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493689&idx=2&sn=4a1dbb4784820d8062088f00a4a64d02&chksm=97b47621a0c3ff378a2bfc2f2fe4847cc063617a9fe7a3b344d749c9975df601b7cc88de135f#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247493689&idx=2&sn=4a1dbb4784820d8062088f00a4a64d02&chksm=97b47621a0c3ff378a2bfc2f2fe4847cc063617a9fe7a3b344d749c9975df601b7cc88de135f&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="">日本政府用AI分配对象了!给你分一个的话,敢不敢要?</p> </section></a> </section> </section> </section> </section> <p data-lake-id="098b923ca3e65e99528d2c30d6cf4c26" 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);letter-spacing: 0.008em;"></span></p> <section data-mpa-template="t" mpa-from-tpl="t" style="white-space: normal;"> <p style="text-align: center;"><strong><span style="color: rgb(140, 140, 140);letter-spacing: 0.008em;font-size: 14px;">一起进大厂,每日学干货</span></strong></p> </section> <section style="margin-top: 5px;white-space: normal;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(0, 0, 0);"><strong><span style="font-size: 14px;">关注我回复【</span></strong></span> <span style="color: rgb(255, 76, 65);"><strong><span style="font-size: 14px;">加群</span></strong></span> <span style="color: rgb(0, 0, 0);"><strong><span style="color: rgb(0, 0, 0);font-size: 14px;">】,加入Java技术交流群</span></strong></span> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <p style="text-align: center;"><img data-ratio="0.5982532751091703" src="/upload/4e21037b66f60f7d73d060863de4b4b5.png" data-type="gif" data-w="458" data-width="100%" style="color: rgb(62, 62, 62);font-size: 16px;vertical-align: middle;width: 62.0938px;"></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzIxMzQzNzMwMw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/HmHDU48icAtYvlypOY9VaGVXQ639L63Iq6zHiclgibG0CAhgrJ2JLRibKbeCgVIx7WXcicbMW6AJL1Hos9AoJTqtVfA/0?wx_fmt=png" data-nickname="后端面试那些事" data-alias="" data-signature="后端老鸟带你进击大厂后端职位!这里分享面试题、内推渠道,还有各种后端工程师相关的学习资料与工具分享等干货内容!"></mpprofile> </section> </section> <p style="text-align: center;"><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="paragraph" mpa-from-tpl="t" style="white-space: normal;border-width: 0px;border-style: none;border-color: initial;"> <section style="box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="margin-top: 0.5em;box-sizing: border-box;"> <section style="padding: 0.5em;border-width: 1px;border-style: solid;border-color: rgb(249, 110, 87);box-shadow: rgb(226, 226, 226) 0px 16px 1px -13px;box-sizing: border-box;"> <section powered-by="xiumi.us" style="text-align: left;box-sizing: border-box;"> <section style="text-align: justify;color: rgb(64, 84, 115);box-sizing: border-box;"> <p style="box-sizing: border-box;"><img src="/upload/a53e4e397528931045198e4f89d7ba0.png" data-type="png" data-ratio="0.33611111111111114" data-w="1080"></p> <p style="box-sizing: border-box;">点击“阅读原文”,领取 2021 年<strong>最新免费技术资料大全</strong></p> </section> </section> </section> </section> <section powered-by="xiumi.us" style="font-size: 32px;color: rgb(249, 110, 87);box-sizing: border-box;text-align: left;"> ↓↓↓ </section> </section> </section> </section>