文章列表

震惊!Kubernetes -K8S全新视频课程上线!网盘免费下载

作者:wkcto

Kubernetes简单来说就是一个自动化部署,缩放,以及容器化管理应用程序的开源系统。Kubernetes这个单词来自于希腊语,含义是舵手或领航员,是一款产品级的容器编排技术,可以自动进行容器的部署、扩容和管理。Kubernetes也称为K8S,其中8是代表中间“ubernete”的8个字符,是Google在2014年开源的一个容器编排引擎,用于自动化容器化应用程序的部署、规划、扩展和管理,它将组成应用程序的容器分组为逻辑单元,以便于管理和发现,用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化的应用简单并且高效,很多细节都不需要运维人员去进行复杂的手工配置和处理; 如今,随着Kubernetes技术的成熟,Kubernetes火热的一塌糊涂。Kubernetes的快速崛起不仅仅是因为能够简化运维人员的工作,节省大量的手工工作时间,从而达到“偷懒”的效果,我们视之为人和。此外,天时和地利也是缺一不可的。 天时:当Docker等容器运行时成熟时,越来越多的企业在私有云和公有云中运行着成百上千的容器实例,关注点逐渐转移到如何管理和调度容器了,自然需要在上层架设一套管理系统。 地利:K8S由Google背书,是由Google内部稳定运行了十几年的第一代容器管理系统Borg、第二代容器管理系统Omega演进而来,目前的K8S是第三代容器管理系统,针对大规模应用集群的自动管理提出了很多先进的理念并且实现了:Pod、ReplicaSet、Service、Kube-proxy等。而且,由于Google的背书,越来越多的第三方加入到K8S生态中来,可以说整个CNCF社区就是围绕K8S生态构建的。这是其他几个竞争对手(如Mesos、Swarm等)没法比的。 Kubernetes是Google开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡。Kubernetes也是从事运维人员的必备技术,对于开发人员来说也是不可多得的一门好技术,我们可以采用Kubernetes技术来进行微服务的部署,为了方便众多Kubernetes小白的学习,我们推出的课程以精炼的篇幅,在比较短的时间内让你快速掌握Kubernetes,以快速适应公司的需要,不管是开发人员还是运维人员都能快速掌握这一门技术; 主讲老师:动力节点-杨老师 Java高级讲师,北京航天航空大学,软件工程硕士。主持开发 2008年奥运场馆人脸信息采集项目,中国电信计费项目,清华大学实验室安保项目,清华大学校园一卡通项目,百威英博物联网项目,京东云平台项目,人人车网等多个大型项目。先后在烟台大学,辽宁师范大学,首都经贸大学,沈阳工业学院,济南大学,许昌学院,北京林业大学等多个高校授课,收到一致好评。授课风格幽默诙谐,通俗易懂。结合丰富开发经验将实战融入教学,为学员顺利就业保驾护航。 课程核心内容(目录): What is Kubernetes? Kubernetes管理员认证(CKA) Kubernetes整体架构 Kubernetes环境搭建方式 Kubeadm部署Kubernetes Kubernetes部署环境要求 Kubernetes部署环境准备 Kubernetes安装具体步骤 Kubernetes部署网络插件 Kubernetes部署“容器化应用” 在Kubernetes集群中部署一个Nginx 在Kubernetes集群中部署一个Tomcat 在Kubernetes集群中部署SpringBoot应用 部署Kubernetes Dashbaord 采用Ingress暴露应用 采用Ingress暴露容器化应用(Nginx) kubernetes部署Spring Cloud微服务 Kubernetes架构及和核心组件 当然,尽管Kubernetes技术非常火热,学起来难度不大,但是还是有一定的门槛的,学习本课程的学员需要先掌握Docker技术,学起来才能够有好的效果;本课程采用的Kubernetes版本为:1.19.4,在正式学习之前,了解Kubernetes的特点是十分必要的,总的来说,Kubernetes有以下三个特点: 1.可移植: 支持公有云,私有云,混合云,多重云(multi-cloud) 2.可扩展: 模块化,插件化,可挂载,可组合 3.自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展 熟练掌握Kubernetes的组件结构和功能是学习Kubernetes课程的基本要求: 1、Master 组件 1.1kube-apiserver 1.2ETCD 1.3kube-controller-manager 1.4cloud-controller-manager 1.5kube-scheduler 1.6插件 addons 1.6.1DNS 1.6.2用户界面 1.6.3容器资源监测 1.6.4Cluster-level Logging 2、节点(Node)组件 2.1kubelet 2.2kube-proxy 2.3docker 2.4RKT 2.5supervisord 2.6fluentd 动力节点重磅推出的全新视频课程——从零开始学 Kubernetes -K8S从入门到实战,已经全网正式上线啦!令人意想不到的是这么好的视频课程,现在竟然可以免费学习啦。 课程百度网盘下载地址: https://pan.baidu.com/share/init?surl=2vG-aTUexOeIu7ROa_FCKA 提取码:jw57 还在犹豫什么,快来学习我们的全新Kubernetes视频课程吧,多一门技术就多一个选择,Kubernetes技术犹如刚刚崛起的新星,在互联网技术的星空之网上烨烨生辉,我们接受这光的洗礼,让我们的技术和事业更进一步! 来源:http://www.bjpowernode.com/javavideo/206.html

体验了一下Java 8 异步 API、循环、日期,还真挺好!

作者:微信小助手

<section> <section data-id="137" data-tools="非找你编辑器" data-tools-id="85108"> <section> <section data-id="140" data-tools="非找你编辑器"> <section style="margin-right:0%;margin-left:0%;"> <section style="display:inline-block;vertical-align:middle;width:80%;" data-width="80%"> <section style=""> <section style="margin-top:10px;margin-bottom:10px;text-align:center;"> <section style="display:inline-block;"> <section style="font-size:0px;padding-bottom:3px;"> <section style="display:inline-block;vertical-align:middle;"> <section style="width:5px;height:1px;background-color:rgb(217,217,217);" data-width="5px"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> <section style="width:1px;height:5px;margin-top:-3px;margin-right:auto;margin-left:auto;background-color:rgb(217,217,217);" data-width="1px"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> </section> <section style="margin-top:-1px;margin-right:-5px;margin-left:-5px;width:100%;display:inline-block;vertical-align:middle;padding-right:8px;padding-left:8px;" data-width="100%"> <section style="width:100%;height:1px;background-color:rgb(217,217,217);" data-width="100%"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> </section> <section style="display:inline-block;vertical-align:middle;"> <section style="width:5px;height:1px;background-color:rgb(217,217,217);" data-width="5px"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> <section style="width:1px;height:5px;margin-top:-3px;margin-right:auto;margin-left:auto;background-color:rgb(217,217,217);" data-width="1px"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> </section> </section> <section style="padding-left:15px;padding-right:15px;color:rgb(161,161,161);"> <p><strong>点击上方关注这个神奇的公众号~</strong></p> </section> <section style="font-size:0px;"> <section style="display:inline-block;vertical-align:middle;"> <section style="width:5px;height:1px;background-color:rgb(217,217,217);" data-width="5px"> <strong><span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span></strong> </section> <section style="width:1px;height:5px;margin-top:-3px;margin-right:auto;margin-left:auto;background-color:rgb(217,217,217);" data-width="1px"> <strong><span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span></strong> </section> </section> <section style="margin-top:-1px;margin-right:-5px;margin-left:-5px;width:100%;display:inline-block;vertical-align:middle;padding-right:8px;padding-left:8px;" data-width="100%"> <section style="width:100%;height:1px;background-color:rgb(217,217,217);" data-width="100%"> <strong><span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span></strong> </section> </section> <section style="display:inline-block;vertical-align:middle;"> <section style="width:5px;height:1px;background-color:rgb(217,217,217);" data-width="5px"> <strong><span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span></strong> </section> <section style="width:1px;height:5px;margin-top:-3px;margin-right:auto;margin-left:auto;background-color:rgb(217,217,217);" data-width="1px"> <br> </section> </section> </section> </section> </section> </section> </section> <section style="display:inline-block;vertical-align:middle;width:20%;" data-width="20%"> <section style=""> <section style="text-align:center;margin:-10px 0% 10px;"> <section style="vertical-align:middle;display:inline-block;width:100%;overflow:hidden !important;" data-width="100%"> <img data-ratio="0.94375" src="/upload/dde7acdc77dc0167b092df91f5896bb3.png" data-type="gif" data-w="480" data-width="100%" style="vertical-align:middle;width:100%;" width="100%"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> </section> </section> </section> </section> </section> <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, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, 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;"><span style="max-width: 100%;font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;">作者:funnyZpC<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">出处:cnblogs.com/funnyzpc/p/10801470.html</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 76, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;">异步API</span></h4> <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, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, 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;">对于多任务耗时的业务场景,一般我们会用到线程异步处理,在以前我们用 Thread 或者 Runnable 来实现异步,这是oracle官方做法,不过缺点很明显</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">对于复杂业务场景需要配置线程池</p> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">代码繁杂,对于新手容易造成不必要的bug</p> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果涉及到线程锁或线程通讯就棘手了</p> </section></li> </ul> <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, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, 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;">现在,java8为我们提供了<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.047);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;box-sizing: border-box !important;overflow-wrap: break-word !important;">CompletableFuture</code>类,可以完全解决以上问题。</p> <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, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, 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> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;line-height: 26px;color: black;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: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.047);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;box-sizing: border-box !important;overflow-wrap: break-word !important;">runAsync()</code><span>&nbsp;</span>异步无参返回</p> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">样例:</p> </section></li> </ul> <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(171, 178, 191);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@Test<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">public&nbsp;void&nbsp;asyncThread()throws&nbsp;Exception{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;CompletableFuture&nbsp;async1&nbsp;=&nbsp;CompletableFuture.runAsync(()-&gt;{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(1000);<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(Thread.currentThread().getName());<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"none&nbsp;return&nbsp;Async"</span>);<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch&nbsp;(Exception&nbsp;e){<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;});<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;调用get()将等待异步逻辑处理完成<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;async1.get();<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;"></code></pre> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;line-height: 26px;color: black;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: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.047);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;box-sizing: border-box !important;overflow-wrap: break-word !important;">supplyAsync()</code><span>&nbsp;</span>异步有参返回</p> </section></li> <li style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;line-height: 26px;color: black;box-sizing: border-box !important;overflow-wrap: break-word !important;">样例:</p> </section></li> </ul> <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(171, 178, 191);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@Test<br style="max-width: 100%;box-sizin

shell定时备份MySQL数据并解决 Using a password on the command line ...

作者:じ☆ve不哭

> mysql: [Warning] Using a password on the command line interface can be insecure 在MySQL5.6+以上版本直接在shell中输入密码会提示次警告且无法连接成功,那我们应该怎么解决这个问题呢,答案就是使用 mysql_config_editor创建一个填写账号密码的隐藏配置文件登录时使用--login-path来引用 ## 1、使用mysql_config_editor配置账号密码 ``` mysql_config_editor set --login-path=xxx --host=xxxxx --port=3306 --user=root --password ``` **注意host在阿里云服务器上且用rds时使用内网ip** ## 2、mysqldump使用 ``` mysqldump --login-path=xxx 数据库名称 > /tmp/导出的文件名称.sql ``` **此处的login-path对应第一步的名称** ## 3、完整的导出表名并自动上传到oss ``` #!/bin/bash PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH Date=`date +%Y-%m-%d_%H:%M:%S` BucketTime=`date +%Y%m` OldDate=$(date -d "-7 days" "+%Y-%m-%d") ###oss的地址### Host="oss-cn-xxxx.aliyuncs.com" ###bucket名字### Bucket="Bucket的名称" ###Access ID### Id="xxx" ###Access Key### Key="xxx" ### oss地址### OssHost=$Bucket.$Host ### 第一步时指定login-path的xxx LoginPath="xxx" ###备份数据库账号信息### grep -v 输出排除命令意思是mysql和information_schema不输出 DBS=`mysql --login-path=$LoginPath -Bse "show databases" | grep -v "information_schema" | grep -v "mysql"` ###罗列数据库信息### #========================BackUp SQL======================== for dbName in $DBS; do mysqldump --login-path=$LoginPath --set-gtid-purged=OFF $dbName > /tmp/$dbName.$Date.sql ###zip压缩设置的密码### # zip -P 密码 /tmp/$dbName.$Date.sql.zip /tmp/$dbName.$Date.sql zip /tmp/$dbName.$Date.sql.zip /tmp/$dbName.$Date.sql sendData="数据库[$dbName]在$Date执行备份, 操作结果:" if [ -s /tmp/$dbName.$Date.sql.zip ] ; then source="/tmp/$dbName.$Date.sql.zip" dest="$BucketTime/$dbName.$Date.sql.zip" resource="/${Bucket}/${dest}" contentType=`file -ib ${source} |awk -F ";" '{print $1}'` dateValue="`TZ=GMT env LANG=en_US.UTF-8 date +'%a, %d %b %Y %H:%M:%S GMT'`" stringToSign="PUT\n\n${contentType}\n${dateValue}\n${resource}" signature=`echo -en $stringToSign | openssl sha1 -hmac ${Key} -binary | base64` url=http://${OssHost}/${dest} echo "upload ${source} to ${url}" curl -i -q -X PUT -T "${source}" \ -H "Host: ${OssHost}" \ -H "Date: ${dateValue}" \ -H "Content-Type: ${contentType}" \ -H "Authorization: OSS ${Id}:${signature}" \ ${url} if [ $? -ne 0 ];then # echo -e ""dbName $dbName $Date Fail Upload"" | mutt -s "'dbName $dbName $Date Fail Upload'" zsljava@163.com sendData="$sendData 上传oss失败!" else # echo -e ""dbName $dbName $Date Success"" | mutt -s "'dbName $dbName $Date Success'" zsljava@163.com rm -rf /tmp/$dbName.$OldDate* sendData="$sendData 备份成功!" fi else # echo -e ""dbName $dbName $Date Fail Backup "" | mutt -s "'dbName $dbName $Date Fail Backup'" zsljava@163.com sendData="$sendData 备份失败!" fi curl --request POST \ --url 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxx' \ --header 'Content-Type: application/json' \ --header 'cache-control: no-cache' \ --data '{"msgtype": "text", "text": { "content": "'"$sendData"'" } }' done #========================BackUp SQL======================== ``` **脚本来自于互联网,自行调整部分代码,因关闭原网页后没找到原网页,所以没有注明来源。请谅解**

淘宝一面:“说一下 Spring Boot 自动装配原理呗?”

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 2px;line-height: 1.75em;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">每次问到 Spring Boot, 面试官非常喜欢问这个问题:“讲述一下 SpringBoot 自动装配原理?”。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">我觉得我们可以从以下几个方面回答:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 什么是 SpringBoot 自动装配? </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> SpringBoot 是如何实现自动装配的?如何实现按需加载? </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> 如何实现一个 Starter? </section></li> </ol> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(41, 128, 185);border-bottom: 1px solid rgb(52, 152, 219);border-top-color: rgb(52, 152, 219);border-right-color: rgb(52, 152, 219);border-left-color: rgb(52, 152, 219);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>前言</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">使用过 Spring 的小伙伴,一定有被 XML 配置统治的恐惧。即使 Spring 后面引入了基于注解的配置,我们在开启某些 Spring 特性或者引入第三方依赖的时候,还是需要用 XML 或 Java 进行显式配置。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">举个例子。没有 Spring Boot 的时候,我们写一个 RestFul Web 服务,还首先需要进行如下配置。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.6920821114369502" data-s="300,640" src="/upload/a8f696c79fc889c9d44f4a1a595600d3.png" data-type="png" data-w="1364" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">spring-servlet.xml</code></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.38205980066445183" data-s="300,640" src="/upload/bc531aa74f0d3230bcae7bc3daaad785.png" data-type="png" data-w="2408" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">但是,Spring Boot 项目,我们只需要添加相关依赖,无需配置,通过启动下面的 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">main</code> 方法即可。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.3166144200626959" data-s="300,640" src="/upload/5c303fe886a66e8ef438378b15bbd04.png" data-type="png" data-w="1276" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">并且,我们通过 Spring Boot 的全局配置文件 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">application.properties</code>或<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">application.yml</code>即可对项目进行设置比如更换端口号,配置 JPA 属性等等。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(52, 152, 219);">为什么 Spring Boot 使用起来这么酸爽呢?</strong> 这得益于其自动装配。<strong style="color: rgb(52, 152, 219);">自动装配可以说是 Spring Boot 的核心,那究竟什么是自动装配呢?</strong></p> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(41, 128, 185);border-bottom: 1px solid rgb(52, 152, 219);border-top-color: rgb(52, 152, 219);border-right-color: rgb(52, 152, 219);border-left-color: rgb(52, 152, 219);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>什么是 SpringBoot 自动装配?</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">我们现在提到自动装配的时候,一般会和 Spring Boot 联系在一起。但是,实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上,通过 SPI 的方式,做了进一步优化。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;margin: 20px 5px;quotes: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;border-left-width: 2.3px;border-left-color: rgb(52, 152, 219);color: rgb(97, 97, 97);background: rgb(236, 240, 241);"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;color: black;line-height: 26px;">SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">META-INF/spring.factories</code>文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.2553191489361702" data-s="300,640" src="/upload/bb432ccd46eb2606e2c8a135ddccc108.png" data-type="png" data-w="1222" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">在我看来,自动装配可以简单理解为:<strong style="color: rgb(52, 152, 219);">通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。</strong></p> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(41, 128, 185);border-bottom: 1px solid rgb(52, 152, 219);border-top-color: rgb(52, 152, 219);border-right-color: rgb(52, 152, 219);border-left-color: rgb(52, 152, 219);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>SpringBoot 是如何实现自动装配的?</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">我们先看一下 SpringBoot 的核心注解 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">SpringBootApplication</code> 。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="1.029585798816568" data-s="300,640" src="/upload/c78f68528febd4483ee386cd8e026322.png" data-type="png" data-w="1014" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">大概可以把 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@SpringBootApplication</code>看作是 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@Configuration</code>、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@EnableAutoConfiguration</code>、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ComponentScan</code> 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:</p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 2px;line-height: 1.75em;"> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@EnableAutoConfiguration</code>:启用 SpringBoot 的自动配置机制 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@Configuration</code>:允许在上下文中注册额外的 bean 或导入其他配置类 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ComponentScan</code>:扫描被 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@Component</code> ( <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@Service</code>, <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@Controller</code>)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">TypeExcludeFilter</code>和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">AutoConfigurationExcludeFilter</code>。 <span style="color: black;"></span> </section></li> </ul> </section> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <figure style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.24201930215293244" src="/upload/911ef2f2fdb4f5cc8a9526e0c6583471.png" data-type="png" data-w="1347" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;letter-spacing: 2px;text-align: left;white-space: normal;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@EnableAutoConfiguration</code> <span style="color: rgb(0, 0, 0);">&nbsp;是实现自动装配的重要注解,我们以这个注解入手。</span> </section> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(52, 152, 219);padding-left: 10px;border-left: 2px solid rgb(52, 152, 219);"><span style="display: none;"></span>@EnableAutoConfiguration:实现自动装配的核心注解</h3> <p style="text-align: left;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;letter-spacing: 2px;text-align: left;white-space: normal;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">EnableAutoConfiguration</code><span style="color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 2px;text-align: left;">&nbsp;只是一个简单地注解,自动装配核心功能的实现实际是通过&nbsp;</span><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;letter-spacing: 2px;text-align: left;white-space: normal;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">AutoConfigurationImportSelector</code><span style="color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 2px;text-align: left;">类。</span></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.4679860302677532" data-s="300,640" src="/upload/da21a777a4042d0e6eecfe2d02d2b510.png" data-type="png" data-w="1718" style=""></p> <p style="text-align: left;"><span style="color: black;text-align: left;">我们现在重点分析下</span><code style="text-align: left;font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">AutoConfigurationImportSelector</code><span style="color: black;text-align: left;"> 类到底做了什么?</span></p> <h3 data-tool="mdnice编辑器" style="font-size: 20px;margin-top: 1.2em;margin-bottom: 1em;font-weight: bold;color: rgb(52, 152, 219);padding-left: 10px;border-left: 2px solid rgb(52, 152, 219);"><span style="display: none;"></span>AutoConfigurationImportSelector:加载自动装配类<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">AutoConfigurationImportSelector</code>类的继承体系如下:</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.21451104100946372" data-s="300,640" src="/upload/95f2d45b7def5af2634abe18b01b0a83.png" data-type="png" data-w="3170" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">可以看出,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">AutoConfigurationImportSelector</code> 类实现了 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">ImportSelector</code>接口,也就实现了这个接口中的 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">selectImports</code>方法,该方法主要用于<strong style="color: rgb(52, 152, 219);">获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中</strong>。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/iaIdQfEric9TxiaDyUJ5pc6Or6DW2FQjgKl8pfcnsgwYhNqGjZA946jY1E1F1PANbnxS7BFP2MJPPOE8BvadTy3XQ/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">final</span>&nbsp;String[]&nbsp;NO_IMPORTS&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;String[<span style="color: #d19a66;line-height: 26px;">0</span>];<br><br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;String[]&nbsp;selectImports(AnnotationMetadata&nbsp;annotationMetadata)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;&lt;1&gt;.判断自动装配开关是否打开</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(!<span style="color: #c678dd;line-height: 26px;">this</span>.isEnabled(annotationMetadata))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;NO_IMPORTS;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #c678dd;line-height: 26px;">else</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;2&gt;.获取所有需要装配的bean</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AutoConfigurationMetadata&nbsp;autoConfigurationMetadata&nbsp;=&nbsp;AutoConfigurationMetadataLoader.loadMetadata(<span style="color: #c678dd;line-height: 26px;">this</span>.beanClassLoader);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AutoConfigurationImportSelector.AutoConfigurationEntry&nbsp;autoConfigurationEntry&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">this</span>.getAutoConfigurationEntry(autoConfigurationMetadata,&nbsp;annotationMetadata);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">这里我们需要重点关注一下<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">getAutoConfigurationEntry()</code>方法,这个方法主要负责加载自动配置类的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">该方法调用链如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.6086956521739131" src="/upload/3cec0cc22962aa2f6764ecf4de09d07b.png" data-type="png" data-w="851" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">现在我们结合<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">getAutoConfigurationEntry()</code>的源码来详细分析一下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/iaIdQfEric9TxiaDyUJ5pc6Or6DW2FQjgKl8pfcnsgwYhNqGjZA946jY1E1F1PANbnxS7BFP2MJPPOE8BvadTy3XQ/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">final</span>&nbsp;AutoConfigurationEntry&nbsp;EMPTY_ENTRY&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;AutoConfigurationEntry();<br><br><span style="line-height: 26px;">AutoConfigurationEntry&nbsp;<span style="color: #61aeee;line-height: 26px;">getAutoConfigurationEntry</span><span style="line-height: 26px;">(AutoConfigurationMetadata&nbsp;autoConfigurationMetadata,&nbsp;AnnotationMetadata&nbsp;annotationMetadata)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;1&gt;.</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(!<span style="color: #c678dd;line-height: 26px;">this</span>.isEnabled(annotationMetadata))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;EMPTY_ENTRY;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #c678dd;line-height: 26px;">else</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;2&gt;.</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AnnotationAttributes&nbsp;attributes&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">this</span>.getAttributes(annotationMetadata);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;3&gt;.</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;String&gt;&nbsp;configurations&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">this</span>.getCandidateConfigurations(annotationMetadata,&nbsp;attributes);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//&lt;4&gt;.</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configurations&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">this</span>.removeDuplicates(configurations);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set&lt;String&gt;&nbsp;exclusions&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">this</span>.getExclusions(annotationMetadata,&nbsp;attributes);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">this</span>.checkExcludedClasses(configurations,&nbsp;exclusions);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configurations.removeAll(exclusions);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configurations&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">this</span>.filter(configurations,&nbsp;autoConfigurationMetadata);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">this</span>.fireAutoConfigurationImportEvents(configurations,&nbsp;exclusions);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;AutoConfigurationImportSelector.AutoConfigurationEntry(configurations,&nbsp;exclusions);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(52, 152, 219);">第 1 步</strong>:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">判断自动装配开关是否打开。默认<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">spring.boot.enableautoconfiguration=true</code>,可在 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">application.properties</code> 或 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">application.yml</code> 中设置</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5179407176287052" src="/upload/a6beb6101e3aa0a395b89facc98eadbe.png" data-type="png" data-w="1282" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(52, 152, 219);">第 2 步</strong> :</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">用于获取<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">EnableAutoConfiguration</code>注解中的 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">exclude</code> 和 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">excludeName</code>。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.4598897734231476" data-s="300,640" src="/upload/90007cab006d58604045fc2119cca97f.png" data-type="png" data-w="3266" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(52, 152, 219);">第 3 步</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">获取需要自动装配的所有配置类,读取<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">META-INF/spring.factories</code></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/iaIdQfEric9TxiaDyUJ5pc6Or6DW2FQjgKl8pfcnsgwYhNqGjZA946jY1E1F1PANbnxS7BFP2MJPPOE8BvadTy3XQ/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories<br></code></pre> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5795971410006497" data-s="300,640" src="/upload/37f02c7e743ea5d60839e92b5d905e4d.png" data-type="png" data-w="3078" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">从下图可以看到这个文件的配置内容都被我们读取到了。<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">XXXAutoConfiguration</code>的作用就是按需加载组件。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5907093534212178" data-s="300,640" src="/upload/f48c541df7dc3c7e4f1250dea3849214.png" data-type="png" data-w="3186" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">不光是这个依赖下的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">META-INF/spring.factories</code>被读取到,所有 Spring Boot Starter 下的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">META-INF/spring.factories</code>都会被读取到。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">所以,你可以清楚滴看到, druid 数据库连接池的 Spring Boot Starter 就创建了<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">META-INF/spring.factories</code>文件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">如果,我们自己要创建一个 Spring Boot Starter,这一步是必不可少的。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5017618040873855" src="/upload/72d568b661aaa1651b17ab268219eb47.png" data-type="png" data-w="2838" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;"><strong style="color: rgb(52, 152, 219);">第 4 步</strong> :</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">到这里可能面试官会问你:“<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">spring.factories</code>中这么多配置,每次启动都要全部加载么?”。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">很明显,这是不现实的。我们 debug 到后面你会发现,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">configurations</code> 的值变小了。</p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5271966527196653" data-s="300,640" src="/upload/5f1503070470f46349f8d2b62c44906b.png" data-type="png" data-w="3346" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">因为,这一步有经历了一遍筛选,<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnXXX</code> 中的所有条件都满足,该类才会生效。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/iaIdQfEric9TxiaDyUJ5pc6Or6DW2FQjgKl8pfcnsgwYhNqGjZA946jY1E1F1PANbnxS7BFP2MJPPOE8BvadTy3XQ/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Configuration</span><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;检查相关的类:RabbitTemplate 和 Channel是否存在</span><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;存在才会加载</span><br><span style="color: #61aeee;line-height: 26px;">@ConditionalOnClass</span>({&nbsp;RabbitTemplate<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>,&nbsp;<span style="color: #e6c07b;line-height: 26px;">Channel</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>&nbsp;})<br>@<span style="color: #e6c07b;line-height: 26px;">EnableConfigurationProperties</span>(<span style="color: #e6c07b;line-height: 26px;">RabbitProperties</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>)<br>@<span style="color: #e6c07b;line-height: 26px;">Import</span>(<span style="color: #e6c07b;line-height: 26px;">RabbitAnnotationDrivenConfiguration</span>.<span style="color: #e6c07b;line-height: 26px;">class</span>)<br><span style="color: #e6c07b;line-height: 26px;">public</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">RabbitAutoConfiguration</span>&nbsp;</span>{<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">有兴趣的童鞋可以详细了解下 Spring Boot 提供的条件注解</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnBean</code>:当容器里有指定 Bean 的条件下 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnMissingBean</code>:当容器里没有指定 Bean 的情况下 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnSingleCandidate</code>:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnClass</code>:当类路径下有指定类的条件下 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnMissingClass</code>:当类路径下没有指定类的条件下 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnProperty</code>:指定的属性是否有指定的值 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnResource</code>:类路径是否有指定的值 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnExpression</code>:基于 SpEL 表达式作为判断条件 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnJava</code>:基于 Java 版本作为判断条件 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnJndi</code>:在 JNDI 存在的条件下差在指定的位置 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnNotWebApplication</code>:当前项目不是 Web 项目的条件下 </section></li> <li> <section style="line-height: 26px;color: rgb(1, 1, 1);margin-top: 10px;margin-bottom: 10px;"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@ConditionalOnWebApplication</code>:当前项目是 Web 项 目的条件下 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(41, 128, 185);border-bottom: 1px solid rgb(52, 152, 219);border-top-color: rgb(52, 152, 219);border-right-color: rgb(52, 152, 219);border-left-color: rgb(52, 152, 219);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>如何实现一个 Starter</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">光说不练假把式,现在就来撸一个 starter,实现自定义线程池</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">第一步,创建<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">threadpool-spring-boot-starter</code>工程</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.2692307692307692" src="/upload/6acd531ad4794b6d6f54ed7ac74e2e44.png" data-type="png" data-w="598" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">第二步,引入 Spring Boot 相关依赖</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7366666666666667" src="/upload/a177ae54c5033011fe16f10565f7f11f.png" data-type="png" data-w="900" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">第三步,创建<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">ThreadPoolAutoConfiguration</code></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4368932038834951" src="/upload/35ec3dd1ce7d5a66d69d7f33666385a7.png" data-type="png" data-w="1751" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">第四步,在<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">threadpool-spring-boot-starter</code>工程的 resources 包下创建<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">META-INF/spring.factories</code>文件</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4416243654822335" src="/upload/61da9aed7d67cc6017eeef038b271fe6.png" data-type="png" data-w="985" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">最后新建工程引入<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">threadpool-spring-boot-starter</code></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8562753036437247" src="/upload/326842a39ac81480168535b2e1b57078.png" data-type="png" data-w="988" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">测试通过!!!</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4297566371681416" src="/upload/8b648ac228c729ac77ee9899a29f8a69.png" data-type="png" data-w="1808" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <h2 data-tool="mdnice编辑器" style="min-height: 32px;line-height: 28px;color: rgb(41, 128, 185);border-bottom: 1px solid rgb(52, 152, 219);border-top-color: rgb(52, 152, 219);border-right-color: rgb(52, 152, 219);border-left-color: rgb(52, 152, 219);font-size: 22px;margin: 1em auto;padding-top: 0.5em;padding-bottom: 0.5em;text-align: center;width: 85%;font-weight: bold;display: flex;flex-direction: column;justify-content: center;"><span style="display: none;"></span>总结</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin: 1em 4px;">Spring Boot 通过<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@EnableAutoConfiguration</code>开启自动装配,通过 SpringFactoriesLoader 最终加载<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">META-INF/spring.factories</code>中的自动配置类实现自动装配,自动配置类其实就是通过<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">@Conditional</code>按需加载的配置类,想要其生效必须引入<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(41, 128, 185);">spring-boot-starter-xxx</code>包实现起步依赖</p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;white-space: normal;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);line-height: 26px;color: black;"><span style="color: rgb(74, 74, 74);letter-spacing: 0.544px;font-size: 15px;"><strong style="white-space: pre-line;letter-spacing: 2px;color: rgb(52, 152, 219);">推荐👍:</strong><span style="white-space: pre-line;color: black;letter-spacing: 2px;"> &nbsp;</span></span><a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzIwNDgzMzI3Mg==&amp;action=getalbum&amp;album_id=1571213952619954180&amp;token=2007747701&amp;lang=zh_CN#wechat_redirect&amp;__biz=MzIwNDgzMzI3Mg==#wechat_redirect" data-linktype="2" style="color: rgb(0, 132, 255);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;white-space: pre-line;border-bottom: 1px solid rgb(0, 132, 255);font-size: 15px;">Github掘金计划:Github上的一些优质项目搜罗</a></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;white-space: normal;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);line-height: 26px;color: black;"><span style="color: rgb(74, 74, 74);letter-spacing: 0.544px;font-size: 15px;"><strong style="white-space: pre-line;letter-spacing: 2px;color: rgb(52, 152, 219);">推荐👍:</strong></span><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&amp;mid=2247497691&amp;idx=1&amp;sn=356ec8f3cbc69c2f6e5fb4a5abd00c45&amp;chksm=cea1b810f9d63106cbedf2f38004120b17535d47ae0f14881e3b8c54293810b713b571e4a102&amp;token=2005423965&amp;lang=zh_CN&amp;scene=21#wechat_redirect" data-linktype="2" style="color: rgb(0, 132, 255);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;white-space: pre-line;border-bottom: 1px solid rgb(0, 132, 255);font-size: 15px;">V4.0 《JavaGuide 面试突击版》来啦!年初搞波大的</a></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;white-space: normal;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);line-height: 26px;color: black;"><span style="color: rgb(74, 74, 74);letter-spacing: 0.544px;font-size: 15px;"><strong style="font-size: 16px;white-space: pre-line;letter-spacing: 2px;color: rgb(52, 152, 219);">推荐👍:</strong></span><span style="color: rgb(0, 132, 255);border-bottom: 1px solid rgb(0, 132, 255);font-size: 15px;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&amp;mid=2247498120&amp;idx=1&amp;sn=0325d8b648e10e5e66a0c633d24b7f17&amp;chksm=cea1b643f9d63f55354973b9583b88c0ddbc60810dc57c3b1cc9c9a8488299bbdc90e8736783&amp;token=1568243595&amp;lang=zh_CN&amp;scene=21#wechat_redirect" data-linktype="2" style="color: rgb(0, 132, 255);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;border-bottom: 1px solid rgb(0, 132, 255);">Github,永远滴神&nbsp;</a></span></p> <p data-tool="mdnice编辑器" style="margin: 1em 4px;padding-top: 8px;padding-bottom: 8px;white-space: normal;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);line-height: 26px;color: black;"><em style="white-space: pre-line;font-size: 14px;color: rgb(231, 76, 60);">我是Guide哥,Java后端开发,拥抱开源,喜欢烹饪,自由的少年。一个喜欢分享大厂面试真题的技术人。我们下期再见!</em></p> </section>

关于加解密、加签验签的那些事

作者:微信小助手

<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 style="color: rgb(154, 154, 154);font-size: 14px;letter-spacing: 0.544px;text-align: left;background-color: rgb(255, 255, 255);">不学无数的</span><span style="color: rgb(154, 154, 154);font-size: 14px;letter-spacing: 0.544px;text-align: left;background-color: rgb(255, 255, 255);">程序员</span>,</span></p> <p style="letter-spacing: 0.5440000295639038px;white-space: normal;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-size: 14px;">链接:jianshu.com/p/5e9fe1fff6a3</span></p> </blockquote> <p style="text-align: left;"><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><span style="font-size: 15px;">面对MD5、SHA、DES、AES、RSA等等这些名词你是否有很多问号?这些名词都是什么?还有什么公钥加密、私钥解密、私钥加签、公钥验签。这些都什么鬼?或许在你日常工作没有听说过这些名词,但是一旦你要设计一个对外访问的接口,或者安全性要求高的系统,那么必然会接触到这些名词。所以加解密、加签验签对于一个合格的程序员来说是必须要掌握的一个概念。那么加解密相关的密码学真的离我们很遥远吗?其实生活中有很多常见的场景其实都用到了密码学的相关知识,我们不要把它想得太难,例如在《睡在我上铺的兄弟》这一段中作弊绕口令中,小瘪三代表A,小赤佬代表B,唉呀妈呀代表C,坑爹呀是D,这一段绕口令其实也是密码学的一种。有兴趣的小伙伴可以看一下这一片段绕口令片段。所以其实密码学与我们生活息息相关,接下来我们就一文彻底搞懂这些概念。</span></p> <p><span style="font-size: 15px;"><br></span></p> <h1 title="《睡在我上铺的兄弟》作弊绕口令片段"><span style="font-size: 14px;color: rgb(136, 136, 136);">《睡在我上铺的兄弟》作弊绕口令片段:</span></h1> <h1 title="《睡在我上铺的兄弟》作弊绕口令片段"><span style="color: rgb(136, 136, 136);font-size: 14px;">h<span style="font-size: 14px;color: rgb(136, 136, 136);font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">ttps://www.bilibili.com/video/av3696396/</span></span></h1> <p><br><span style="font-size: 15px;"></span></p> <h2><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">没有硝烟的战场——浅谈密码技术</span></strong></span></h2> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="color: rgb(136, 136, 136);font-size: 14px;">没有根基也许可以建一座小屋,但绝对不能造一座坚固的大厦。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">密码这个词有很多种的解释,在现代社会如果不接触编程的话,那么普遍的认为是我们设置的登录密码、或者是去银行取钱时输入的数字。都是我们在注册时实现给提供服务的一方存储一组数字,以后我们登录的时候就用这组数字相当于就证明了我们的身份。这个数字通常来说就是叫做密码。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">而我们需要了解的不是上面说的密码,而是一种“密码术”,就是对于要传递的信息按照某种规则进行转换,从而隐藏信息的内容。这种方法可以使机密信息得以在公开的渠道传递而不泄密。使用这种方法,要经过加密过程。在加密过程中我们需要知道下面的这些概念:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <ul class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"><p style="text-align: left;"><strong><span style="font-size: 15px;">原文</span></strong><span style="font-size: 15px;">:或者叫明文,就是被隐藏的文字。</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><strong><span style="font-size: 15px;">加密法</span></strong><span style="font-size: 15px;">:指隐藏原文的法则。</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><strong><span style="font-size: 15px;">密文</span></strong><span style="font-size: 15px;">:或者叫伪文,指对原文按照加密法处理过后生成的可公开传递的文字。</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><strong><span style="font-size: 15px;">密钥</span></strong><span style="font-size: 15px;">:在加密法中起决定性的因素,可能是数字、词汇,也可能是一些字母,或者这些东西的组合。</span></p></li> </ul> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">加密的结果生成了密文,要想让接受者能够读懂这些密文,那么就要把加密法以及密钥告诉接受者,否者接受者无法对密文解密,也就无法读懂原文。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">从历史的角度来看,密码学大概可以分为古典密码学和近现代密码学两个阶段。两者以现代信息技术的诞生为分界点,现在所讨论的密码学多指的是后者,建立在信息论和数学成果基础之上的。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3 style=""><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">古典密码学</span></strong></span></h3> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">古典密码学源自于数千年前,最早在公元前 1900 年左右的古埃及,就出现了通过使用特殊字符和简单替换式密码来保护信息。美索不达米亚平原上曾经出土一个公元前 1500 年左右的泥板,其上记录了加密描述的陶瓷器上釉的工艺配方。古希腊时期(公元前 800 ﹣前 146 年)还发明了通过物理手段来隐藏信息的“隐写术”,例如使用牛奶书写、用蜡覆盖文字等。后来在古罗马时期还出现了基于替换加密的凯撒密码,据称凯撒曾用此方法与其部下通信而得以命名。这些手段多数是采用简单的机械工具来保护秘密,在今天看来毫无疑问是十分简陋,很容易猜出来的。严格来看,可能都很难称为密码科学。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">凯撒密码是当偏移量是 3 的时候,所有的字母都 A 都将被替换成 D,B 变成 E,以此类推。</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: justify;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.41823899371069184" data-s="300,640" src="/upload/9f2c865b1efeec818d0fa7edbc4a2d6.png" data-type="png" data-w="636" style="width: 311px;height: 130px;"></p> <p style="text-align: left;"><br></p> <p style="text-align: center;"><span style="font-size: 12px;color: rgb(136, 136, 136);">凯撒密码</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h3><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">近代密码学</span></strong></span></h3> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">近代密码学的研究来自于第一、二次世界大战中对于军事通信进行保护和猜出来的需求。1901年12月,意大利的工程师 Guglielmo Marconi(奎里亚摩•马可尼)成功完成了跨越大西洋的无线电通信的实验,在全球范围内引发轰动,推动了无线电通信时代的到来。无线电大大提高了远程通信的能力,但是它有一个天然的缺陷——很难限制接收方,这就意味着你所传的信息有可能被拦截,因此就催生了加密技术的发展。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">对于无线电信息进行加密和解密也直接促进了近现代密码学和计算机技术的出现。反过来这些科技进步也影响了时代的发展。一战时期德国外交部长 Arthur Zimmermann(阿瑟•齐默尔曼)拉拢墨西哥构成抗美军事同盟的电报(1917年1月16日)被英国情报机构— 40 号办公室破译,直接导致了美国的参战;二战时期德国使用的恩尼格玛(Enigma)密码机(当时最先进的加密设备)被盟军成功破译(1939年到1941年),导致大西洋战役德国失败。据称,二战时期光英国从事密码学研究的人员就达到 7000 人,而他们的成果使二战结束的时间至少提前了一到两年时间。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">接下来就是可以称之为是密码学发展史上里程碑的事件了。1945年9月1日,Claude Elwood Shannon(克劳德•艾尔伍德•香农)完成了划时代的内部报告《A Mathematical Theory of Cryptography(密码术的一个数学理论)》,1949 年 10 月,该报告以《Communication Theory of Secrecy Systems(保密系统的通信理论)》为题在 Bell System Technical Journal(贝尔系统技术期刊)上正式发表。这篇论文首次将密码学和信息论联系到一起,为<strong>对称密码技术</strong>提供了数学基础。这也标志着近现代密码学的正式建立。这也是密码学发展史上的第一座里程碑性事件。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">密码学发展史上的第二个里程碑性事件是 DES 的出现。DES 全称为 Data Encryption Standard,即数据加密标准,是一种使用密钥加密的分组密码算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">密码学发展史上的第三个里程碑性事件就是我们区块链中广泛应用的公钥密码,也就是<strong>非对称密码</strong>算法的出现。1976年11月,Whitfield Diffie 和 Martin E.Hellman 在 IEEE Transactions on Information Theory 上发表了论文《New Directions in Cryptography(密码学的新方向)》,探讨了无需传输密钥的保密通信和签名认证体系问题,正式开创了现代公钥密码学体系的研究。在公钥密码发现以前,如果需要保密通信,通信双方事先要对加解密的算法以及要使用的密钥进行事先协商,包括送鸡毛信,实际上是在传送密钥。但自从有了公钥密码,需要进行秘密通信的双方不再需要进行事前的密钥协商了。公钥密码在理论上是不保密的,在实际上是保密的。也就是说,公钥密码是可以猜出来的,但需要极长的时间,等到猜出来了,这个秘密也没有保密的必要了。</span></p> <p><br></p> <p style="text-align: left;"><span style="font-size: 15px;">上面我们说到了关于近现代的密码学相关的东西,基本上总结下来我们现在常用的就两个,一个是<strong>对称加密算法</strong>,一个是<strong>非对称加密算法</strong>。那么接下来我们就以介绍这两个概念为主线引出开题中我们提到的概念。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h2 style=""><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">程序实现</span></strong></span></h2> <h3 style="text-align: left;"><br></h3> <h3 style="text-align: left;"><strong><span style="font-size: 15px;">对称加密算法</span></strong><span style="font-size: 15px;"></span></h3> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">对称加密指的就是加密和解密使用同一个秘钥,所以叫做对称加密。对称加密只有一个秘钥,作为私钥。具体的算法有:DES、3DES、TDEA、Blowfish、RC5、IDEA。但是我们常见的有:DES、AES 等等。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">那么对称加密的优点是什么呢?算法公开、计算量小、加密速度快、加密效率高。缺点就是秘钥的管理和分发是非常困难的,不够安全。在数据传送前,发送方和接收方必须商定好秘钥,然后双方都必须要保存好秘钥,如果一方的秘钥被泄露了,那么加密的信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘钥,这会使得收、发双方所拥有的的钥匙数量巨大,秘钥管理也会成为双方的负担。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">加密的过程我们可以理解为如下:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <ul class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"><p style="text-align: left;"><span style="font-size: 15px;">加密:原文+秘钥 = 密文</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-size: 15px;">解密:密文-秘钥 = 原文</span></p></li> </ul> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">可以看到两次过程使用的都是一个秘钥。用图简单表示如下:</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.3921875" data-s="300,640" src="/upload/233de2af6cdc80e3dc11b75bea1344d1.png" data-type="png" data-w="1280" style=""></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h4><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">实战演练</span></strong></span></h4> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-size: 15px;">既然我们知道关于对称加密算法的相关知识,那么我们日常用 Java 如何实现对称加密的加密和解密动作呢?常见的对称加密算法有:DES、AES 等。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <h5 style="text-align: left;"><strong><span style="font-size: 15px;">DES</span></strong><span style="font-size: 15px;"></span></h5> <p><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">DES 加密算法是一种分组密码,以 64 位为分组对数据加密,它的密钥长度是 56 位,加密解密用同一算法。DES 加密算法是对密钥进行保密,而公开算法,包括加密和解密算法。这样,只有掌握了和发送方相同密钥的人才能解读由 DES 加密算法加密的密文数据。因此,破译 DES 加密算法实际上就是搜索密钥的编码。对于 56 位长度的密钥来说,如果用穷举法来进行搜索的话,其运算次数为 2 的 56 次方。</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-size: 15px;">接下来用 Java 实现 DES 加密</span></p> <p style="text-align: left;"><span style="font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="java"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">final</span> <span class="code-snippet__keyword">static</span> String DES = <span class="code-snippet__string">"DES"</span>;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">main</span><span class="code-snippet__params">(String[] args)</span> <span class="code-snippet__keyword">throws</span> Exception </span>{</span></code><code><span class="code-snippet_outer"> String data = <span class="code-snippet__string">"123 456"</span>;</span></code><code><span class="code-snippet_outer"> String key = <span class="code-snippet__string">"wang!@#$"</span>;</span></code><code><span class="code-snippet_outer"> System.err.println(encrypt(data, key));</span></code><code><span class="code-snippet_outer"> System.err.println(decrypt(encrypt(data, key), key));</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * Description 根据键值进行加密</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> data</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> key 加密键byte数组</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@return</span></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@throws</span> Exception</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__keyword">static</span> String <span class="code-snippet__title">encrypt</span><span class="code-snippet__params">(String data, String key)</span> <span class="code-snippet__keyword">throws</span> Exception </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">byte</span>[] bt = encrypt(data.getBytes(), key.getBytes());</span></code><code><span class="code-snippet_outer"> String strs = <span class="code-snippet__keyword">new</span> BASE64Encoder().encode(bt);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> strs;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * Description 根据键值进行解密</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> data</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> key 加密键byte数组</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@return</span></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@throws</span> IOException</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@throws</span> Exception</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__keyword">static</span> String <span class="code-snippet__title">decrypt</span><span class="code-snippet__params">(String data, String key)</span> <span class="code-snippet__keyword">throws</span> IOException,</span></span></code><code><span class="code-snippet_outer"> Exception </span></code><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (data == <span class="code-snippet__keyword">null</span>)</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">null</span>;</span></code><code><span class="code-snippet_outer"> BASE64Decoder decoder = <span class="code-snippet__keyword">new</span> BASE64Decoder();</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">byte</span>[] buf = decoder.decodeBuffer(data);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">byte</span>[] bt = decrypt(buf,key.getBytes());</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">new</span> String(bt);</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * Description 根据键值进行加密</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> data</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> key 加密键byte数组</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@return</span></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@throws</span> Exception</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">byte</span>[] encrypt(<span class="code-snippet__keyword">byte</span>[] data, <span class="code-snippet__keyword">byte</span>[] key) <span class="code-snippet__keyword">throws</span> Exception {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 生成一个可信任的随机数源</span></span></code><code><span class="code-snippet_outer"> SecureRandom sr = <span class="code-snippet__keyword">new</span> SecureRandom();</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 从原始密钥数据创建DESKeySpec对象</span></span></code><code><span class="code-snippet_outer"> DESKeySpec dks = <span class="code-snippet__keyword">new</span> DESKeySpec(key);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象</span></span></code><code><span class="code-snippet_outer"> SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);</span></code><code><span class="code-snippet_outer"> SecretKey securekey = keyFactory.generateSecret(dks);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// Cipher对象实际完成加密操作</span></span></code><code><span class="code-snippet_outer"> Cipher cipher = Cipher.getInstance(DES);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 用密钥初始化Cipher对象</span></span></code><code><span class="code-snippet_outer"> cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> cipher.doFinal(data);</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * Description 根据键值进行解密</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> data</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> key 加密键byte数组</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@return</span></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@throws</span> Exception</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">byte</span>[] decrypt(<span class="code-snippet__keyword">byte</span>[] data, <span class="code-snippet__keyword">byte</span>[] key) <span class="code-snippet__keyword">throws</span> Exception {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 生成一个可信任的随机数源</span></span></code><code><span class="code-snippet_outer"> SecureRandom sr = <span class="code-snippet__keyword">new</span> SecureRandom();</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 从原始密钥数据创建DESKeySpec对象</span></span></code><code><span class="code-snippet_outer"> DESKeySpec dks = <span class="code-snippet__keyword">new</span> DESKeySpec(key);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象</span></span></code><code><span class="code-snippet_outer"> SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);</span></code><code><span class="code-snippet_outer"> SecretKey securekey = keyFactory.generateSecret(dks);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// Cipher对象实际完成解密操作</span></span></code><code><span class="code-snippet_outer"> Cipher cipher = Cipher.getInstance(DES);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 用密钥初始化Cipher对象</span></span></code><code><span class="code-snippet_outer"> cipher.init(Cipher.DECRYPT_MODE, securekey, sr);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> cipher.doFinal(data);</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><span style="font-size: 15px;"></span></p> <p style="text-align: left;"><br></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">输出以后可以看到数据被加密了:</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="properties"><code><span class="code-snippet_outer"><span class="code-snippet__meta">5fiw/XhRJ0E</span>=<span class="code-snippet__string"></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attr">123</span> <span class="code-snippet__string">456</span></span></code></pre> </section> <p style="text-align: left;"><br><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"></span></p> <pre><code><span aria-hidden="true"></span></code></pre> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">在 Java 中用 DES 加密有一个<strong>特殊的地方</strong>:</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <ol class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">秘钥设置的长度必须大于等于 8。</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">秘钥设置的长度如果大于 8 的话,那么只会取前 8 个字节作为秘钥。</span></p></li> </ol> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">为什么呢,我们可以看到在初始化 DESKeySpec 类的时候有下面一段,其中 var1 是我们传的秘钥。可以看到它进行了截取,只截取前八个字节。</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="java"><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__title">DESKeySpec</span><span class="code-snippet__params">(<span class="code-snippet__keyword">byte</span>[] var1, <span class="code-snippet__keyword">int</span> var2)</span> <span class="code-snippet__keyword">throws</span> InvalidKeyException </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (var1.length - var2 &lt; <span class="code-snippet__number">8</span>) {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">throw</span> <span class="code-snippet__keyword">new</span> InvalidKeyException(<span class="code-snippet__string">"Wrong key size"</span>);</span></code><code><span class="code-snippet_outer"> } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">this</span>.key = <span class="code-snippet__keyword">new</span> <span class="code-snippet__keyword">byte</span>[<span class="code-snippet__number">8</span>];</span></code><code><span class="code-snippet_outer"> System.arraycopy(var1, var2, <span class="code-snippet__keyword">this</span>.key, <span class="code-snippet__number">0</span>, <span class="code-snippet__number">8</span>);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <p style="text-align: left;"><strong><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">AES</span></strong><br><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"></span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">AES 加密算法是密码学中的高级加密标准,该加密算法采用对称分组密码体制,密钥长度的最少支持为 128、192、256,分组长度 128 位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的区块加密标准,AES 标准用来替代原先的 DES,已经被多方分析且广为全世界所使用。</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">JCE(Java Cryptography Extension)在早期JDK版本中,由于受美国的密码出口条例约束,Java 中涉及加解密功能的 API 被限制出口,所以 Java 中安全组件被分成了两部分: 不含加密功能的 JCA(Java Cryptography Architecture )和含加密功能的 JCE(Java Cryptography Extension)。</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">JCE 的 API 都在 javax.crypto 包下,核心功能包括:加解密、密钥生成(对称)、MAC 生成、密钥协商。</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">加解密功能由 Cipher 组件提供,其也是 JCE 中最核心的组件。</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">在设置 Cipher 类的时候有几个<strong>注意点</strong>:</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <ol class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">Cipher 在使用时需以参数方式指定 transformation。</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">transformation 的格式为 algorithm/mode/padding,其中 algorithm 为必输项,如: AES/DES/CBC/PKCS5Padding,具体有哪些可看下表。</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">缺省的 mode 为 ECB,缺省的 padding 为 PKCS5Padding。</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">在 block 算法与流加密模式组合时, 需在 mode 后面指定每次处理的 bit 数, 如 DES/CFB8/NoPadding, 如未指定则使用缺省值, SunJCE 缺省值为 64bits。</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">Cipher 有 4 种操作模式:ENCRYPT_MODE(加密)、DECRYPT_MODE(解密)、WRAP_MODE(导出Key)、UNWRAP_MODE(导入Key),初始化时需指定某种操作模式。</span></p></li> </ol> <p style="text-align: left;"><br></p> <table> <thead> <tr> <th><span style="font-size: 15px;">算法/模式/填充</span></th> <th><span style="font-size: 15px;">16字节加密后数据长度</span></th> <th><span style="font-size: 15px;">不满16字节加密后长度</span></th> </tr> </thead> <tbody> <tr> <td><span style="font-size: 15px;">AES/CBC/NoPadding</span></td> <td><span style="font-size: 15px;">16</span></td> <td><span style="font-size: 15px;">不支持</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/CBC/PKCS5Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/CBC/ISO10126Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/CFB/NoPadding</span></td> <td><span style="font-size: 15px;">16</span></td> <td><span style="font-size: 15px;">原始数据长度</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/CFB/PKCS5Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/CFB/ISO10126Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/ECB/NoPadding</span></td> <td><span style="font-size: 15px;">16</span></td> <td><span style="font-size: 15px;">不支持</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/ECB/PKCS5Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/ECB/ISO10126Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/OFB/NoPadding</span></td> <td><span style="font-size: 15px;">16</span></td> <td><span style="font-size: 15px;">原始数据长度</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/OFB/PKCS5Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/OFB/ISO10126Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/PCBC/NoPadding</span></td> <td><span style="font-size: 15px;">16</span></td> <td><span style="font-size: 15px;">不支持</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/PCBC/PKCS5Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> <tr> <td><span style="font-size: 15px;">AES/PCBC/ISO10126Padding</span></td> <td><span style="font-size: 15px;">32</span></td> <td><span style="font-size: 15px;">16</span></td> </tr> </tbody> </table> <p><br></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">秘钥的可以由我们自己定义,也可以是由AES自己生成,当自己定义是需要是要注意:</span></p> <p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;"><br></span></p> <ol class="list-paddingleft-2" style="text-align: left;"> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;">根据 AES 规范,可以是 16 字节、24 字节和32 字节长,分别对应 128 位、192 位和 256 位;</span></p></li> <li style="text-align: left;"><p style="text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont,

ElasticSearch 面试 4 连炮,你顶得住么?

作者:微信小助手

<section mpa-paragraph-type="ignored" data-mpa-powered-by="yiban.io"> <p data-lake-id="f47942fff38c686ed626a530b6d84219" style="text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><span data-mce-style="font-size: 10px" style="font-size: 13px;"><span style="color: #888888;">点击上方蓝色“</span></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;"><span style="color: #888888;">”,选择“设为星标”</span></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: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><img class="rich_pages" data-ratio="0.5628517823639775" data-s="300,640" src="/upload/6f834be74fd5a60d8ec1b0debd737ccc.null" data-type="jpeg" data-w="533" style="inset: auto;"><br></p> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style=""> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" textvalue="面试题" tab="innerlink" data-linktype="2"></a> <br> </section> <hr data-tool="mdnice编辑器" style="height: 1px;margin-top: 10px;margin-bottom: 10px;border-right: none;border-bottom: none;border-left: none;border-top-style: solid;border-top-color: black;"> <h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;">面试题</h1> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">es 写入数据的工作原理是什么啊?es 查询数据的工作原理是什么啊?底层的 lucene 介绍一下呗?倒排索引了解吗?</p> <h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;">面试官心理分析</h1> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">问这个,其实面试官就是要看看你了解不了解 es 的一些基本原理,因为用 es 无非就是写入数据,搜索数据。你要是不明白你发起一个写入和搜索请求的时候,es 在干什么,那你真的是......</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对 es 基本就是个黑盒,你还能干啥?你唯一能干的就是用 es 的 api 读写数据了。要是出点什么问题,你啥都不知道,那还能指望你什么呢?</p> <h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 24px;">面试题剖析</h1> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;">es 写数据过程</h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">客户端选择一个 node 发送请求过去,这个 node 就是 <code style="">coordinating node</code>(协调节点)。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;"><code style="">coordinating node</code> 对 document 进行<strong>路由</strong> ,将请求转发给对应的 node(有 primary shard)。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">实际的 node 上的 <code style="">primary shard</code> 处理请求,然后将数据同步到 <code style="">replica node</code>。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZfeuVTCgib6jttDV1FibpUNxf7CRLBXwPpP3SDDjrtIicX3e1uo4II7ia2yMsic4OyhY9MBGyUuCKL0YNeA/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="">coordinating&nbsp;node<br></code></pre> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">如果发现</p> <pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZfeuVTCgib6jttDV1FibpUNxf7CRLBXwPpP3SDDjrtIicX3e1uo4II7ia2yMsic4OyhY9MBGyUuCKL0YNeA/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="">primary&nbsp;node<br></code></pre> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">和所有</p> <pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZfeuVTCgib6jttDV1FibpUNxf7CRLBXwPpP3SDDjrtIicX3e1uo4II7ia2yMsic4OyhY9MBGyUuCKL0YNeA/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="">replica&nbsp;node<br></code></pre> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">都搞定之后,就返回响应结果给客户端。</p> <figure style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-cropselx1="27" data-cropselx2="506" data-cropsely1="0" data-cropsely2="238" data-ratio="0.43466666666666665" src="/upload/ab41563c531aa71160d1b2d016c98d45.png" data-type="png" data-w="750" style="display: block;margin-right: auto;margin-left: auto;width: 548px;height: 238px;"> </figure> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">es-write</p> </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;">es 读数据过程</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以通过 <code style="">doc id</code> 来查询,会根据 <code style="">doc id</code> 进行 hash,判断出来当时把 <code style="">doc id</code> 分配到了哪个 shard 上面去,从那个 shard 去查询。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 客户端发送请求到 <strong style="color: black;">任意</strong> 一个 node,成为 <code style="">coordinate node</code>。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="">coordinate node</code> 对 <code style="">doc id</code> 进行哈希路由,将请求转发到对应的 node,此时会使用 <code style="">round-robin</code> <strong style="color: black;">随机轮询算法</strong> ,在 <code style="">primary shard</code> 以及其所有 replica 中随机选择一个,让读请求负载均衡。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 接收请求的 node 返回 document 给 <code style="">coordinate node</code>。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="">coordinate node</code> 返回 document 给客户端。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;">es 搜索数据过程</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">es 最强大的是做全文检索,就是比如你有三条数据:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/JdLkEI9sZfeuVTCgib6jttDV1FibpUNxf7CRLBXwPpP3SDDjrtIicX3e1uo4II7ia2yMsic4OyhY9MBGyUuCKL0YNeA/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">java真好玩儿啊<br>java好难学啊<br>j2ee特别牛<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">你根据 <code style="">java</code> 关键词来搜索,将包含 <code style="">java</code>的 <code style="">document</code> 给搜索出来。es 就会给你返回:java真好玩儿啊,java好难学啊。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 客户端发送请求到一个 <code style="">coordinate node</code>。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 协调节点将搜索请求转发到 <strong style="color: black;">所有</strong> 的 shard 对应的 <code style="">primary shard</code> 或 <code style="">replica shard</code>,都可以。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> query phase:每个 shard 将自己的搜索结果(其实就是一些 <code style="">doc id</code>)返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> fetch phase:接着由协调节点根据 <code style="">doc id</code> 去各个节点上 <strong style="color: black;">拉取实际</strong> 的 <code style="">document</code> 数据,最终返回给客户端。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;">写数据底层原理</h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-cropselx1="26" data-cropselx2="528" data-cropsely1="0" data-cropsely2="334" data-ratio="0.6025280898876404" src="/upload/a2c4e575d3dfbf71b2f0bed5d9a4a1a8.png" data-type="png" data-w="712" style="display: block;margin-right: auto;margin-left: auto;width: 554px;height: 334px;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">es-write-detail</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">先写入内存 buffer,在 buffer 里的时候数据是搜索不到的;同时将数据写入 translog 日志文件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果 buffer 快满了,或者到一定时间,就会将内存 buffer 数据 <code style="">refresh</code> 到一个新的 <code style="">segment file</code> 中,但是此时数据不是直接进入 <code style="">segment file</code> 磁盘文件,而是先进入 <code style="">os cache</code> 。这个过程就是 <code style="">refresh</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">每隔 1 秒钟,es 将 buffer 中的数据写入一个<strong>新的</strong> <code style="">segment file</code>,每秒钟会产生一个<strong>新的磁盘文件</strong> <code style="">segment file</code>,这个 <code style="">segment file</code> 中就存储最近 1 秒内 buffer 中写入的数据。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">但是如果 buffer 里面此时没有数据,那当然不会执行 refresh 操作,如果buffer里面有数据,默认 1 秒钟执行一次 refresh 操作,刷入一个新的 segment file 中。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">操作系统里面,磁盘文件其实都有一个东西,叫做 <code style="">os cache</code>,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入 <code style="">os cache</code>,先进入操作系统级别的一个内存缓存中去。只要 <code style="">buffer</code> 中的数据被 refresh 操作刷入 <code style="">os cache</code>中,这个数据就可以被搜索到了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为什么叫 es 是<strong>准实时</strong> 的?<code style="">NRT</code>,全称 <code style="">near real-time</code>。默认是每隔 1 秒 refresh 一次的,所以 es 是准实时的,因为写入的数据 1 秒之后才能被看到。可以通过 es 的 <code style="">restful api</code> 或者 <code style="">java api</code>,<strong>手动</strong> 执行一次 refresh 操作,就是手动将 buffer 中的数据刷入 <code style="">os cache</code>中,让数据立马就可以被搜索到。只要数据被输入 <code style="">os cache</code> 中,buffer 就会被清空了,因为不需要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">重复上面的步骤,新的数据不断进入 buffer 和 translog,不断将 <code style="">buffer</code> 数据写入一个又一个新的 <code style="">segment file</code> 中去,每次 <code style="">refresh</code> 完 buffer 清空,translog保留。随着这个过程推进,translog 会变得越来越大。当 translog 达到一定长度的时候,就会触发 <code style="">commit</code> 操作。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">commit 操作发生第一步,就是将 buffer 中现有数据 <code style="">refresh</code> 到 <code style="">os cache</code> 中去,清空 buffer。然后,将一个 <code style="">commit point</code> 写入磁盘文件,里面标识着这个 <code style="">commit point</code> 对应的所有 <code style="">segment file</code>,同时强行将 <code style="">os cache</code> 中目前所有的数据都 <code style="">fsync</code> 到磁盘文件中去。最后<strong>清空</strong> 现有 translog 日志文件,重启一个 translog,此时 commit 操作完成。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这个 commit 操作叫做 <code style="">flush</code>。默认 30 分钟自动执行一次 <code style="">flush</code>,但如果 translog 过大,也会触发 <code style="">flush</code>。flush 操作就对应着 commit 的全过程,我们可以通过 es api,手动执行 flush 操作,手动将 os cache 中的数据 fsync 强刷到磁盘上去。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">translog 日志文件的作用是什么?你执行 commit 操作之前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,无论是 buffer 还是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。所以需要将数据对应的操作写入一个专门的日志文件 <code style="">translog</code> 中,一旦此时机器宕机,再次重启的时候,es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会<strong>丢失</strong> 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写操作必须是直接 <code style="">fsync</code> 到磁盘,但是性能会差很多。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">实际上你在这里,如果面试官没有问你 es 丢数据的问题,你可以在这里给面试官炫一把,你说,其实 es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的<strong>数据丢失</strong> 。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;border-left-color: rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">数据写入 segment file 之后,同时就建立好了倒排索引。</p> </blockquote> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;">删除/更新数据底层原理</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果是删除操作,commit 的时候会生成一个 <code style="">.del</code> 文件,里面将某个 doc 标识为 <code style="">deleted</code> 状态,那么搜索的时候根据 <code style="">.del</code> 文件就知道这个 doc 是否被删除了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果是更新操作,就是将原来的 doc 标识为 <code style="">deleted</code> 状态,然后新写入一条数据。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">buffer 每次 refresh 一次,就会产生一个 <code style="">segment file</code>,所以默认情况下是 1 秒钟一个 <code style="">segment file</code>,这样下来 <code style="">segment file</code> 会越来越多,此时会定期执行 merge。每次 merge 的时候,会将多个 <code style="">segment file</code> 合并成一个,同时这里会将标识为 <code style="">deleted</code> 的 doc 给<strong>物理删除掉</strong> ,然后将新的 <code style="">segment file</code> 写入磁盘,这里会写一个 <code style="">commit point</code>,标识所有新的 <code style="">segment file</code>,然后打开 <code style="">segment file</code> 供搜索使用,同时删除旧的 <code style="">segment file</code>。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;">底层 lucene</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">简单来说,lucene 就是一个 jar 包,里面包含了封装好的各种建立倒排索引的算法代码。我们用 Java 开发的时候,引入 lucene jar,然后基于 lucene 的 api 去开发就可以了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过 lucene,我们可以将已有的数据建立索引,lucene 会在本地磁盘上面,给我们组织索引的数据结构。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;">倒排索引</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在搜索引擎中,每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。例如,文档 1 经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">那么,倒排索引就是<strong>关键词到文档</strong> ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">举个栗子。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">有以下文档:</p> <section data-tool="mdnice编辑器" style="overflow-x: auto;"> <table> <thead> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">DocId</th> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">Doc</th> </tr> </thead> <tbody style="border-width: 0px;border-style: initial;border-color: initial;"> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">1</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">谷歌地图之父跳槽 Facebook</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">2</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">谷歌地图之父加盟 Facebook</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">3</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">谷歌地图创始人拉斯离开谷歌加盟 Facebook</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">4</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">谷歌地图之父跳槽 Facebook 与 Wave 项目取消有关</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">5</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">谷歌地图之父拉斯加盟社交网站 Facebook</td> </tr> </tbody> </table> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对文档进行分词之后,得到以下<strong>倒排索引</strong> 。</p> <section data-tool="mdnice编辑器" style="overflow-x: auto;"> <table> <thead> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">WordId</th> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">Word</th> <th style="border-top-width: 1px;border-color: rgb(204, 204, 204);text-align: left;background-color: rgb(240, 240, 240);min-width: 85px;">DocIds</th> </tr> </thead> <tbody style="border-width: 0px;border-style: initial;border-color: initial;"> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">1</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">谷歌</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">1,2,3,4,5</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">2</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">地图</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">1,2,3,4,5</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">3</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">之父</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">1,2,4,5</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">4</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">跳槽</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">1,4</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">5</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">Facebook</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">1,2,3,4,5</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">6</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">加盟</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">2,3,5</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">7</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">创始人</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">3</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">8</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">拉斯</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">3,5</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">9</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">离开</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">3</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: rgb(248, 248, 248);"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">10</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">与</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">4</td> </tr> <tr style="border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">..</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">..</td> <td style="border-color: rgb(204, 204, 204);min-width: 85px;">..</td> </tr> </tbody> </table> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">另外,实用的倒排索引还可以记录更多的信息,比如文档频率信息,表示在文档集合中有多少个文档包含某个单词。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">那么,有了倒排索引,搜索引擎可以很方便地响应用户的查询。比如用户输入查询 <code style="">Facebook</code>,搜索系统查找倒排索引,从中读出包含这个单词的文档,这些文档就是提供给用户的搜索结果。</p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: flex;flex-flow: row nowrap;margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;vertical-align: middle;width: auto;flex: 100 100 0%;align-self: center;height: auto;box-sizing: border-box;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;transform: translate3d(0px, 0px, 1px) rotateY(180deg);box-sizing: border-box;" powered-by="xiumi.us"> <section style="background-color: rgba(194, 150, 255, 0.45);height: 1px;box-sizing: border-box;line-height: 0;"> <br> </section> </section> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section style="margin-top: 10px;margin-bottom: 10px;" mpa-from-tpl="t"> <p style="width:40%;margin-right: auto;margin-left: auto;"><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;"><span style="color: #8C8C8C;"><br></span></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(&quot;https://mmbiz.qpic.cn/mmbiz_png/sUbvrqLicbpzB81mjeBxPuxnYdalGxNnJo30L2Hq3WwGficcq8w5YJkLeXnsNHocN53k55TfN5mBpCdicGRyfDg1g/640?wx_fmt=png&quot;);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="2247492620_1" data-recommend-article-time="1611620940" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtZe5iaPydS3PGea0kOV9rqeyIVKCMkPowIQadrzryAVntr2vlcKLDkvnKsfavczJ07lp7iamDfhSgfw/0?wx_fmt=jpeg" data-recommend-article-title="如何排查系统的性能瓶颈点?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492620&amp;idx=1&amp;sn=7447a4445d55b995c888fee8ce8a300b&amp;chksm=97b47a14a0c3f302cb6463d81a355e525f02a1f9fcc5a9e2668230b6bfbb695f7216d89f7a2d#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492620&amp;idx=1&amp;sn=7447a4445d55b995c888fee8ce8a300b&amp;chksm=97b47a14a0c3f302cb6463d81a355e525f02a1f9fcc5a9e2668230b6bfbb695f7216d89f7a2d&amp;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="">如何排查系统的性能瓶颈点?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247492607_1" data-recommend-article-time="1611534540" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtZmRMTHsx0tJDJ4vYxgm4oqIO6BtyXfZKqItOXMmvGNdjx94Mria6tv7IOg7TAKOwCqic1tm4bqqqIA/0?wx_fmt=jpeg" data-recommend-article-title="虎牙二面:说说你对 Java “零拷贝”的理解?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492607&amp;idx=1&amp;sn=775fcab7e30ccbb43f5dc060c78ee96d&amp;chksm=97b47de7a0c3f4f108d1dee5c3f8f3680463a0d1e76ef029a3ba26a86cffad1533f4215d1f77#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492607&amp;idx=1&amp;sn=775fcab7e30ccbb43f5dc060c78ee96d&amp;chksm=97b47de7a0c3f4f108d1dee5c3f8f3680463a0d1e76ef029a3ba26a86cffad1533f4215d1f77&amp;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="">虎牙二面:说说你对 Java “零拷贝”的理解?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247492596_1" data-recommend-article-time="1611448140" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtagiaiahcYRaia1bSJb0HYtXkgOSdj5dWwsaicZ4VkzCLfujwFIlicg2VpqWXoykuZ09L4Looxg9PjwVWA/0?wx_fmt=jpeg" data-recommend-article-title="K8S知道,K9S呢?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492596&amp;idx=1&amp;sn=6aa7cb0d84a6b9949a283f5f657a4c5a&amp;chksm=97b47deca0c3f4fa76bee607461218c9d27bc0f28e573bd78a8eefed590adecd6df7ed206216#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492596&amp;idx=1&amp;sn=6aa7cb0d84a6b9949a283f5f657a4c5a&amp;chksm=97b47deca0c3f4fa76bee607461218c9d27bc0f28e573bd78a8eefed590adecd6df7ed206216&amp;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="">K8S知道,K9S呢?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247492585_1" data-recommend-article-time="1611361740" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/6tgwFZrjh8FGXgjgcMJ9CBbOrzy0yjPFztzBImJib40JvCdjF3tmUamtosHpvMRcRicicwOah0rRvKOnfnngUtd9g/0?wx_fmt=jpeg" data-recommend-article-title="MyBatis 流式查询,用起来还不错!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492585&amp;idx=1&amp;sn=9ffb3da2c6412e842cebb65313091636&amp;chksm=97b47df1a0c3f4e77fae4d7904f54d753bf4f816c2a668147834f51ad5ca3b665c2c3b0ed6eb#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492585&amp;idx=1&amp;sn=9ffb3da2c6412e842cebb65313091636&amp;chksm=97b47df1a0c3f4e77fae4d7904f54d753bf4f816c2a668147834f51ad5ca3b665c2c3b0ed6eb&amp;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="">MyBatis 流式查询,用起来还不错!</p> </section></a> </section> </section> </section> </section> <p><br></p> <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> <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: #8C8C8C;"><br></span></p> <section 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;margin-top: 5px;"> <span style="color: #8C8C8C;">一起进大厂,每日学干货</span> </section> <section 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;margin-top: 5px;"> <span style="color: #8C8C8C;">关注我,不迷路</span> </section> <p style="text-align: center;"><img data-ratio="1" src="/upload/7b57b8ce8a74c4aebec729d708bae61d.png" data-type="png" data-w="258"></p> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="paragraph" style="border-width: 0px;border-style: none;border-color: initial;" mpa-from-tpl="t"> <p><br></p> <section style="white-space: normal;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;box-shadow: rgb(226, 226, 226) 0px 16px 1px -13px;border-color: rgb(249, 110, 87);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&nbsp;年<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;"> ↓↓↓&nbsp; </section> </section> </section> </section> </section> <section data-mpa-template="t" mpa-paragraph-type="ignored" style="white-space: normal;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);"> <section data-role="outer" label="Powered by 135editor.com" style="font-size: 16px;font-family: 微软雅黑;"> <section data-mpa-template="t" mpa-paragraph-type="ignored" style="letter-spacing: 0.544px;"> <section data-role="outer" label="Powered by 135editor.com"> <br> </section> </section> </section> </section>

韩信大招:一致性哈希

作者:微信小助手

<p style="text-align: center;" data-mpa-powered-by="yiban.io"><img class="rich_pages" data-ratio="0.56171875" data-s="300,640" src="/upload/6509ccbbaec811291538752537bda803.jpg" data-type="jpeg" data-w="1280" style=""></p> <p data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-style="margin-top: 10px; margin-bottom: 10px; background-color: rgb(255, 255, 255); color: rgb(0, 0, 0); font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif; font-size: 16px; white-space: normal; word-spacing: 0.8px; letter-spacing: 0.75px; text-align: center; visibility: visible;" class="js_darkmode__1" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);font-size: 16px;word-spacing: 0.8px;text-align: center;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;font-size: 14px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">这是悟空的第&nbsp;</span><span data-darkmode-color-15906764299112="rgb(255, 104, 39)" data-darkmode-original-color-15906764299112="rgb(255, 104, 39)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(255, 104, 39)" data-darkmode-original-color-15958675267961="rgb(255, 104, 39)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(255, 104, 39)" data-darkmode-original-color-15965526125846="rgb(255, 104, 39)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(255, 104, 39)" data-darkmode-original-color-15969880239317="rgb(255, 104, 39)" data-darkmode-color-15976750929548="rgb(255, 104, 39)" data-darkmode-original-color-15976750929548="rgb(255, 104, 39)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(255, 104, 39)" data-darkmode-original-color-15982803404507="rgb(255, 104, 39)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;font-size: 14px;color: rgb(255, 104, 39);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">78</span><span data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;font-size: 14px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;篇原创文章</span><br data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p data-tool="mdnice编辑器" data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-style="background-color: rgb(255, 255, 255); color: rgb(0, 0, 0); font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif; font-size: 16px; white-space: normal; word-spacing: 0.8px; letter-spacing: 0.75px; text-align: center; visibility: visible;" class="js_darkmode__2" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);font-size: 16px;word-spacing: 0.8px;text-align: center;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span data-darkmode-color-15906764299112="rgb(178, 178, 178)" data-darkmode-original-color-15906764299112="rgb(178, 178, 178)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(178, 178, 178)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-style="color: rgb(178, 178, 178); font-size: 14px; visibility: visible;" class="js_darkmode__3" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(178, 178, 178)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(178, 178, 178)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(178, 178, 178)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(178, 178, 178)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;color: rgb(178, 178, 178);font-size: 14px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">作者 | 悟空聊架构</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-style="background-color: rgb(255, 255, 255); color: rgb(0, 0, 0); font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif; font-size: 16px; white-space: normal; word-spacing: 0.8px; letter-spacing: 0.75px; text-align: center; visibility: visible;" class="js_darkmode__4" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;min-height: 1em;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);font-size: 16px;word-spacing: 0.8px;text-align: center;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span data-darkmode-color-15906764299112="rgb(178, 178, 178)" data-darkmode-original-color-15906764299112="rgb(178, 178, 178)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(178, 178, 178)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-style="color: rgb(178, 178, 178); font-size: 14px; visibility: visible;" class="js_darkmode__5" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(178, 178, 178)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(178, 178, 178)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(178, 178, 178)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(178, 178, 178)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;color: rgb(178, 178, 178);font-size: 14px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">来源 |&nbsp;<span style="letter-spacing: 0.75px;word-spacing: 0.8px;">悟空聊架构</span>(ID:PassJava666)</span></p> <section data-darkmode-color-15906764299112="rgb(230, 230, 230)" data-darkmode-original-color-15906764299112="rgb(0, 0, 0)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-style="margin-bottom: 20px; background-color: rgb(255, 255, 255); color: rgb(0, 0, 0); font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif; font-size: 16px; white-space: normal; word-spacing: 0.8px; letter-spacing: 0.75px; text-align: center; visibility: visible;" class="js_darkmode__6" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(0, 0, 0)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(0, 0, 0)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(0, 0, 0)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(0, 0, 0)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(0, 0, 0)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="margin-bottom: 20px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);font-size: 16px;word-spacing: 0.8px;text-align: center;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span data-darkmode-color-15906764299112="rgb(178, 178, 178)" data-darkmode-original-color-15906764299112="rgb(178, 178, 178)" data-darkmode-bgcolor-15906764299112="rgb(36, 36, 36)" data-darkmode-original-bgcolor-15906764299112="rgb(255, 255, 255)" data-darkmode-color-15958675267961="rgb(163, 163, 163)" data-darkmode-original-color-15958675267961="rgb(178, 178, 178)" data-darkmode-bgcolor-15958675267961="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15958675267961="rgb(255, 255, 255)" data-style="color: rgb(178, 178, 178); font-size: 14px; visibility: visible;" class="js_darkmode__7" data-darkmode-color-15965526125846="rgb(163, 163, 163)" data-darkmode-original-color-15965526125846="rgb(178, 178, 178)" data-darkmode-bgcolor-15965526125846="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15965526125846="rgb(255, 255, 255)" data-darkmode-bgcolor-15969880239317="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15969880239317="rgb(255, 255, 255)" data-darkmode-color-15969880239317="rgb(163, 163, 163)" data-darkmode-original-color-15969880239317="rgb(178, 178, 178)" data-darkmode-color-15976750929548="rgb(163, 163, 163)" data-darkmode-original-color-15976750929548="rgb(178, 178, 178)" data-darkmode-bgcolor-15976750929548="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15976750929548="rgb(255, 255, 255)" data-darkmode-color-15982803404507="rgb(163, 163, 163)" data-darkmode-original-color-15982803404507="rgb(178, 178, 178)" data-darkmode-bgcolor-15982803404507="rgb(25, 25, 25)" data-darkmode-original-bgcolor-15982803404507="rgb(255, 255, 255)" style="max-width: 100%;color: rgb(178, 178, 178);font-size: 14px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;">转载请联系授权(微信ID:PassJava)</span> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;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, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">韩信点兵的成语来源淮安民间传说。常与多多益善搭配。寓意越多越好。我们来看下主公刘邦和韩信大将军的对话。</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: black;">刘邦</strong>:“你觉得我可以带兵多少?”</p> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: black;">韩信</strong>:“最多十万。”</p> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: black;">刘邦</strong>不解的问:“那你呢?”</p> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: black;">韩信</strong>自豪地说:“越多越好,多多益善嘛!<span style="letter-spacing: 0px;"></span></p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">假如刘邦现在给了韩信一千个士兵,需要大致均匀分成三组。士兵的编号是六位数,从 1-100000 随机分配。比如第一个士兵的值是 245,第二个士兵的编号是 82593,其他士兵类似。那么如何对士兵进行分配呢?</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: black;">刘邦</strong>:韩将军,你看这些士兵怎么分配好呢?</p> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);"><strong style="color: black;">韩信</strong>:这还不简单,我的<span style="color: rgb(255, 104, 39);">一技能</span>就能搞定。</p> </blockquote> <h2 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">一技能:哈希算法</span></h2> <h3 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">分组</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">韩信的一技能<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">哈希算法</code>:将士兵的编号 num 值当做一个哈希值,再和总做小组数 N 做取余操作,得出的结果在 0 到 N - 1 之间,这个士兵就属于那个组。</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">如下图所示,每来一个士兵都有一个六位的 hash 值(也可以称作编号),然后被韩信用除以 3 取余数的方式分配到三个组。比如第一组中的编号为 123456 的士兵,除以 3 之后,整除,余数为 0,所以分配到第一组。</p> <figure data-tool="mdnice编辑器" style="color: black;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.3327731092436974" src="/upload/73f78eeaffe7aeb783c0003683df728b.png" data-type="png" data-w="595" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 哈希算法 </figcaption> </figure> <h3 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">查找士兵</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">现在已经分好组了,假如想找到编号为 666666 的士兵该怎么找?首先将 666666 除以 3,得到余数 0,说明在第一个组,然后去第一个组里面找就可以了。</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">这里有小伙伴可能会问,为什么不是把所有士兵放到一个组?</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;"><strong style="color: black;">因为一个组太大了,影响行军速度</strong>。映射到互联网架构中,就是通过增加节点从而减小单节点的负载压力。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">哈希分组弊端</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">刘邦看了这个一技能后,大呼:</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">韩将军真是厉害。</p> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">哈希算法看起来很完美,那我再给你五百士兵,需要分成四个组怎么办?</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">这时,韩信的副将说话了:</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">这还不简单,再用 4 取余不就好了吗?</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">刘邦摸着下巴思索片刻后,对副将说:</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">这个方案可行,但很多士兵都被重新分组了,刚刚建立的团队友情就被分解了。</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">我们来看下刘邦为什么觉得方案不可行。</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">比如原来分配到一组的编号为 3 的士兵,当分成四组的时候,通过公式计算:3%4=3,所以会分配到到第四组。</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">依次类推,会发现很多士兵进行了重新分配,只有小部分不会变换分组,比如 1,2,12 不会被重新分组。</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">韩信对着刘邦点点头,对着主公说道:</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">主公,您说得没错,这就是我的一技能的<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);padding: 3px;margin: 3px;">弱点</code>所在。</p> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">不过我还有一个技能:<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);padding: 3px;margin: 3px;">一致性哈希</code>。</p> </blockquote> <h2 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">二技能:一致性哈希</span></h2> <h3 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">哈希环</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">一致性哈希算法也用了取模运算,但是它与哈希算法不同的地方:</p> <ul data-tool="mdnice编辑器" style="color: black;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: black;">哈希算法</strong>:对节点的数量进行取模运算。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: black;">一致性哈希算法</strong>:对 2^32 进行取模运算。 </section></li> </ul> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">可以想象一下,一致性哈希算法,是将整个哈希值空间组成了一个虚拟的圆环,也就是<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">哈希环</code>。</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">如下图,把 3 个组映射到固定大小为 <code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">2^32</code> 的哈希环中。三个组一共将整个环分成了三个区域,C-A(第一组)、A-B(第二组)、B-C(第三组)。如下图所示:</p> <figure data-tool="mdnice编辑器" style="color: black;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.888235294117647" src="/upload/2cb4b6630233cdf234b89ac3e42dbce2.png" data-type="png" data-w="510" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 分成三组 </figcaption> </figure> <ul data-tool="mdnice编辑器" style="color: black;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">第一组负责存储落在 C-A 区间内的数据。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">第二组负责存储落在 A-B 区间内的数据。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">第三组负责存储落在 B-C 区间内的数据。</p> </section></li> </ul> <h3 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">士兵分配</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">假定编号为 9527 的士兵,进行哈希运算后,落到 C-A 区域。如下图所示:</p> <figure data-tool="mdnice编辑器" style="color: black;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9500924214417745" src="/upload/2b534052a8ee51aa51c31a54d2dda56b.png" data-type="png" data-w="541" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 士兵所站位置 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">第二步,让这个士兵顺时针往前走,遇到的第一个节点 A 就是他所在的组了。如下图所示:</p> <figure data-tool="mdnice编辑器" style="color: black;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9945652173913043" src="/upload/36cc79b893a1644cc9bafc2fa0dc7568.png" data-type="png" data-w="552" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 顺时针遇到第一个节点 </figcaption> </figure> <h3 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">增加分组</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">目前三个节点的时候,假定编号为 89757 的士兵经过哈希运算后,分配到了 B-C 区域(第三组),也就是属于 C 节点管控。如下图所示:</p> <figure data-tool="mdnice编辑器" style="color: black;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9421052631578948" src="/upload/6285d4b5c2461cef130de73113aacd72.png" data-type="png" data-w="570" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 属于 C 节点 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">回到刘邦刚问的问题,如果分组变成四组,该怎么进行士兵分配。</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">如下图所示,增加一个节点 D,原来的区域 B-C 变成了区域 B-D(第三组) 和 D-C(第四组)。</p> <figure data-tool="mdnice编辑器" style="color: black;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8845437616387337" src="/upload/2416ee2a5a3e289a8ca1d65e5c2497eb.png" data-type="png" data-w="537" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 增加 D 节点 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">那么这名士兵属于哪个节点管控呢?如下图所示,士兵顺时针往前走,先走到了 D 节点,所以属于 D 节点管控。虽然还是属于第三组,<strong style="color: black;">但是这名士兵的领导者已经变了:由 C 变成了 D</strong>。</p> <figure data-tool="mdnice编辑器" style="color: black;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9767857142857143" src="/upload/b622b7f4d750315b4b32b19978db2439.png" data-type="png" data-w="560" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 领导者变了 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">从上面的变化来看,只有 B-C 区域中的部分数据会进行迁移:B-D 之间的数据会由 C 节点<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">迁移</code>到 D 节点。</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">而<strong style="color: black;">其他数据不受影响,也不用进行迁移</strong>。而且节点越多,需要迁移的数据就越少。这就是多多益善了~</p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">刘邦看了后,大赞韩信:</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">不亏是大将军,萧何当时月下追你,值了!</p> </blockquote> <h3 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">哈希环缺陷</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">萧何看了韩信画的哈希环后,觉得有些不对劲,思索片刻后,对韩信说:</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">将军,你这个哈希环上的节点分布<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);padding: 3px;margin: 3px;">不太均匀</code>啊,你看第三组和第四组的的区域好小啊。</p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">萧何说得没错,确实存在这个问题,放到互联网架构中,就存在如下问题:</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;"><span style="color:#000000;"><strong>节点分布不均匀,导致业务对节点的访问冷热不均</strong></span><span style="color: rgb(58, 58, 58);">。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">韩信眼中充满着赞赏,知我者莫若萧何。然后胸有成竹地说道:</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">你说得没错,不过我还有一个技能,<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);padding: 3px;margin: 3px;">虚拟节点映射</code>。</p> </blockquote> <h2 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">三技能:虚拟节点</span></h2> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">一般虚拟节点比物理节点要多,并相对均匀地分布在哈希环上。如下图所示,12 个虚拟节点 N1~N12,相对均匀地分布在虚拟节点上。如果有士兵属于 N2/N3/N4 中的某一个,都会重新映射到 A 节点,依次类推,N5/N6/N7 属于 B 节点的虚拟节点映射。<span style="color: black;letter-spacing: 0px;"></span></p> <figure data-tool="mdnice编辑器" style="color: black;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <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, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.0893617021276596" src="/upload/2871e96dd91d60b1183672f2c08f5572.png" data-type="png" data-w="470" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 虚拟节点 </figcaption> </figure> </section> </figure> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">我们来看下萧何的提出的问题,真实的 B-D 区域比较小,用虚拟节点后,N5/N6/N7 属于 B 节点,N8/N9/N10 属于 D 节点,他们分到的虚拟节点一样多,而且区域大致相等。所以士兵的分配也比较均匀。</p> <blockquote data-tool="mdnice编辑器" style="color: rgb(106, 115, 125);border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">萧何看了韩信的三技能后,直呼:妙哉妙哉!</p> </blockquote> <h2 data-tool="mdnice编辑器" style="color: black;font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">总结</span></h2> <p data-tool="mdnice编辑器" style="color: rgb(58, 58, 58);margin-bottom: 20px;line-height: 1.8em;">本篇通过韩信点兵的故事,然后从故事中衍生出刘邦、韩信、萧何的对话,来讲解士兵的分组的问题。现在对故事中的知识点做一个总结:</p> <ul data-tool="mdnice编辑器" style="color: black;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 哈希算法会带来增加或删除节点时, <strong>数据迁移</strong>量太大的问题。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 一致性哈希算法 <strong>降低</strong>了数据迁移量。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <span style="color: rgb(1, 1, 1);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;">节点较少</span> <span style="color: rgb(1, 1, 1);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;"></span>,哈希环上每个节点实际占据的区间大小不一,最终导致业务对节点的访问 <strong>冷热不均</strong>。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 引入 <strong>虚拟节点映射</strong>解决了分布不均问题。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 节点 <strong>越多</strong>时, <span style="color: rgb(1, 1, 1);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;">使用哈希</span> <span style="color: rgb(1, 1, 1);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;">算法时,</span>需要迁移的数据就 <strong>越多</strong>,而使用一致性哈希算法,迁移的数据就 <strong>越少</strong>。 <br> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 一致性哈希算法本质上是一种 <strong>路由寻址</strong>算法,适合简单的路由寻址场景。 <br> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 一致性哈希算法常用在负载均衡的架构设计中。 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 封面图片来源王者荣耀。 <br> </section> </section> <p style="white-space: normal;box-sizing: border-box;text-align: center;"><span style="color: rgb(2, 30, 170);font-family: monospace;font-size: 16px;letter-spacing: 0.544px;white-space: pre-wrap;background-color: rgb(255, 255, 255);">- END -</span></p> <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(&quot;https://mmbiz.qpic.cn/mmbiz_png/sUbvrqLicbpzB81mjeBxPuxnYdalGxNnJo30L2Hq3WwGficcq8w5YJkLeXnsNHocN53k55TfN5mBpCdicGRyfDg1g/640?wx_fmt=png&quot;);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="2451950743_1" data-recommend-article-time="1611633000" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/SfAHMuUxqJ3VMtibPPw2Fn98uzdrtC5wRHv6Pnnhx8t89ZFnp671xa2wvgsB4KyuBFtqWqUVRXibz3GwEpEs9R6A/0?wx_fmt=jpeg" data-recommend-article-title="用动图讲解分布式 Raft" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451950743&amp;idx=1&amp;sn=df1c600f636c8d9b119f534750c007eb&amp;chksm=8d1c3508ba6bbc1e6e4def2ea4c25d9c5e69013d463af31f6bc78cacbc3735ccea455842303d#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451950743&amp;idx=1&amp;sn=df1c600f636c8d9b119f534750c007eb&amp;chksm=8d1c3508ba6bbc1e6e4def2ea4c25d9c5e69013d463af31f6bc78cacbc3735ccea455842303d&amp;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="">四:用动图讲解分布式 Raft</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2451950571_1" data-recommend-article-time="1610503618" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/SfAHMuUxqJ1XJ3foP6SbnsBdm0nct0kmrS15E2r4MrSIdEY6cucMDHAKFAic2Wm0vHwPgnvATIJM7c6fNMpKsnQ/0?wx_fmt=jpeg" data-recommend-article-title="诸葛亮 VS 庞统,拿下分布式 Paxos | 文末送书" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451950571&amp;idx=1&amp;sn=04359a2a8db23a64da29cd03dafe0f9c&amp;chksm=8d1c3274ba6bbb62b03a452f5598d355d0dc91ea955d810e5a8128c466b3b0d04f2e6469c49b#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451950571&amp;idx=1&amp;sn=04359a2a8db23a64da29cd03dafe0f9c&amp;chksm=8d1c3274ba6bbb62b03a452f5598d355d0dc91ea955d810e5a8128c466b3b0d04f2e6469c49b&amp;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="">三:诸葛亮 VS 庞统,拿下分布式 Paxos</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2451950422_1" data-recommend-article-time="1609320216" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/SfAHMuUxqJ2ROTVCQJsNTB7HPghU6s7FibByRFg044hvsyiaIouAYZxSyZDMUbs9x9ZRqtyYErwGNYiaWo6r2wI9g/0?wx_fmt=jpeg" data-recommend-article-title="用太极拳讲分布式理论,真舒服!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451950422&amp;idx=1&amp;sn=7f86457acedbd0853cbcb7dc4377dd54&amp;chksm=8d1c32c9ba6bbbdfd3d8c698addfb13a02589409bdf6a03a777e9afc95249018293d9a9e0a3f#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451950422&amp;idx=1&amp;sn=7f86457acedbd0853cbcb7dc4377dd54&amp;chksm=8d1c32c9ba6bbbdfd3d8c698addfb13a02589409bdf6a03a777e9afc95249018293d9a9e0a3f&amp;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="">二:用太极拳讲分布式理论,真舒服!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2451949807_1" data-recommend-article-time="1607650417" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/SfAHMuUxqJ3EponJUvecQg0gQ0Zmcpgz5W68qNXUmiabl8rfNqCFa0aD4I9u7p3bwANhH8J35sHVEeT2deCEPoA/0?wx_fmt=jpeg" data-recommend-article-title="用三国杀讲分布式算法,舒适了吧?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451949807&amp;idx=1&amp;sn=d8fb211bc87275e004a8001e095ef402&amp;chksm=8d1c3170ba6bb866ca19548e3922d64d194a0c798622aa954e0236b85cb0869c88ff40f3deed#rd"> <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=""><span style="display: none;line-height: 0px;">‍‍</span></p> <span style="display: none;line-height: 0px;">‍</span> <section data-recommend-type="list-title" data-recommend-tid="6" data-mid="" data-from="yb-recommend"> <section data-recommend-title="t" data-recommend-content="t" data-mid=""> <a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451949807&amp;idx=1&amp;sn=d8fb211bc87275e004a8001e095ef402&amp;chksm=8d1c3170ba6bb866ca19548e3922d64d194a0c798622aa954e0236b85cb0869c88ff40f3deed&amp;scene=21#wechat_redirect" data-linktype="2">一:用三国杀讲分布式算法,舒适了吧?</a> </section> </section> <a href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451949807&amp;idx=1&amp;sn=d8fb211bc87275e004a8001e095ef402&amp;chksm=8d1c3170ba6bb866ca19548e3922d64d194a0c798622aa954e0236b85cb0869c88ff40f3deed&amp;scene=21#wechat_redirect" data-linktype="2"></a>‍ <span style="display: none;line-height: 0px;">‍</span> <p><br></p> </section> </section> </section> </section> </section> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;white-space: normal;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;"> <section powered-by="xiumi.us" style="text-align: center;box-sizing: border-box;"> <section data-role="outer" label="Powered by 135editor.com" style="color: rgb(255, 150, 155);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 14px;max-width: 100%;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-role="paragraph" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;font-size: 16px;letter-spacing: 0.544px;line-height: 25.6px;border-width: 0px;border-style: none;border-top-color: rgb(189, 189, 189);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;display: inline-block;max-width: 100%;border-top: 3px solid rgb(70, 70, 70);border-bottom: 1px solid rgb(220, 220, 220);width: 556px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding-top: 5px;padding-bottom: 5px;max-width: 100%;clear: both;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <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, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;"> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);"><code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);padding: 3px;margin: 3px;">作者简介</code>:8 年互联网经验,擅长架构设计、分布式、微服务。手写了一套 SpringCloud 实战教程,自主开发了 PMP 刷题小程序和 Java 刷题小程序。回复 pdf 领取。</p> </blockquote> </section> </section> </section> </section> </section> </section> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="display: flex;flex-flow: row nowrap;box-sizing: border-box;"> <section style="display: inline-block;vertical-align: bottom;width: auto;align-self: flex-end;flex: 2 2 0%;height: auto;box-sizing: border-box;"> <section powered-by="xiumi.us" style="margin-top: 10px;opacity: 0.5;box-sizing: border-box;"> <span style="text-decoration: underline;"><em><strong><span style="text-decoration: underline;color: rgb(43, 43, 43);font-family: Optima-Regular, Optima, PingFangTC-Light, PingFangSC-light, PingFangTC-light;font-size: 14px;letter-spacing: 2px;text-align: left;word-spacing: 2px;background-color: rgb(255, 255, 255);">我是悟空,努力变强,变身超级赛亚人!</span></strong></em></span> </section> </section> </section> </section> </section> </figure>

Prometheus 监控,程序员的助眠神器

作者:微信小助手

<section data-mpa-template="t" mpa-paragraph-type="ignored" style="max-width: 100%;color: rgb(62, 62, 62);font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">对很多人来说,未知、不确定、不在掌控的东西,会有潜意识的逃避。<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="当我第一次接触 Prometheus 的时候也有类似的感觉。对初学者来说, Prometheus 包含的概念太多了,门槛也太高了。概念:Instance、Job、Metric、Metric Name、Metric Label、Metric Value、Metric Type(Counter、Gauge、Histogram、Summary)、DataType(Instant Vector、Range Vector、Scalar、String)、Operator、Function" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">当我第一次接触 Prometheus 的时候也有类似的感觉。对初学者来说, Prometheus 包含的概念太多了,门槛也太高了。</span></a></p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-left-color: rgba(0, 0, 0, 0.4);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgba(0, 0, 0, 0.047);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;font-size: 16px;word-break: break-word;color: black;line-height: 26px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="当我第一次接触 Prometheus 的时候也有类似的感觉。对初学者来说, Prometheus 包含的概念太多了,门槛也太高了。概念:Instance、Job、Metric、Metric Name、Metric Label、Metric Value、Metric Type(Counter、Gauge、Histogram、Summary)、DataType(Instant Vector、Range Vector、Scalar、String)、Operator、Function" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">概念:Instance、Job、Metric、Metric Name、Metric Label、Metric Value、Metric Type(Counter、Gauge、Histogram、Summary)、DataType(Instant Vector、Range Vector、Scalar、String)、Operator、Function</span></a></p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">马云说:“虽然阿里巴巴是全球最大的零售平台,但阿里不是零售公司,是一家数据公司”。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;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;">Prometheus 也是一样,本质来说是一个基于数据的监控系统。</strong></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;max-width: 100%;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">日常监控</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">假设需要监控 WebServerA 每个API的请求量为例,需要监控的维度包括:服务名(job)、实例IP(instance)、API名(handler)、方法(method)、返回码(code)、请求量(value)。</p> <p style="max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-backh="309" data-backw="578" data-ratio="0.535" data-s="300,640" data-type="png" data-w="1000" src="/upload/a83663f800b0fa017281ea8fa1316007.png" style="border-radius: 3px;width: 544px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果以SQL为例,演示常见的查询操作:<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">查询 method=put 且 code=200 的请求量(红框)</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;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(171, 178, 191);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">SELECT&nbsp;*&nbsp;from&nbsp;http_requests_total&nbsp;WHERE&nbsp;code=”200”&nbsp;AND&nbsp;method=”put”&nbsp;AND&nbsp;created_at&nbsp;BETWEEN&nbsp;1495435700&nbsp;AND&nbsp;1495435710;<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;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">查询 handler=prometheus 且 method=post 的请求量(绿框)</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;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(171, 178, 191);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">SELECT&nbsp;*&nbsp;from&nbsp;http_requests_total&nbsp;WHERE&nbsp;handler=”prometheus”&nbsp;AND&nbsp;method=”post”&nbsp;AND&nbsp;created_at&nbsp;BETWEEN&nbsp;1495435700&nbsp;AND&nbsp;1495435710;<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;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">查询 instance=10.59.8.110 且 handler 以 query 开头 的请求量(绿框)</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;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(171, 178, 191);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">SELECT&nbsp;*&nbsp;from&nbsp;http_requests_total&nbsp;WHERE&nbsp;handler=”query”&nbsp;AND&nbsp;instance=”10.59.8.110”&nbsp;AND&nbsp;created_at&nbsp;BETWEEN&nbsp;1495435700&nbsp;AND&nbsp;1495435710;<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;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">通过以上示例可以看出,在常用查询和统计方面,日常监控多用于根据监控的维度进行查询与时间进行组合查询。另外,关注公众号Java技术栈,在后台回复:面试,可以获取我整理的最新<span style="max-width: 100%;letter-spacing: 1.5px;word-spacing: 1.5px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">Java系列面试题和答案</span>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果监控100个服务,平均每个服务部署10个实例,每个服务有20个API,4个方法,30秒收集一次数据,保留60天。那么总数据条数为:100(服务) 10(实例) 20(API) 4(方法) 86400(1天秒数)* 60(天) / 30(秒)= 138.24 亿条数据,写入、存储、查询如此量级的数据是不可能在Mysql类的关系数据库上完成的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">因此 Prometheus 使用 TSDB 作为 存储引擎。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;max-width: 100%;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">存储引擎</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:</span></a></p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">存储的数据量级十分庞大</span></a> </section></li> <li style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">大部分时间都是写入操作</span></a> </section></li> <li style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序</span></a> </section></li> <li style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库</span></a> </section></li> <li style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据</span></a> </section></li> <li style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用</span></a> </section></li> <li style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">读操作是十分典型的升序或者降序的顺序读</span></a> </section></li> <li style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">高并发的读操作十分常见</span></a> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&amp;mid=2247517642&amp;idx=2&amp;sn=258dd06dbb03db2ee49fa0ee40394d35&amp;chksm=eb5000fcdc2789ea55afe3a9ffe54659e1b6a8cfb3f491ced82140a5c963cc0eb03788a9543f&amp;scene=21#wechat_redirect" textvalue="TSDB 作为 Prometheus 的存储引擎完美契合了监控数据的应用场景:存储的数据量级十分庞大大部分时间都是写入操作写入操作几乎是顺序添加,大多数时候数据到达后都以时间排序写操作很少写入很久之前的数据,也很少更新数据。大多数情况在数据被采集到数秒或者数分钟后就会被写入数据库删除操作一般为区块删除,选定开始的历史时间并指定后续的区块。很少单独删除某个时间或者分开的随机时间的数据基本数据大,一般超过内存大小。一般选取的只是其一小部分且没有规律,缓存几乎不起任何作用读操作是十分典型的升序或者降序的顺序读高并发的读操作十分常见那么 TSDB 是怎么实现以上功能的呢?" 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%;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;">那么 TSDB 是怎么实现以上功能的呢?</strong></span></a></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;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(171, 178, 191);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;text-align: left;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(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"labels"</span>:&nbsp;[{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"latency"</span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"500"</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(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"samples"</span>:[{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"timestamp"</span>:&nbsp;1473305798,<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"value"</span>:&nbsp;0.9<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;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">原始数据分为两部分 label, samples。前者记录监控的维度(标签:标签值),指标名称和标签的可选键值对唯一确定一条时间序列(使用 series_id 代表);后者包含包含了时间戳(timestamp)和指标值(value)。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;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(171, 178, 191);display: -webkit-box;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">series<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;">│.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;&nbsp;&nbsp;server{latency=<span style="max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"500"</span>}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">│.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;&nbsp;&nbsp;server{latency=<span style="max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"300"</span>}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">│.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;&nbsp;&nbsp;.&nbsp;&nbsp;&nbsp;server{}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">│.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">v<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&lt;--------&nbsp;time&nbsp;----------&gt;<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;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">TSDB 使用 timeseries:doc:: 为 key 存储 value。为了加速常见查询查询操作:label 和 时间范围结合。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">TSDB 额外构建了三种索引:Series, Label Index 和 Time Index。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">以标签 latency 为例:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;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;">Series</strong></p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-left-color: rgba(0, 0, 0, 0.4);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgba(0, 0, 0, 0.047);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;font-size: 16px;word-break: break-word;color: black;line-height: 26px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">存储两部分数据。一部分是按照字典序的排列的所有标签键值对序列(series);另外一部分是时间线到数据文件的索引,按照时间窗口切割存储数据块记录的具体位置信息,因此在查询时可以快速跳过大量非查询窗口的记录数据</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;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;">Label Index</strong></p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-left-color: rgba(0, 0, 0, 0.4);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgba(0, 0, 0, 0.047);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;font-size: 16px;word-break: break-word;color: black;line-height: 26px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">每对 label 为会以 index:label: 为 key,存储该标签所有值的列表,并通过引用指向 Series 该值的起始位置。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;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;">Time Index</strong></p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;border-left-color: rgba(0, 0, 0, 0.4);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgba(0, 0, 0, 0.047);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;font-size: 16px;word-break: break-word;color: black;line-height: 26px;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">数据会以 index:timeseries:: 为 key,指向对应时间段的数据文件</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;max-width: 100%;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">数据计算</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">强大的存储引擎为数据计算提供了完美的助力,使得 Prometheus 与其他监控服务完全不同。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">Prometheus 可以查询出不同的数据序列,然后再加上基础的运算符,以及强大的函数,就可以执行 metric series 的矩阵运算(见下图)。</p> <p style="max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-backh="453" data-backw="567" data-ratio="0.798941798941799" data-s="300,640" data-type="png" data-w="567" src="/upload/e8a287fe746301ca265612ec5be202ae.png" style="width: 544px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">如此,Promtheus体系的能力不弱于监控界的“数据仓库”+“计算平台”。因此,在大数据的开始在业界得到应用,就能明白,这就是监控未来的方向。<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;max-width: 100%;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">一次计算,处处查询</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">当然,如此强大的计算能力,消耗的资源也是挺恐怖的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">因此,查询预计算结果通常比每次需要原始表达式都要快得多,尤其是在仪表盘和告警规则的适用场景中,仪表盘每次刷新都需要重复查询相同的表达式,告警规则每次运算也是如此。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;max-width: 100%;min-height: 1em;word-spacing: 0.1em;letter-spacing: 0.1em;line-height: 1.95;color: rgb(51, 51, 51);word-break: break-word;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;">因此,Prometheus提供了 Recoding rules,可以预先计算经常需要或者计算量大的表达式,并将其结果保存为一组新的时间序列, 达到一次计算,多次查询的目的。</p> <p style="max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-backh="211" data-backw="578" data-ratio="0.36503067484662577" data-s="300,640" data-type="png" data-w="652" src="/upload/8719d76f5bffb23929bbdd44163e5771.png" style="width: 544px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;"></p> </section> </section> <section style="margin-bottom: 15px;max-width: 100%;color: rgb(62, 62, 62);font-size: 15px;white-space: normal;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;min-height: 1em;line-height: 1.75em;letter-spacing: 1px;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 style="max-width: 100%;color: rgb(136, 136, 136);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;letter-spacing: 0.544px;white-space: pre-line;box-sizing: border-box !important;overflow-wrap: break-word !important;">来源:</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;letter-spacing: 0.544px;white-space: pre-line;box-sizing: border-box !important;overflow-wrap: break-word !important;">https://www.cyningsun.com/02-22-2020/hidden-secret-to-understanding-prometheus.html</span></span> </section> <section> <section data-id="137" data-tools="非找你编辑器" data-tools-id="85108"> <section> <section data-id="884" data-tools="非找你编辑器" data-tools-id="39075"> <section style="margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;vertical-align: top;width: 40%;box-sizing: border-box;" data-width="40%"> <section> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;"> <section style="border-top: 1px dotted rgb(62, 62, 62);box-sizing: border-box;"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> </section> </section> </section> <section style="display: inline-block;vertical-align: top;width: 20%;box-sizing: border-box;" data-width="20%"> <section> <section style="margin-top: -10px;margin-right: 0%;margin-left: 0%;text-align: center;font-size: 10px;box-sizing: border-box;"> <section style="display: inline-block;box-sizing: border-box;"> <section style="width:2.3em;height:2.3em;line-height: 2.0em;border-radius: 100%;margin-left: auto;margin-right: auto;font-size: 18px;color: #ffffff;box-sizing: border-box;background-color: #3e3e3e;" data-width="2.3em"> <p style="box-sizing: border-box;"><span style="color: #ffffff;"><strong style="box-sizing: border-box;">end</strong></span></p> </section> <section style="width: 0px;margin-top: -0.76em;border-bottom-width: 0.8em;border-bottom-style: solid;box-sizing: border-box;border-left: 0.8em solid transparent !important;border-right: 0.5em solid transparent !important;" data-width="0px"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> </section> </section> </section> </section> <section style="display: inline-block;vertical-align: top;width: 40%;box-sizing: border-box;" data-width="40%"> <section> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;"> <section style="border-top: 1px dotted rgb(62, 62, 62);box-sizing: border-box;"> <br> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section data-id="8304" data-tools="非找你编辑器" data-tools-id="10301"> <section style="margin: 60px 5px 16px;border-width: 3px;border-style: solid;border-color: rgb(233, 131, 109);text-align: center;border-radius: 2px;font-size: 18px;font-weight: inherit;text-decoration: inherit;box-sizing: border-box;padding: 0px;"> <section style="margin:10px;"> <section style="width: 50%;float: left;padding-right: 0.1em;box-sizing: border-box;" data-width="50%"> <img data-cropselx1="0" data-cropselx2="269" data-cropsely1="0" data-cropsely2="269" data-ratio="1" src="/upload/407a5281becaefd3658cea4ca2ad7660.jpg" data-type="jpeg" data-w="258" data-width="100%" style="width: 269px;height: 269px;"> <span style="line-height: 300px;float: left;height: 0px;clear: both;overflow: hidden;"></span> </section> <section style="width:50%;display:inline-block;box-sizing:border-box;padding-left:0.1em;box-sizing:border-box;" data-width="50%"> <img data-ratio="1" src="/upload/56b706a083838a5d5a342c4cc8b40caa.jpg" data-type="jpeg" data-w="240" data-width="100%" style="width:100%;"> </section> </section> </section> </section> <p><br></p>

阿里面试官的“说一下从url输入到返回请求的过程”问的难度就是不一样!

作者:微信小助手

<p style="white-space: normal;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);text-align: center;"><span style="orphans: 2;widows: 2;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;font-size: 14px;color: rgb(255, 41, 65);line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;">(给</span><span style="orphans: 2;widows: 2;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;font-size: 14px;line-height: 22.4px;color: rgb(0, 128, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">前端大全</span><span style="orphans: 2;widows: 2;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;font-size: 14px;color: rgb(255, 41, 65);line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;">加星标,提升前端技能</span><span style="orphans: 2;widows: 2;font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;max-width: 100%;white-space: pre-wrap;color: rgb(255, 41, 65);font-size: 14px;line-height: 22.4px;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></p> <section style="font-size: 16px;letter-spacing: 0px;text-align: start;white-space: normal;color: rgb(62, 62, 62);line-height: 1.6;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background-color: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">转自:掘金 - 孟祥_成都&nbsp;</p> <p style="font-size: inherit;color: inherit;line-height: inherit;">https://juejin.cn/post/6928677404332425223</p> </blockquote> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span></p> <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;overflow-wrap: break-word;text-align: left;font-family: Helvetica;"> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;">前言</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">年前准备换工作,总结了一波面试最频繁的面试问题跟大家交流。此文章是关于浏览器的常见问题,大概面试10家遇到6家提问类似问题(主要是大厂和中厂)。(面试的部分内容已经忘了,为了串联成一个完整的故事,增加可读性,20%的内容为虚构),目前入职滴滴出行成都团队。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span><span style="font-size: 16px;">问题: 从浏览器地址栏输入url到请求返回发生了什么</span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">你一看这种烂掉牙的问题,小case,但996面试大佬由此延展的问题已经远远超越了这个问题本身了,不信你就接着看。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>我回答了首先会进行 url 解析,根据 dns 系统进行 ip 查找。</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">话音刚落,此时一位喜欢修福报的公司的大佬打断了我,说url为啥要解析,dns查询规则是什么?我一听就心里想,不按套路出牌啊,网上一般都没问这两个问题,心里再一想,俗话说,万事开头难,扛过这一波,答出来,就是阳光明媚,万物骚动的春天!</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 218, 169);"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;font-size: 15px;">先说为什么url要解析(也就是编码)</p> </blockquote> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 我回答大概内容是:因为网络标准规定了URL只能是字母和数字,还有一些其它特殊符号(-_.~ ! * ' ( ) ; : @ &amp; = + $ , / ? # [ ],特殊符号是我下来查的资料,实在背不住这么多,比较常见的就是不包括百分号和双引号),而且如果不转义会出现歧义,比如 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">http:www.baidu.com?key=value</code>,假如我的 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">key</code>本身就包括等于 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">=</code>符号,比如 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">ke=y=value</code>,就会出现歧义,你不知道 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">=</code>到底是连接 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">key</code>和 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">value</code>的符号,还是说本身 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">key</code>里面就有 <code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">=</code>。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 大佬接着毒打我说,那url编码的规则是什么呢,我说utf-8 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 大佬接着穷追不舍,为啥是utf-8呢,所有浏览器都是这样吗?中文的话用gb2312编码吗,还有就是万一浏览器不是你说的这样统一用utf-8,你怎么保证都是utf-8的编码? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 我支支吾吾的说,我了解的大概是这样,不太清楚, 应该和html本身的编码格式有关,然后怎么保证utf-8的编码,我觉得可以用encodeURIComponent </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 大佬说encodeURIComponent比encodeURI有什么区别? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 区别就是encodeURIComponent编码范围更广,适合给参数编码,encodeURI适合给URL本身(locaion.origin)编码,当然项目里一般都是用qs库去处理 </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 218, 169);"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;font-size: 15px;">然后说说dns解析流程,并且html如何做dns优化</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">首先dns这个属于很久以前在计算机网络谢希仁版看到过了,有一些细节忘了,但是大致流程是记得的。比如说查询一个网址为:www.baidu.com</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">1、器中输入https://www.baidu.com 域名,操作系统会先查hosts件是否有记录,有的话就会把相对应映射的IP返回。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">2、hosts文件没有就去查本地dns解析器有没有缓存。(这个我没答上来)</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">3、然后就去找我们计算机上配置的dns服务器上有或者有缓存,就返回</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">4、还没有的话就去找根DNS服务器(全球13台,固定ip地址),然后判断.com域名是哪个服务器管理,如果无法解析,就查找.baidu.com服务器是否能解析,直到查到www.baidu.com的IP地址</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">注:后面查资料才发现dns查询有两种模式,一种是转发模式,一种是非转发模式,我上面说的4是非转发模式。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">前端的dns优化,可以在html页面头部写入dns缓存地址,比如</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/zPh0erYjkib3tUfibiaO1lGLlEl51At8LCbFNHuQsES5C1M4p1hkXt6ibSXMfSU1eVZ2M1aEjAFjwYiab40qwHwGocA/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">&lt;meta&nbsp;http-equiv=<span style="color: #98c379;line-height: 26px;">"x-dns-prefetch-control"</span>&nbsp;content=<span style="color: #98c379;line-height: 26px;">"on"</span>&nbsp;/&gt;<br>&lt;link&nbsp;rel=<span style="color: #98c379;line-height: 26px;">"dns-prefetch"</span>&nbsp;href=<span style="color: #98c379;line-height: 26px;">"http://bdimg.share.baidu.com"</span>&nbsp;/&gt;<br><br><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">终于抗过了第一轮的猛问,接着我继续说从浏览器地址栏输入url到请求返回发生了什么</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>查找到IP之后,就是http协议的三次握手(以及后面会涉及到四次分手)</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我刚恢复节奏,准备侃侃而谈,修福报的大佬再次打断了我,说三次握手,为啥两次不行,顺便说一下3次握手发生了什么。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我去,大意了,没有闪,这是不是说我每说一句都要夹杂着各种问题,太难了啊!!!</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">没有办法,继续回答大佬,我说我先回答三次握手发生的事情吧,简答来说:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">第一次握手:主机A发送位码为SYN=1的TCP包给服务器,并且随机产生一个作为确认号(这是tcp包的一部分),主机B收到SYN码后直到A要求建立连接;</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">第二次握手:主机B收到请求后,向A发送确认号(主机A的seq+1),syn=1,seq = 随机数 的TCP包;</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">主机A收到后检查确认号是否正确,即第一次A发送的确认号是否+1了,以及位码ack是否为1,若正确,主机A会再发送确认号(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着补上小问题为什么两次握手不行,因为第二次握手,主机B还不能确认主机A已经收到确认请求,也是说B认为建立好连接,开始发数据了,结果发出去的包一直A都没收到,那攻击B就很容易了,我专门发包不接收,服务器很容易就挂了。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 218, 169);"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;font-size: 15px;">接着,大佬说出个加分题,我看你不是科班出身,能答多少是多少。问题是,从网卡把数据包传输出去到服务器发生了什么,提示我OSI参考模型</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我一听,好嘛,这不是计算机网络的知识吗,幸亏之前看过书,但也是好久以前看过了,只能凭借自己的理解解答了。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 我说,先从局域网把数据发送到公司的交换机(如果交换机没有缓存本地mac地址和IP地址的映射,此时会通过ARP协议来获得),交换机的好处是可以隔离冲突域(因为以太网用的是CSMA/CD协议,这个协议规定网线上同一时刻只能有一台机器发送数据),这样就可以不仅仅同一时刻只有一台机器发送网络包了 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 然后交换机再将数据发送到路由器,路由器相当于公司网关(我们公司小),路由器具有转发和分组数据包的功能(路由器通过选定的路由协议会构造出路由表,同时不定期的跟相邻路由器交换路由信息),然后这算是经过了物理层,数据链路层(以太网),开始到网络层进行数据转发了 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 然后路由器转发IP数据报,一般公司的IP地址都会经过NAT转换,让内网的ip也能够访问外网,我们公司我注意了一下是192.168打头的内网ip地址。通过路由器的分组传输,所有数据到达服务器。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 然后服务器的上层协议传输层协议开始发挥作用,根据tcp包里的端口号,让服务器特定的服务来处理到来的数据包,并且tcp是面向字节流的(tcp有四大特性,可靠传输、流量控制、拥塞控制、连接管理),所以我们node的request对象,它的监听事件data事件为什么要用字符串一起拼接起来呢(buffer),就是因为tcp本身就是字节流,request对象使用的data(http层面)是tcp传来的数据块。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 最后数据由传输层转交给应用层,也就是http服务(或者https),后端经过一系列逻辑处理,返回给前端数据。 </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 218, 169);"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;font-size: 15px;">答完这里,我说大佬我只知道大概的流程,具体细节我不是很清楚,但自己后面会补上。。。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>大佬让我继续,我就接着3次握手之后接着说道,建立完链接,就该请求html文件了,如果html文件在缓存里面浏览器直接返回,如果没有,就去后台拿</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">刚说到缓存,立马就有一种不详的预感,果不其然大佬先让把缓存解释一下。缓存这种问烂的问题,本以为能轻松应对,结果还是被问了个满头包。。。。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5681818181818182" src="/upload/8c58f071fdb5b7f26ad1edfab51243c8.png" data-type="png" data-w="528" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我说的大概意思是:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">浏览器首次加载资源成功时,服务器返回200,此时浏览器不仅将资源下载下来,而且把response的header(里面的date属性非常重要,用来计算第二次相同资源时当前时间和date的时间差)一并缓存;</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">下一次加载资源时,首先要经过强缓存的处理,cache-control的优先级最高,比如cache-control:no-cache,就直接进入到协商缓存的步骤了,如果cache-control:max-age=xxx,就会先比较当前时间和上一次返回200时的时间差,如果没有超过max-age,命中强缓存,不发请求直接从本地缓存读取该文件(这里需要注意,如果没有cache-control,会取expires的值,来对比是否过期),过期的话会进入下一个阶段,协商缓存</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">协商缓存阶段,则向服务器发送header带有If-None-Match和If-Modified-Since的请求,服务器会比较Etag,如果相同,命中协商缓存,返回304;如果不一致则有改动,直接返回新的资源文件带上新的Etag值并返回200;</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">协商缓存第二个重要的字段是,If-Modified-Since,如果客户端发送的If-Modified-Since的值跟服务器端获取的文件最近改动的时间,一致则命中协商缓存,返回304;不一致则返回新的last-modified和文件并返回200;</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">果不其然,大佬问了一些缓存不常问的,首先就是问我知道什么是from disk cache和from memory cache吗,什么时候会触发?</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 我说强缓存会触发,这两种,具体什么行为不知道,大概内容如下: </section></li> </ul> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/zPh0erYjkib3tUfibiaO1lGLlEl51At8LCbFNHuQsES5C1M4p1hkXt6ibSXMfSU1eVZ2M1aEjAFjwYiab40qwHwGocA/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">1、先查找内存,如果内存中存在,从内存中加载;<br>2、如果内存中未查找到,选择硬盘获取,如果硬盘中有,从硬盘中加载;<br>3、如果硬盘中未查找到,那就进行网络请求;<br>4、加载到的资源缓存到硬盘和内存;<br><br><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>接着大佬又问知道什么是启发式缓存吗,在什么条件下触发?</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这个问题给我的感觉就两个字,懵逼!然后如实回答不知道。(查了下资料大概如下)</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>启发式缓存:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果响应中未显示Expires,Cache-Control:max-age或Cache-Control:s-maxage,并且响应中不包含其他有关缓存的限制,缓存可以使用启发式方法计算新鲜度寿命。通常会根据响应头中的2个时间字段 Date 减去 Last-Modified 值的 10% 作为缓存时间。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/zPh0erYjkib3tUfibiaO1lGLlEl51At8LCbFNHuQsES5C1M4p1hkXt6ibSXMfSU1eVZ2M1aEjAFjwYiab40qwHwGocA/640?wx_fmt=png&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">// Date 减去 Last-Modified 值的 10%&nbsp;作为缓存时间。<br>// Date:创建报文的日期时间, Last-Modified 服务器声明文档最后被修改时间<br>&nbsp;&nbsp;response_is_fresh&nbsp;=&nbsp;&nbsp;max(0,(Date&nbsp;-&nbsp;&nbsp;Last-Modified))&nbsp;%&nbsp;10<br><br><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>接着回答,我说返回html之后,会解析html,这部分知识我提前准备过,但是答的不是很详细,大概意思就是cssom + domTree = html,然后布局和绘制</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">构建DOM树(DOM tree):从上到下解析HTML文档生成DOM节点树(DOM tree),也叫内容树(content tree);</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">构建CSSOM(CSS Object Model)树:加载解析样式生成CSSOM树;</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">执行JavaScript:加载并执行JavaScript代码(包括内联代码或外联JavaScript文件);</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">构建渲染树(render tree):根据DOM树和CSSOM树,生成渲染树(render tree);</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">渲染树:按顺序展示在屏幕上的一系列矩形,这些矩形带有字体,颜色和尺寸等视觉属性。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">布局(layout):根据渲染树将节点树的每一个节点布局在屏幕上的正确位置;</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">绘制(painting):遍历渲染树绘制所有节点,为每一个节点适用对应的样式,这一过程是通过UI后端模块完成;</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">接着面试官问我一些页面渲染层的一些优化手段,大概如下:</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 18px;color: #3da742;"><strong style="color: black;">页面渲染优化</strong></span><span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> HTML文档结构层次尽量少,最好不深于六层; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 脚本尽量后放,放在前即可; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 少量首屏样式内联放在标签内; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 样式结构层次尽量简单; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 在脚本中尽量减少DOM操作,尽量缓存访问DOM的样式信息,避免过度触发回流; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 动画尽量使用在绝对定位或固定定位的元素上; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 隐藏在屏幕外,或在页面滚动时,尽量停止动画; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 尽量缓存DOM查找,查找器尽量简洁; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 涉及多域名的网站,可以开启域名预解析 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最后面试官问我,如何诊断页面渲染时各个性能指标,我大概说了,通过chrome浏览器的工具,比如看网络请求情况的network,还有看页面渲染情况的perfermance,以后有机会自己总结一篇。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> </section> <p style="caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);text-align: start;white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span></p> <p style="caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;text-align: center;"><span style="font-size: 15px;color: rgb(136, 136, 136);"></span></p> <p style="caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);white-space: normal;text-align: center;"><span style="font-size: 15px;color: rgb(136, 136, 136);">- EOF -</span></p> <p style="caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);text-align: start;white-space: normal;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"></span><br></p> <section donone="shifuMouseDownCard('shifu_c_030')" label="Copyright Reserved by PLAYHUDONG." style="text-align: start;white-space: normal;margin-top: 1em;margin-bottom: 1em;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-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;color: rgb(255, 255, 255);background-color: rgb(255, 105, 31);font-family: inherit;text-align: inherit;text-decoration: inherit;font-size: 16px;box-sizing: border-box !important;overflow-wrap: break-word !important;">推荐阅读</span>&nbsp;&nbsp; <span style="margin-left: 4px;padding: 3px 8px;max-width: 100%;border-top-left-radius: 1.2em;border-top-right-radius: 1.2em;border-bottom-right-radius: 1.2em;border-bottom-left-radius: 1.2em;color: rgb(255, 255, 255);line-height: 1.2;background-color: rgb(204, 204, 204);font-family: inherit;text-align: inherit;text-decoration: inherit;border-color: rgb(249, 110, 87);font-size: 12px;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;"><span style="text-decoration: underline;font-size: 13px;">1、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&amp;mid=2651563109&amp;idx=1&amp;sn=003eb9ae619c96e7a3c4198a2381fca4&amp;chksm=802573a4b752fab24220d6871cd0b341f8b35862aac3f956622bd9959ae968894f60a223e5c2&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2">2 年前端 7~9 月面试经历总结</a></span></p> <p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="text-decoration: underline;font-size: 13px;">2、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&amp;mid=2651563668&amp;idx=2&amp;sn=67dbe075b51bf14644afb59d87a05d4d&amp;chksm=80257155b752f843f4f66a33999f0ae5c1b3be3c7d9991560510b50a7caf2ac20e9bf1655867&amp;scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2">12 道腾讯前端面试真题及答案整理</a></span></p> <p style="max-width: 100%;min-height: 1em;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="text-decoration: underline;font-size: 13px;">3、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&amp;mid=2651563264&amp;idx=1&amp;sn=ec486cabe5a0d62a1a3026f4d17b4dee&amp;chksm=802572c1b752fbd7b5c38a200c57ff8707743039e5fb92d9eb30cedb6b53a2494b67f35c84b6&amp;scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2">104道 CSS 面试题,助你查漏补缺(上)</a></span></p> </section> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;word-wrap: break-word !important;"></span><br></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);text-align: center;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;word-wrap: break-word !important;">觉得本文对你有帮助?请分享给更多人</span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;color: rgb(51, 51, 51);text-align: center;"><span style="font-size: 15px;"><span style="max-width: 100%;color: rgb(255, 169, 0);box-sizing: border-box !important;word-wrap: break-word !important;">推荐关注「前端大全」,提升前端技能</span></span></p> <p style="text-align: center;"><img data-copyright="0" data-ratio="0.75" data-s="300,640" src="/upload/2099e3111f50ebfc6cfc8f2c36e473d3.jpg" data-type="jpeg" data-w="600" style=""></p> <p style="text-align: right;"><span style="font-size: 14px;text-align: right;"></span><span style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-align: right;caret-color: rgb(51, 51, 51);max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">点赞和在看就是最大的支持</span><span style="font-family: -apple-system-font, system-ui, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;text-align: right;caret-color: rgb(51, 51, 51);max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">❤️</span></p>

"服务不可用"怎么排查?讲了100遍还是记不住?

作者:微信小助手

<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: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><img data-ratio="0.6333333333333333" src="/upload/faf706081f8b26948f5daeb74695529b.jpg" data-type="jpeg" data-w="960"></p> <section> <section style="color: rgba(0, 0, 0, 0.498);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: right;"> <span style="font-size: 12px;letter-spacing: 0.544px;">来</span> <span style="font-size: 12px;letter-spacing: 0.544px;">源</span> <span style="font-size: 12px;letter-spacing: 0.544px;">:</span> <span style="font-size: 12px;letter-spacing: 0.544px;">https://urlify.cn/Q3Ar6z</span> <br> </section> </section> <pre style="color: rgb(0, 0, 0);font-size: 16px;letter-spacing: 0.544px;text-align: left;"> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;"> <br> </section> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <img data-ratio="1" data-type="png" data-w="20" src="/upload/932757970322354ddd9b6e30dfca31bf.png" style="background-color: rgb(255, 255, 255);color: rgb(63, 63, 63);font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1.6px;display: inline-block;vertical-align: text-bottom;box-sizing: border-box !important;visibility: visible !important;width: 20px !important;"> <span style="letter-spacing: 1.6px;background-color: rgb(255, 255, 255);font-family: Optima-Regular, PingFangTC-light;">正文如下:</span> </section> <section style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"> <br> </section></pre> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">下面是线上机器的cpu使用率,可以看到从4月8日开始,随着时间cpu使用率在逐步增高,最终使用率达到100%导致线上服务不可用,后面重启了机器后恢复。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <figure data-tool="mdnice编辑器"> <img data-cropselx1="0" data-cropselx2="476" data-cropsely1="0" data-cropsely2="350" data-ratio="0.7352941176470589" src="/upload/1a8635261f5d704bea5244f39a870304.png" data-type="png" data-w="476" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;width: 476px;visibility: visible !important;height: 350px;"> </figure> <h3 data-tool="mdnice编辑器" style="text-align: left;"></h3> <h3 data-tool="mdnice编辑器" style="text-align: left;"><strong><span style="font-family: Optima-Regular, PingFangTC-light;"># 排查思路</span></strong></h3> <p><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">简单分析下可能出问题的地方,分为5个方向:</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="width: 577.417px;"> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 系统本身代码问题 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 内部下游系统的问题导致的雪崩效应 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 上游系统调用量突增 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> http请求第三方的问题 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 机器本身的问题 </section></li> </ul> </section> <h3 data-tool="mdnice编辑器" style="text-align: left;"></h3> <h3 data-tool="mdnice编辑器" style="text-align: left;"><strong><span style="font-family: Optima-Regular, PingFangTC-light;"># 开始排查</span></strong><span style="font-family: Optima-Regular, PingFangTC-light;"></span></h3> <p><br></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <ol data-tool="mdnice编辑器" class="list-paddingleft-2" style="width: 577.417px;"> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看日志,没有发现集中的错误日志,初步排除代码逻辑处理错误。 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 首先联系了内部下游系统观察了他们的监控,发现一起正常。可以排除下游系统故障对我们的影响。 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看provider接口的调用量,对比7天没有突增,排除业务方调用量的问题。 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看tcp监控,TCP状态正常,可以排除是http请求第三方超时带来的问题。 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看机器监控,6台机器cpu都在上升,每个机器情况一样。排除机器故障问 </section> <section style="text-align: left;"> 题。即通过上述方法没有直接定位到问题。 </section></li> </ol> </section> <h3 data-tool="mdnice编辑器" style="text-align: left;"><br></h3> <h3 data-tool="mdnice编辑器" style="text-align: left;"><strong><span style="font-family: Optima-Regular, PingFangTC-light;"># 解决方案</span></strong></h3> <p><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">1、重启了6台中问题比较严重的5台机器,先恢复业务。保留一台现场,用来分析问题。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">2、查看当前的tomcat线程pid。</span></p> <figure data-tool="mdnice编辑器"> <img data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="40" data-ratio="0.06472491909385113" src="/upload/ce0b1256ae0c1e53f501f447e36f1ec4.png" data-type="png" data-w="618" style="margin-right: auto;margin-left: auto;display: block;height: 37px;box-sizing: border-box !important;width: 578px;"> </figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">3、查看该pid下线程对应的系统占用情况。top -Hp 384</span></p> <figure data-tool="mdnice编辑器"> <img data-cropselx1="0" data-cropselx2="576" data-cropsely1="0" data-cropsely2="818" data-ratio="1.218840579710145" src="/upload/5a8cc3a1d7c597b0f930b2c97c59d9f3.png" data-type="png" data-w="690" style="margin-right: auto;margin-left: auto;background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: center center;background-repeat: no-repeat;display: block;height: 705px;box-sizing: border-box !important;width: 578px;"> </figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">4、发现pid&nbsp;4430&nbsp;4431&nbsp;4432&nbsp;4433&nbsp;线程分别占用了约40%的cpu</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">5、将这几个pid转为16进制,分别为114e&nbsp;114f&nbsp;1150&nbsp;1151</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">6、下载当前的java线程栈&nbsp;sudo -u tomcat jstack -l 384&gt;/1.txt</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">7、查询5中对应的线程情况,发现都是gc线程导致的</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <figure data-tool="mdnice编辑器"> <img data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="132" data-ratio="0.22835820895522388" src="/upload/2ca8cd06e8da5e5367bd583c647bd2fd.png" data-type="png" data-w="670" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;width: 578px;visibility: visible !important;height: 132px;"> </figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">8、dump java堆数据</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">sudo -u tomcat jmap -dump:live,format=b,file=/dump201612271310.dat 384</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">9、使用MAT加载堆文件,可以看到javax.crypto.JceSecurity对象占用了95%的内存空间,初步定位到问题。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">MAT下载地址:</span></p> <blockquote data-tool="mdnice编辑器"> <p style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">http://www.eclipse.org/mat/</span><img data-cropselx1="0" data-cropselx2="565" data-cropsely1="0" data-cropsely2="492" data-ratio="0.8701622971285893" src="/upload/69b168933c66d3836c24aea82bc78c4.png" data-type="png" data-w="801" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;width: 565px;visibility: visible !important;height: 492px;"></p> </blockquote> <figure data-tool="mdnice编辑器"> <img data-cropselx1="0" data-cropselx2="576" data-cropsely1="0" data-cropsely2="606" data-ratio="0.9027237354085603" src="/upload/c4a9b007bb060cf0f2961339026eabf.png" data-type="png" data-w="771" style="margin-right: auto;margin-left: auto;background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: center center;background-repeat: no-repeat;display: block;height: 522px;box-sizing: border-box !important;width: 578px;"> </figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">10、查看类的引用树,看到BouncyCastleProvider对象持有过多。即我们代码中对该对象的处理方式是错误的,定位到问题。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <h3 data-tool="mdnice编辑器" style="text-align: left;"><strong><span style="font-family: Optima-Regular, PingFangTC-light;"># 代码分析</span></strong></h3> <p><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">我们代码中有一块是这样写的</span></p> <figure data-tool="mdnice编辑器"> <img data-cropselx1="0" data-cropselx2="576" data-cropsely1="0" data-cropsely2="196" data-ratio="0.2917139614074915" src="/upload/d6cff95102d98a8767c9262b242a76e0.png" data-type="png" data-w="881" style="margin-right: auto;margin-left: auto;background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: center center;background-repeat: no-repeat;display: block;height: 169px;box-sizing: border-box !important;width: 578px;"> </figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">这是加解密的功能,每次运行加解密都会new一个BouncyCastleProvider对象,放倒Cipher.getInstance()方法中。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">看下Cipher.getInstance()的实现,这是jdk的底层代码实现,追踪到JceSecurity类中</span></p> <figure data-tool="mdnice编辑器"> <img data-cropselx1="0" data-cropselx2="576" data-cropsely1="0" data-cropsely2="646" data-ratio="0.9619771863117871" src="/upload/e8ea791e3bbf4ca6b6809d7f16733c31.png" data-type="png" data-w="789" style="margin-right: auto;margin-left: auto;background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: center center;background-repeat: no-repeat;display: block;height: 556px;box-sizing: border-box !important;width: 578px;"> </figure> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">verifyingProviders每次put后都会remove,verificationResults只会put,不会remove.</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><img data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="277" data-ratio="0.4792746113989637" src="/upload/37f6e1659cf458749f99c99a343b7062.png" data-type="png" data-w="772" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;width: 578px;visibility: visible !important;height: 277px;"></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">看到verificationResults是一个static的map,即属于JceSecurity类的。所以每次运行到加解密都会向这个map put一个对象,而这个map属于类的维度,所以不会被GC回收。这就导致了大量的new的对象不被回收。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <h3 data-tool="mdnice编辑器" style="text-align: left;"><strong><span style="font-family: Optima-Regular, PingFangTC-light;"># 代码改进</span></strong></h3> <p><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">将有问题的对象置为static,每个类持有一个,不会多次新建。</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <figure data-tool="mdnice编辑器"> <img data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="120" data-ratio="0.20833333333333334" src="/upload/5b08d9574c516ab7ff5515b3b74a9307.png" data-type="png" data-w="1080" style="margin-right: auto;margin-left: auto;display: block;box-sizing: border-box !important;width: 578px;visibility: visible !important;height: 120px;"> </figure> <h3 data-tool="mdnice编辑器" style="text-align: left;"><br></h3> <h3 data-tool="mdnice编辑器" style="text-align: left;"><strong><span style="font-family: Optima-Regular, PingFangTC-light;"># 本文总结</span></strong></h3> <p><br></p> <p data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;">遇到线上问题不要慌,首先确认排查问题的思路:</span></p> <p data-tool="mdnice编辑器" style="text-align: left;"><br></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <ol data-tool="mdnice编辑器" class="list-paddingleft-2" style="width: 577.417px;"> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看日志 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看CPU情况 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看TCP情况 </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看java线程,jstack </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 查看java堆,jmap </section></li> <li style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"> <section style="text-align: left;"> 通过MAT分析堆文件,寻找无法被回收的对象 </section></li> </ol> </section> <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(&quot;https://mmbiz.qpic.cn/mmbiz_png/sUbvrqLicbpzB81mjeBxPuxnYdalGxNnJo30L2Hq3WwGficcq8w5YJkLeXnsNHocN53k55TfN5mBpCdicGRyfDg1g/640?wx_fmt=png&quot;);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="2247492881_1" data-recommend-article-time="1614040140" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtYLhPF7twsn8EDqCy16n8NooMW6apLDCrM6LcWT0AZtIy0XGn37P8754W6ic0KDzYRYUvmFialBC5nQ/0?wx_fmt=jpeg" data-recommend-article-title="为什么汉字不能当密码,假如用汉字做密码,又会怎样?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492881&amp;idx=1&amp;sn=30025ed2a590269e6a3f92f0bc8068a7&amp;chksm=97b47b09a0c3f21fcab116c064a144e33fb542f6a2a5fe480caa1ef83fb418598e6545eab239#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492881&amp;idx=1&amp;sn=30025ed2a590269e6a3f92f0bc8068a7&amp;chksm=97b47b09a0c3f21fcab116c064a144e33fb542f6a2a5fe480caa1ef83fb418598e6545eab239&amp;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="">为什么汉字不能当密码,假如用汉字做密码,又会怎样?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247492869_1" data-recommend-article-time="1613953740" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtbicRzxlOzbYX2BODMyfBqzmTYrahBUpz42gQFllCO2g8l6ibvWOHu6615RBQKff2xoFLibVFBJagZ5A/0?wx_fmt=jpeg" data-recommend-article-title="Spring中涉及的设计模式总结" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492869&amp;idx=1&amp;sn=9274fdac4f943f054988158e74a2acd1&amp;chksm=97b47b1da0c3f20bf6bbff44726bed96b5bb88a2425bd3c6193b06905784fa75c5e40453e1c5#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492869&amp;idx=1&amp;sn=9274fdac4f943f054988158e74a2acd1&amp;chksm=97b47b1da0c3f20bf6bbff44726bed96b5bb88a2425bd3c6193b06905784fa75c5e40453e1c5&amp;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="">Spring中涉及的设计模式总结</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247492855_1" data-recommend-article-time="1612484940" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtZ1taAsOIulnoiah9lnicCNdfjST64ANjibnoAnPcibhx0YeDqz5S1au5qyibehxtdjTMH9rMCK8PdUicCg/0?wx_fmt=jpeg" data-recommend-article-title="到底是什么原因才导致 select * 效率低下的?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492855&amp;idx=1&amp;sn=b9214c4d1bfca5f8379b28104d1d02e5&amp;chksm=97b47aefa0c3f3f920f00dc638f6ea2038d8b62033bcb397308c6afe8aab7181bf3b222a51f5#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492855&amp;idx=1&amp;sn=b9214c4d1bfca5f8379b28104d1d02e5&amp;chksm=97b47aefa0c3f3f920f00dc638f6ea2038d8b62033bcb397308c6afe8aab7181bf3b222a51f5&amp;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="">到底是什么原因才导致 select * 效率低下的?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247492841_1" data-recommend-article-time="1612398540" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtbtN7Nctwk4xVNrtO8071iaibRkhuq9U6ibz5ApBM3ZDqB1zaibHLcP605IBU3rxEVDvZZ9wDFh5deCQg/0?wx_fmt=jpeg" data-recommend-article-title="@Autowire 和 @Resource 注解使用的正确姿势,别再用错的了!!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492841&amp;idx=1&amp;sn=7b1a42e2763dabfdf5279a20e9ceee46&amp;chksm=97b47af1a0c3f3e73775f37583787e76435f99decbe1dea6901d95d3d834726715a021e670bb#rd"> <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=""><a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247492841&amp;idx=1&amp;sn=7b1a42e2763dabfdf5279a20e9ceee46&amp;chksm=97b47af1a0c3f3e73775f37583787e76435f99decbe1dea6901d95d3d834726715a021e670bb&amp;scene=21#wechat_redirect" data-linktype="2">@Autowire 和 @Resource 注解使用的正确姿势,别再用错的了!!</a></p> </section> </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(255, 104, 39);"></span></p> <section data-mpa-template="t" mpa-from-tpl="t" style="white-space: normal;"> <p style="text-align: center;"><span style="color: rgb(140, 140, 140);letter-spacing: 0.008em;font-size: 14px;">一起进大厂,每日学干货</span></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(140, 140, 140);font-size: 14px;"><span style="font-size: 15px;letter-spacing: 0.12px;text-align: center;color: rgb(0, 0, 0);"><strong><span style="font-size: 14px;">关注我回复【</span></strong></span><span style="font-size: 15px;letter-spacing: 0.12px;text-align: center;color: rgb(255, 76, 65);"><strong><span style="font-size: 14px;">加群</span></strong></span><span style="font-size: 15px;letter-spacing: 0.12px;text-align: center;color: rgb(0, 0, 0);"><strong><span style="font-size: 14px;">】,加入Java技术交流群</span></strong></span></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&nbsp;年<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;"> ↓↓↓&nbsp; </section> </section> </section> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <section style="text-align: left;"> <span style="font-size: 16px;font-family: Optima-Regular, PingFangTC-light;"></span> </section> </section>