文章列表

关于动态生成html里的点击事件

作者:仲夏时节的梦想

aja请求返回的json数据通过for循环拼接成动态Html ![](/upload/f0520584e5f545df86be56fe9ed99437.png) 其中一段代码是这样的 ``` '<td><span ><i class="compile"></i><i id="delete'+i+'" class="delete" data="'+message[i].id+'" onclick="del('+i+')"></i></span></td></tr>' ``` 1 其中一个i标签是点击删除功能,利用普通的$('#').click() 这种选择无效,必须在for循环遍历的时候直接跟一个onclick事件,如上面代码。 2 在onclick事件执行时,需要传对应的id, onclick="del('+message[i].id+')",这种情况会报错,具体为什么我也不知道。可行的方法是 del()方法里传i(i是for循环的变量),然后在点击事件的生效的标签上加个id="一段写死的字符串+i",如上面代码,然后data属性里存要传递的值。最后在del()方法里这样写就可以了: ``` function del(i){ var id = $('#delete'+i).attr("data"); alert(id) } ```

Linux 解压7z文件

作者:じ☆ve宝贝

## 1.下载安装包 yum install p7zip (自动完成安装) 手动下载 http://nchc.dl.sourceforge.net/sourceforge/p7zip/p7zip_4.65_src_all.tar.bz2 ## 2.解压 tar -xjvf p7zip_4.65_src_all.tar.bz2 ## 3.安装 cd p7zip_4.65 make && make install ## 4.常见问题 这时如果发现乱码,请执行命令export LANG=zh_CN.GBK ## 常用命令: 7za e ishagua.7z 解压到当前目录下,不保留原来的目录结构 7za x ishagua.7z 解压到当前目录下,但保留原来的目录结构

弥补MySQL和Redis短板:看HBase怎么确保高可用

作者:微信小助手

<section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;">HBase 是一个基于 Hadoop 面向列的非关系型分布式数据库(NoSQL),设计概念来源于谷歌的 BigTable 模型。</span></p> </section> <section style="clear: both;box-sizing: border-box;"></section> </section> </section> </section> </section> <p style="line-height: 1.75em;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.5148514851485149" data-s="300,640" src="/upload/f7cd3efb8210ade74d7ca592f2be8a43.png" data-type="png" data-w="707" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">它面向实时读写、随机访问大规模数据集的场景,是一个高可靠性、高性能、高伸缩的分布式存储系统,在大数据相关领域应用广泛。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">HBase 系统支持对所存储的数据进行透明切分,从而使得系统的存储以及计算具有良好的水平扩展性。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">知乎从 2017 年起开始逐渐采用 HBase 系统存储各类在线业务数据,并在 HBase 服务之上构建各类应用模型以及数据计算任务。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">伴随着知乎这两年的发展,知乎核心架构团队基于开源容器调度平台 Kubernetes 打造了一整套 HBase 服务平台管理系统。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">经过近两年的研发迭代,目前已经形成了一套较为完整的 HBase 自动化运维服务体系,能够完成 HBase 集群的快捷部署、平滑扩缩容、HBase 组件细粒度监控、故障跟踪等功能。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">知乎对 HBase 的使用经验不算太长,在 2017 年初的时候,HBase 服务主要用于离线算法、推荐、反作弊,还有基础数据仓库数据的存储计算,通过 MapReduce 和 Spark 来进行访问。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">而在当时知乎的在线存储主要采用 MySQL 和 Redis 系统,其中:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MySQL:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">支持大部分的业务数据存储,当数据规模增大后有一些需要进行扩容的表,分表会带来一定的复杂性。</span></p><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">有些业务希望能屏蔽这个事情,还有一些是因为历史原因在表设计的时候用 rmsdb 的形式存了一些本该由列存储的数据,希望做一下迁移。此外 MySQL 基于 SSD,虽然性能很好,花销也比较大。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Redis:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可以提供大规模的缓存,也可以提供一定的存储支持。Redis 性能极好,主要的局限是做数据 Resharding 较为繁琐,其次是内存成本较高。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">针对以上两种在线存储所存在的一些问题,我们希望建立一套在线存储 NoSQL 服务,对以上两种存储作为一个补充。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">选型期间我们也考虑过 Cassandra,早期一些业务曾尝试使用 Cassandra 作为存储。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">隔壁团队在运维了一段时间的 Cassandra 系统之后,遇到不少的问题,Cassandra 系统可操作性没有达到预期,目前除了 Tracing 相关的系统,其他业务已经放弃使用 Cassandra。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们从已有的离线存储系统出发,在衡量了稳定性、性能、代码成熟度、上下游系统承接、业界使用场景以及社区活跃度等方面之后,选择了 HBase,作为知乎在线存储的支撑组件之一。</span></p> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="86122" data-color="#138bde"> <section> <section> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">HBase On Kubernetes</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> </section> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">初期知乎只有一套进行离线计算的集群,所有业务都跑在一个集群上,并且 HBase 集群和其他离线计算 Yarn 以及 Impala 混合部署,HBase 的日常离线计算和数据读写都严重受到其他系统影响。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">并且 HBase 的监控都只停留在主机层面的监控,出现运行问题时,进行排查很困难,系统恢复服务时间较长,这种状态下,我们需要重新构建一套适用于在线服务的系统。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;letter-spacing: 1px;line-height: 1.75em;color: rgb(71, 193, 168);">在这样的场景下,我们对在线 HBase 服务的需求是明确的:</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);"><strong><span style="font-size: 15px;letter-spacing: 1px;">①隔离性:</span></strong></span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">从业务方的视角来说,希望相关的服务做到环境隔离,权限收归业务,避免误操作和业务相互影响。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">对于响应时间,服务的可用性,都可以根据业务的需要指定 SLA;</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">对于资源的分配和 blockcache 等参数的配置也能够更加有适应性,提供业务级别的监控和报警,快速定位和响应问题。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②资源利用率:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">从运维的角度,资源的分配要合理,尽可能的提升主机 CPU,内存包括磁盘的有效利用率。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">③成本控制:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">团队用最小的成本去得到最大的运维收益,所以需要提供便捷的调用接口,能够灵活的进行 HBase 集群的申请、扩容、管理、监控。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">同时成本包括机器资源,还有工程师。当时我们线上的这套系统是由一位工程师独立去进行维护。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">综合以上需求,参考我们团队之前对基础设施平台化的经验,最终的目标是把 HBase 服务做成基础组件服务平台提供给上游业务。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这个也是知乎技术平台部门工作思路之一,尽可能的把所有的组件对业务都黑盒化,接口化,服务化。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">同时在使用和监控的粒度上尽可能的准确,细致,全面。这是我们构建在线 HBase 管理运维系统的一个初衷。</span></p> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="86122" data-color="#138bde"> <section> <section> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">Why Kubernetes?</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">前文说到我们希望将整个 HBase 系统平台服务化,那就涉及到如何管理和运维 HBase 系统,知乎在微服务和容器方面的工作积累和经验是相当丰富的:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在当时我们所有的在线业务都已经完成了容器化的迁移工作,超万级别的业务容器平稳运行在基于 Mesos 的容器管理平台 Bay 上(参见[1])。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">与此同时,团队也在积极的做着 Infrastructure 容器化的尝试,已经成功将基础消息队列组件 Kafka 容器化运行于 Kubernetes 系统之上(参见[2]),因此我们决定也将 HBase 通过 Kubernetes 来进行资源的管理调度。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kubernetes 是谷歌开源的容器集群管理系统,是 Google 多年大规模容器管理技术 Borg 的开源版本。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kubernetes 提供各种维度组件的资源管理和调度方案,隔离容器的资源使用,各个组件的 HA 工作,同时还有较为完善的网络方案。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kubernetes 被设计作为构建组件和工具的生态系统平台,可以轻松地部署、扩展和管理应用程序。有着 Kubernetes 大法的加持,我们很快有了最初的落地版本([4])。</span></p> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="86122" data-color="#138bde"> <section> <section> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">初代架构</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">最初的落地版本架构见下图,平台在共享的物理集群上通过 Kubernetes(以下简称 K8S)API 建立了多套逻辑上隔离的 HBase 集群。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每套集群由一组 Master 和若干个 Regionserver(以下简称 RS)构成,集群共享一套 HDFS 存储集群,各自依赖的 Zookeeper 集群独立;集群通过一套管理系统 Kubas 服务来进行管理([4])。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-croporisrc="/upload/2d628eed0c19f1fabc6019fc1f625a6.jpg" data-cropx1="0" data-cropx2="720" data-cropy1="0" data-cropy2="565.8715596330276" data-ratio="0.7847222222222222" data-s="300,640" data-type="jpeg" data-w="720" src="https://mmbiz.qpic.cn/mmbiz_jpg/tibrg3AoIJTsbWP5dyM3ibwP0FAlL3rwW1sQ0APC4k1sMicFycteU58auyN8Cs64dgqDSUOdMEicx0fqH4iaLdvp4Yg/640?wx_fmt=jpeg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 654px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">第一代架构</span></em></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">模块定义:</span></strong><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">在 K8S 中如何去构建 HBase 集群,首先需要用 K8S 本身的基础组件去描述 HBase 的构成。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">K8S 的资源组件有以下几种:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Node:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">定义主机节点,可以是物理机,也可以是虚拟机;</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Pod:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">一组紧密关联的容器集合,是 K8S 调度的基本单位;</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">ReplicationController:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">一组 Pod 的控制器,通过其能够确保 Pod 的运行数量和健康,并能够弹性伸缩。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">结合之前 Kafka on K8S 的经验,出于高可用和扩展性的考虑,我们没有采用一个 Pod 里带多个容器的部署方式。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而是统一用一个 ReplicationController 定义一类HBase组件,就是上图中的 Master,Regionserver 还有按需创建的 Thriftserver。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">通过以上概念,我们在 K8S 上就可以这样定义一套最小 HBase 集群:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">2*MasterReplicationController</span></strong></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">3*RegionserverReplicationController</span></strong></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">2*ThriftserverReplicationController(可选)</span></strong></p></li> </ul> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="86122" data-color="#138bde"> <section> <section> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">高可用以及故障恢复</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">作为面向在线业务服务的系统,高可用和故障转移是必需在设计就要考虑的事情,在整体设计中,我们分别考虑组件级别、集群级别和数据存储级别的可用性和故障恢复问题。</span></p> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde"> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde" data-custom="#1e9be8"> <section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①组件级别</span></strong></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(71, 193, 168);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">HBase 本身已经考虑了很多故障切换和恢复的方案:</span></p> </section> </section> </section> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Zookeeper 集群:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">自身设计保证了可用性。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Master:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通过多个 Master 注册在 Zookeeper 集群上来进行主节点的 HA 和更新。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">RegionServer:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">本身就是无状态的,节点失效下线以后会把上面的 Region 自动迁走,对服务可用性不会有太大影响。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Thriftserver:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当时业务大多数是 Python 和 Golang,通过用 Thrift 对 HBase 的进行,Thriftserver 本身是单点的,这里我们通过 HAProxy 来代理一组 Thriftserver 服务。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">HDFS:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">本身又由 Namenode 和 DataNode 节点组成,Namenode 我们开启 HA 功能,保证了 HDFS 的集群可用性。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde"> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde" data-custom="#1e9be8"> <section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②集群级别</span></strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">关于集群级别:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Pod 容器失效:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Pod 是通过 Replication Controller 维护的,K8S 的 Controller Manager 会在它的存储 etcd 去监听组件的失效情况,如果副本少于预设值会自动新的 Pod 容器来进行服务。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kubernetes 集群崩溃:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">该场景曾经在生产环境中出现过,针对这种情况,我们对 SLA 要求较高的业务采用了少量物理机搭配容器的方式进行混合部署,极端场景出现时,可以保证重要业务受到的影响可控。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde"> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde" data-custom="#1e9be8"> <section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">③数据级别</span></strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">所有在 K8S 上构建的 HBase 集群都共享了一套 HDFS 集群,数据的可用性由 HDFS 集群的多副本来提供。</span></p> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="86122" data-color="#138bde"> <section> <section> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">实现细节</p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> </section> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde"> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde" data-custom="#1e9be8"> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>资源分配</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">初期物理节点统一采用 2*12 核心的 CPU,128G 内存和 4T 的磁盘,其中磁盘用于搭建服务的 HDFS,CPU 和内存则在 K8S 环境中用于建立 HBase 相关服务的节点。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Master 组件的功能主要是管理 HBase 集群,Thriftserver 组件主要承担代理的角色,所以这两个组件资源都按照固定额度分配。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在对 Regionserver 组件进行资源分配设计的时候,考虑两种方式去定义资源:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-croporisrc="/upload/c89b465131569ab38f6086eec644388.jpg" data-cropx1="0" data-cropx2="720" data-cropy1="0" data-cropy2="432.66055045871565" data-ratio="0.6" data-s="300,640" data-type="jpeg" data-w="720" src="https://mmbiz.qpic.cn/mmbiz_jpg/tibrg3AoIJTsbWP5dyM3ibwP0FAlL3rwW13SC5ibQJd2bEFejcpVSwkgFh7C64cZqibB0m2yYuuKo2PGypyhBCHfcQ/640?wx_fmt=jpeg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 654px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">资源分配方式</span></em></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">按照业务需求分配:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">根据业务方对自身服务的描述,对相关的 QPS 以及 SLA 进行评估,为业务专门配置参数,包含 Blockcache,Region 大小以及数量等。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">优点是针对业务优化,能够充分的利用资源,降低业务的资源占用成本。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">管理成本增加,需要对每一个业务进行评估,对平台维护人员非常不友好,同时需要业务同学本身对 HBase 有理解。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">统一规格的资源分配:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">CPU 以及 MEM 都按照预先设定好的配额来分配,提供多档的配置,将 CPU 和 MEM 的配置套餐化。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">方便之处在于业务扩容时直接增加 Regionserver 的个数,配置稳定,运维成本较低,遇到问题时排障方便。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">针对某些有特有访问方式的业务有局限性,如 CPU 计算型,大 KV 存储,或者有 MOB 需求的业务,需要特殊的定制。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">介于当时考虑接入的在线业务并不多,所以采用了按业务定制的方式去配置 Regionserver,正式环境同一业务采用统一配置的一组 Regionserver,不存在混合配置的 Regionserver 组。</span></p></li> </ul> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde"> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde" data-custom="#1e9be8"> <section> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>参数配置</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs vbnet" style="overflow-wrap: break-word;margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);padding: 0.5em;display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: none 0% 0% repeat scroll rgb(40, 43, 46);"><span class="hljs-meta" style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);word-wrap: inherit !important;word-break: inherit !important;">#&nbsp;Example&nbsp;for&nbsp;hbase&nbsp;dockerfile&nbsp;</span><br><span class="hljs-meta" style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);word-wrap: inherit !important;word-break: inherit !important;">#&nbsp;install&nbsp;cdh5.5.0-hbase1.0.0</span><br>ADD&nbsp;hdfs-site.xml&nbsp;/usr/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">lib</span>/hbase/conf/<br>ADD&nbsp;core-site.xml&nbsp;/usr/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">lib</span>/hbase/conf/<br>ADD&nbsp;env-init.py&nbsp;/usr/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">lib</span>/hbase/bin/<br>ENV&nbsp;JAVA_HOME&nbsp;/usr/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">lib</span>/jvm/java<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">-8</span>-oracle<br>ENV&nbsp;HBASE_HOME&nbsp;/usr/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">lib</span>/hbase<br>ENV&nbsp;HADOOP_PREFIX&nbsp;/usr/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">lib</span>/hadoop<br>ADD&nbsp;env-init.py&nbsp;/usr/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">lib</span>/hbase/bin/<br>ADD&nbsp;hadoop_xml_conf.sh&nbsp;/usr/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">lib</span>/hbase/bin/<br></code></pre> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">基础镜像基于 cdh5.5.0-hbase1.0.0 构建:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">固定的环境变量,如 JDK_HOME,HBASE_HOME,都通过 ENV 注入到容器镜像中。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">与 HDFS 相关的环境变量,如 hdfs-site.xml 和 core-site.xml 预先加入 Docker 镜像中,构建的过程中就放入了 HBase 的相关目录中,用以确保 HBase 服务能够通过对应配置访问到 HDFS。</span></p></li> <li><p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">与 HBase 相关的配置信息,如组件启动依赖的 Zookeeper 集群地址, HDFS 数据目录路径,堆内存以及 GC 参数等,这些配置都需要根据传入 KubasService 的信息进行对应变量的修改。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">一个典型的传入参数示例:</span></p> <section class="" data-tools="135编辑器" data-id="88286" data-color="#138bde"> <section> <section> <section class=""> <section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs bash" style="overflow-wrap: break-word;margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);padding: 0.5em;display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: none 0% 0% repeat scroll rgb(40, 43, 46);">REQUEST_DATA&nbsp;=&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"name"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">'test-cluster'</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"rootdir"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"hdfs://namenode01:8020/tmp/hbase/test-cluster"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"zkparent"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"/test-cluster"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"zkhost"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"zookeeper01,zookeeper02,zookeeper03"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"zkport"</span>:&nbsp;2181,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"regionserver_num"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">'3'</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"codecs"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"snappy"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"client_type"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"java"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"cpu"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">'1'</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"memory"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">'30'</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"status"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"running"</span>,<br>}<br></code></pre> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通过上面的参数 KubasService 启动 Docker 时,在启动命令中利用 hadoop_xml_conf.sh 和 env-init.py 修改 hbase-site.xml 和 hbase-env.sh 文件来完成最后的配置注入,如下所示:</span></p> <section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs delphi" style="overflow-wrap: break-word;margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);padding: 0.5em;display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: none 0% 0% repeat scroll rgb(40, 43, 46);">source&nbsp;/usr/lib/hbase/bin/hadoop_xml_conf.sh<br>&amp;&amp;&nbsp;put_config&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">file</span>&nbsp;/etc/hbase/conf/hbase-site.xml&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">property</span>&nbsp;hbase.regionserver.codecs&nbsp;--value&nbsp;snappy<br>&amp;&amp;&nbsp;put_config&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">file</span>&nbsp;/etc/hbase/conf/hbase-site.xml&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">property</span>&nbsp;zookeeper.znode.parent&nbsp;--value&nbsp;/test-cluster<br>&amp;&amp;&nbsp;put_config&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">file</span>&nbsp;/etc/hbase/conf/hbase-site.xml&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">property</span>&nbsp;hbase.rootdir&nbsp;--value&nbsp;hdfs:<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);word-wrap: inherit !important;word-break: inherit !important;">//namenode01:8020/tmp/hbase/test-cluster</span><br>&amp;&amp;&nbsp;put_config&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">file</span>&nbsp;/etc/hbase/conf/hbase-site.xml&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">property</span>&nbsp;hbase.zookeeper.quorum&nbsp;--value&nbsp;zookeeper01,zookeeper02,zookeeper03<br>&amp;&amp;&nbsp;put_config&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">file</span>&nbsp;/etc/hbase/conf/hbase-site.xml&nbsp;--<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">property</span>&nbsp;hbase.zookeeper.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">property</span>.clientPort&nbsp;--value&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">2181</span><br>&amp;&amp;&nbsp;service&nbsp;hbase-regionserver&nbsp;start&nbsp;&amp;&amp;&nbsp;tail&nbsp;-f&nbsp;/<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">var</span>/log/hbase/hbase-hbase-regionserver.log<br></code></pre> </section> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde"> <section class="" data-tools="135编辑器" data-id="39" data-color="#138bde" data-custom="#1e9be8"> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>网络通信</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">网络方面,采用了 Kubernetes 上原生的网络模式,每一个 Pod 都有自己的 IP 地址,容器之间可以直接通信。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">同时在 Kubernetes 集群中添加了 DNS 自动注册和反注册功能,以 Pod 的标识名字作为域名,在 Pod 创建和重启和销毁时将相关信息同步全局 DNS。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在这个地方我们遇到过问题,当时我们的 DNS 解析不能在 Docker 网络环境中通过 IP 反解出对应的容器域名。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这就使得 Regionserver 在启动之后向 Master 注册和向 Zookeeper 集群注册的服务名字不一致。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">导致 Master 中对同一个 Regionserver 登记两次,造成 Master 与 Regionserver 无法正常通信,整个集群无法正常提供服务。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">经过我们对源码的研究和实验之后,我们在容器启动 Regionserver 服务之前修改 /etc/hosts 文件,将 Kubernetes 对注入的 hostname 信息屏蔽。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这样的修改让容器启动的 HBase 集群能够顺利启动并初始化成功,但是也给运维提升了复杂度。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因为现在 HBase 提供的 Master 页现在看到的 Regionserver 都是 IP 形式的记录,给监控和故障处理带来了诸多不便。</span></p> <p style="line-height: normal;"><br></p> <section class="" data-tools="135编辑器" data-id="86122" data-color="#138bde"> <section> <section> <section> <section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">存在问题</p> </section> </section> </section> </section> <p style="line-height: normal;"><b

别再说你不会ElasticSearch调优了,都给你整理好了

作者:微信小助手

<pre data-mpa-powered-by="yiban.io"><p style="line-height: 1.75em;"><span style="font-size: 12px;letter-spacing: 1px;color: rgb(136, 136, 136);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><img class="mpa-image" data-backh="370" data-backw="556" data-before-oversubscription-url="http://mmbiz.qpic.cn/mmbiz_jpg/z79yIbGBEQBSBmxP6u3PdU8DFXv36hTS8LbiacWzeKBndjhRoZHAIqrpRK2ZoWXia02MDaUsNh3rDLW5o1DjF9KQ/0" data-ratio="0.6666666666666666" src="/upload/681541741a81d098721ac0c0e032dda5.null" data-w="960" style="width: 100%;height: auto;"></span></p><p style="line-height: 1.75em;"><span style="font-size: 12px;letter-spacing: 1px;color: rgb(136, 136, 136);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">作者:Ghost Stories<br>原文:http://wangnan.tech/post/elasticsearch-how-to/</span></p></pre> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">ES 发布时带有的默认值,可为 ES 的开箱即用带来很好的体验。全文搜索、高亮、聚合、索引文档 等功能无需用户修改即可使用,当你更清楚的知道你想如何使用 ES 后,你可以作很多的优化以提高你的用例的性能,下面的内容告诉你 你应该/不应该 修改哪些配置。</span></p> <h3 style="box-sizing: border-box;font-weight: bold;font-size: 18px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.75em;margin-top: 1.5em !important;margin-bottom: 1.5em !important;padding-top: 0.5em !important;padding-bottom: 0.5em !important;color: rgb(0, 150, 136) !important;"><span style="color: rgb(255, 76, 65);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><strong><span style="color: rgb(255, 76, 65);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;box-sizing: border-box;letter-spacing: 1px;font-size: 18px;">第一部分:调优索引速度</span></strong></span></h3> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="color: rgb(0, 128, 255);letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-indexing-speed.html</span></p> <p style="line-height: 1.75em;"><span style="box-sizing: border-box;letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">使用批量请求批量请求将产生比单文档索引请求好得多的性能。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">为了知道批量请求的最佳大小,您应该在具有单个分片的单个节点上运行基准测试。 首先尝试索引100个文件,然后是200,然后是400,等等。 当索引速度开始稳定时,您知道您达到了数据批量请求的最佳大小。 在配合的情况下,最好在太少而不是太多文件的方向上犯错。 请注意,如果群集请求太大,可能会使群集受到内存压力,因此建议避免超出每个请求几十兆字节,即使较大的请求看起来效果更好。</span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">发送端使用多worker/多线程向es发送数据,发送批量请求的单个线程不太可能将Elasticsearch群集的索引容量最大化。 为了使用集群的所有资源,您应该从多个线程或进程发送数据。 除了更好地利用集群的资源,这应该有助于降低每个fsync的成本。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">请确保注意TOO_MANY_REQUESTS(429)响应代码(Java客户端的EsRejectedExecutionException),这是Elasticsearch告诉您无法跟上当前索引速率的方式。 发生这种情况时,应该再次尝试暂停索引,理想情况下使用随机指数回退。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">与批量调整大小请求类似,只有测试才能确定最佳的worker数量。 这可以通过逐渐增加工作者数量来测试,直到集群上的I / O或CPU饱和。</span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">调大 refresh interval。<span style="font-size: 16px;letter-spacing: 1px;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;">默认的index.refresh_interval是1s,这迫使Elasticsearch每秒创建一个新的分段。 增加这个价值(比如说30s)将允许更大的部分flush并减少未来的合并压力。</span></span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><br></span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">加载大量数据时禁用refresh和replicas。如果您需要一次加载大量数据,则应该将index.refresh_interval设置为-1并将index.number_of_replicas设置为0来禁用刷新。这会暂时使您的索引处于危险之中,因为任何分片的丢失都将导致数据 丢失,但是同时索引将会更快,因为文档只被索引一次。 初始加载完成后,您可以将index.refresh_interval和index.number_of_replicas设置回其原始值。</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">设置参数,禁止OS将es进程swap出去<br style="box-sizing: border-box;">您应该确保操作系统不会swapping out the java进程,通过禁止swap<br style="box-sizing: border-box;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;letter-spacing: 1px;color: rgb(0, 128, 255);">https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration-memory.html</span></span></p> <p style="line-height: 1.75em;"><span style="color: rgb(0, 128, 255);letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><br></span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">为filesystem cache分配一半的物理内存<br style="box-sizing: border-box;">文件系统缓存将用于缓冲I / O操作。 您应该确保将运行Elasticsearch的计算机的内存至少减少到文件系统缓存的一半。</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">使用自动生成的id(auto-generated ids)<br style="box-sizing: border-box;">索引具有显式id的文档时,Elasticsearch需要检查具有相同id的文档是否已经存在于相同的分片中,这是昂贵的操作,并且随着索引增长而变得更加昂贵。 通过使用自动生成的ID,Elasticsearch可以跳过这个检查,这使索引更快。</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">买更好的硬件<br style="box-sizing: border-box;">搜索一般是I/O 密集的,此时,你需要<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;a.为filesystem cache分配更多的内存<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;b.使用SSD硬盘<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;c.使用local storage(不要使用NFS、SMB 等remote filesystem)<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;d.亚马逊的 弹性块存储(Elastic Block Storage)也是极好的,当然,和local storage比起来,它还是要慢点,如果你的搜索是 CPU-密集的,买好的CPU吧</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">加大 indexing buffer size<br style="box-sizing: border-box;">如果你的节点只做大量的索引,确保index.memory.index_buffer_size足够大,每个分区最多可以提供512 MB的索引缓冲区,而且索引的性能通常不会提高。 Elasticsearch采用该设置(java堆的一个百分比或绝对字节大小),并将其用作所有活动分片的共享缓冲区。 非常活跃的碎片自然会使用这个缓冲区,而不是执行轻量级索引的碎片。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">默认值是10%,通常很多:例如,如果你给JVM 10GB的内存,它会给索引缓冲区1GB,这足以承载两个索引很重的分片。</span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">禁用_field_names字段<br style="box-sizing: border-box;">_field_names 字段引入了一些索引时间开销,所以如果您不需要运行存在查询,您可能需要禁用它。<br style="box-sizing: border-box;">_field_names:<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;letter-spacing: 1px;color: rgb(0, 128, 255);">https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-field-names-field.html</span></span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">剩下的,再去看看 “调优 磁盘使用”吧<br style="box-sizing: border-box;"><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;letter-spacing: 1px;color: rgb(0, 128, 255);">https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-disk-usage.html&nbsp;</span>中有许多磁盘使用策略也提高了索引速度。</span></p> <h3 style="box-sizing: border-box;font-weight: bold;font-size: 18px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.75em;margin-top: 1.5em !important;margin-bottom: 1.5em !important;padding-top: 0.5em !important;padding-bottom: 0.5em !important;color: rgb(0, 150, 136) !important;"><span style="color: rgb(255, 76, 65);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><strong><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(255, 76, 65);box-sizing: border-box;letter-spacing: 1px;font-size: 18px;">第二部分-调优搜索速度</span></strong></span></h3> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">filesystem cache越大越好<br style="box-sizing: border-box;">为了使得搜索速度更快, es严重依赖filesystem cache<br style="box-sizing: border-box;">一般来说,需要至少一半的 可用内存 作为filesystem cache,这样es可以在物理内存中 保有 索引的热点区域(hot regions of the index)</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">用更好的硬件<br style="box-sizing: border-box;">搜索一般是I/O bound的,此时,你需要<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;a.为filesystem cache分配更多的内存<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;b.使用SSD硬盘<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;c.使用local storage(不要使用NFS、SMB 等remote filesystem)<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;d.亚马逊的 弹性块存储(Elastic Block Storage)也是极好的,当然,和local storage比起来,它还是要慢点<br style="box-sizing: border-box;">如果你的搜索是 CPU-bound,买好的CPU吧</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">文档模型(document modeling)<br style="box-sizing: border-box;">文档需要使用合适的类型,从而使得 search-time operations 消耗更少的资源。咋作呢?<br style="box-sizing: border-box;">答:避免 join操作。具体是指<br style="box-sizing: border-box;">a.nested 会使得查询慢 好几倍<br style="box-sizing: border-box;">b.parent-child关系 更是使得查询慢几百倍<br style="box-sizing: border-box;">如果 无需join 能解决问题,则查询速度会快很多</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">预索引 数据<br style="box-sizing: border-box;">根据“搜索数据最常用的方式”来最优化索引数据的方式<br style="box-sizing: border-box;">举个例子:<br style="box-sizing: border-box;">所有文档都有price字段,大部分query 在 fixed ranges 上运行 range aggregation。你可以把给定范围的数据 预先索引下。然后,使用 terms aggregation</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">Mappings(能用 keyword 最好了)<br style="box-sizing: border-box;">数字类型的数据,并不意味着一定非得使用numeric类型的字段。<br style="box-sizing: border-box;">一般来说,存储标识符的 字段(书号ISBN、或来自数据库的 标识一条记录的 数字),使用keyword更好(integer,long 不好哦,亲)<br style="box-sizing: border-box;"><br></span></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">6.避免运行脚本<br style="box-sizing: border-box;">一般来说,脚本应该避免。 如果他们是绝对需要的,你应该使用painless和expressions引擎。</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">搜索rounded 日期<br style="box-sizing: border-box;">日期字段上使用now,一般来说不会被缓存。但,rounded date则可以利用上query cache rounded到分钟等</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">强制merge只读的index<br style="box-sizing: border-box;">只读的index可以从“merge成 一个单独的 大segment”中收益</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">预热 全局序数(global ordinals)<br style="box-sizing: border-box;">全局序数 用于 在 keyword字段上 运行 terms aggregations<br style="box-sizing: border-box;">es不知道 哪些fields 将 用于/不用于 term aggregation,因此 全局序数 在需要时才加载进内存,但,可以在mapping type上,定义 eager_global_ordinals==true,这样,refresh时就会加载 全局序数</span></p> <p><br></p> <p style="line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">预热 filesystem cache<br style="box-sizing: border-box;">机器重启时,filesystem cache就被清空。OS将index的热点区域(hot regions of the index)加载进filesystem cache是需要花费一段时间的。<br style="box-sizing: border-box;">设置 index.store.preload 可以告知OS 这些文件需要提早加载进入内存</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">11使用索引排序来加速连接<br style="box-sizing: border-box;">索引排序对于以较慢的索引为代价来加快连接速度非常有用。在索引分类文档中阅读更多关于它的信息。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">12.使用preference来优化高速缓存利用率<br style="box-sizing: border-box;">有多个缓存可以帮助提高搜索性能,例如文件系统缓存,请求缓存或查询缓存。然而,所有这些缓存都维护在节点级别,这意味着如果连续运行两次相同的请求,则有一个或多个副本,并使用循环(默认路由算法),那么这两个请求将转到不同的分片副本,阻止节点级别的缓存帮助。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">由于搜索应用程序的用户一个接一个地运行类似的请求是常见的,例如为了分析索引的较窄的子集,使用标识当前用户或会话的优选值可以帮助优化高速缓存的使用。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">13.副本可能有助于吞吐量,但不会一直存在<br style="box-sizing: border-box;">除了提高弹性外,副本可以帮助提高吞吐量。例如,如果您有单个分片索引和三个节点,则需要将副本数设置为2,以便共有3个分片副本,以便使用所有节点。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">现在假设你有一个2-shards索引和两个节点。在一种情况下,副本的数量是0,这意味着每个节点拥有一个分片。在第二种情况下,副本的数量是1,这意味着每个节点都有两个碎片。哪个设置在搜索性能方面表现最好?通常情况下,每个节点的碎片数少的设置将会更好。原因在于它将可用文件系统缓存的份额提高到了每个碎片,而文件系统缓存可能是Elasticsearch的1号性能因子。同时,要注意,没有副本的设置在发生单个节点故障的情况下会出现故障,因此在吞吐量和可用性之间进行权衡。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">那么复制品的数量是多少?如果您有一个具有num_nodes节点的群集,那么num_primaries总共是主分片,如果您希望能够一次处理max_failures节点故障,那么正确的副本数是max(max_failures,ceil(num_nodes / num_primaries) - 1)。</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">14.打开自适应副本选择<br style="box-sizing: border-box;">当存在多个数据副本时,elasticsearch可以使用一组称为自适应副本选择的标准,根据包含分片的每个副本的节点的响应时间,服务时间和队列大小来选择数据的最佳副本。这可以提高查询吞吐量并减少搜索量大的应用程序的延迟。</span></p> <h3 style="box-sizing: border-box;font-weight: bold;font-size: 18px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.75em;margin-top: 1.5em !important;margin-bottom: 1.5em !important;padding-top: 0.5em !important;padding-bottom: 0.5em !important;color: rgb(0, 150, 136) !important;"><span style="color: rgb(255, 76, 65);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;"><strong><span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;color: rgb(255, 76, 65);box-sizing: border-box;letter-spacing: 1px;font-size: 18px;">第三部分:通用的一些建议</span></strong></span></h3> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">1、不要 返回大的结果集<br style="box-sizing: border-box;">es 设计来作为搜索引擎,它非常擅长返回匹配 query 的 top n 文档。但,如“返回满足某个query的 所有文档”等数据库领域的工作,并不是 es 最擅长的领域。如果你确实需要返回所有文档,你可以使用 Scroll API</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">2、避免 大的 doc。即,单个 doc 小了 会更好<br style="box-sizing: border-box;">given that(考虑到) http.max_context_length默认==100MB,es拒绝索引操作100MB的文档。当然你可以提高这个限制,但,Lucene本身也有限制的,其为2GB<br style="box-sizing: border-box;">即使不考虑上面的限制,大的doc 会给 network/memory/disk带来更大的压力;<br style="box-sizing: border-box;">a.任何搜索请求,都需要获取 _id 字段,由于filesystem cache工作方式。即使它不请求 _source字段,获取大doc _id 字段消耗更大<br style="box-sizing: border-box;">b.索引大doc时消耗内存会是 doc本身大小 的好几倍<br style="box-sizing: border-box;">c.大doc的 proximity search, highlighting 也更加昂贵。它们的消耗直接取决于doc本身的大小</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">3、避免 稀疏<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;a.不相关数据 不要 放入同一个索引<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;b.一般化文档结构(Normalize document structures)<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;c.避免类型<br style="box-sizing: border-box;">&nbsp;&nbsp;&nbsp;&nbsp;d.在 稀疏 字段上,禁用 norms &amp; doc_values 属性</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">稀疏为什么不好?<br style="box-sizing: border-box;">Lucene 背后的数据结构 更擅长处理 紧凑的数据<br style="box-sizing: border-box;">text类型的字段,norms默认开启;numerics, date, ip, keyword,doc_values默认开启<br style="box-sizing: border-box;">Lucene内部使用 integer的doc_id来标识文档 和 内部API交互。<br style="box-sizing: border-box;">举个例子:<br style="box-sizing: border-box;">使用match查询时生成doc_id的迭代器,这些doc_id被用于获取它们的norm,以便计算score。当前的实现是每个doc中保留一个byte用于存储norm值。获取norm值其实就是读取doc_id位置处的一个字节<br style="box-sizing: border-box;">这非常高效,Lucene通过此值可以快速访问任何一个doc的norm值;但,给定一个doc,即使某个field没有值,仍需要为此doc的此field保留一个字节<br style="box-sizing: border-box;">doc_values也有同样的问题。2.0之前的fielddata被现在的doc_values所替代了。<br style="box-sizing: border-box;">稀疏性 最明显的影响是 对存储的需求(任何doc的每个field,都需要一个byte);但是呢,稀疏性 对 索引速度和查询速度 也是有影响的,因为:即使doc并没有某些字段值,但,索引时,依然需要写这些字段,查询时,需要skip这些字段的值<br style="box-sizing: border-box;">某个索引中拥有少量稀疏字段,这完全没有问题。但,这不应该成为常态<br style="box-sizing: border-box;">稀疏性影响最大的是 norms&amp;doc_values ,但,倒排索引(用于索引 text以及keyword字段),二维点(用于索引geo_point字段)也会受到较小的影响</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">如何避免稀疏呢?<br style="box-sizing: border-box;">1、不相关数据 不要 放入同一个索引<br style="box-sizing: border-box;">给个tip:索引小(即:doc的个数较少),则,primary shard也要少<br style="box-sizing: border-box;">2、一般化文档结构(Normalize document structures)<br style="box-sizing: border-box;">3、避免类型(Avoid mapping type)<br style="box-sizing: border-box;">同一个index,最好就一个mapping type<br style="box-sizing: border-box;">在同一个index下面,使用不同的mapping type来存储数据,听起来不错,但,其实不好。given that(考虑到)每一个mapping type会把数据存入 同一个index,因此,多个不同mapping type,各个的field又互不相同,这同样带来了稀疏性 问题<br style="box-sizing: border-box;">4、在 稀疏 字段上,禁用 norms &amp; doc_values 属性<br style="box-sizing: border-box;">a.norms用于计算score,无需score,则可以禁用它(所有filtering字段,都可以禁用norms)<br style="box-sizing: border-box;">b.doc_vlaues用于sort&amp;aggregations,无需这两个,则可以禁用它<br style="box-sizing: border-box;">但是,不要轻率的做出决定,因为 norms&amp;doc_values无法修改。只能reindex</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">秘诀1:混合 精确查询和提取词干(mixing exact search with stemming)<br style="box-sizing: border-box;">对于搜索应用,提取词干(stemming)都是必须的。例如:查询 skiing时,ski和skis都是期望的结果<br style="box-sizing: border-box;">但,如果用户就是要查询skiing呢?<br style="box-sizing: border-box;">解决方法是:使用multi-field。同一份内容,以两种不同的方式来索引存储<br style="box-sizing: border-box;">query.simple_query_string.quote_field_suffix,竟然是 查询完全匹配的</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">秘诀2:获取一致性的打分<br style="box-sizing: border-box;">score不能重现<br style="box-sizing: border-box;">同一个请求,连续运行2次,但,两次返回的文档顺序不一致。这是相当坏的用户体验</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">如果存在 replica,则就可能发生这种事,这是因为:<br style="box-sizing: border-box;">search时,replication group中的shard是按round-robin方式来选择的,因此两次运行同样的请求,请求如果打到 replication group中的不同shard,则两次得分就可能不一致</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">那问题来了,“你不是整天说 primary和replica是in-sync的,是完全一致的”嘛,为啥打到“in-sync的,完全一致的shard”却算出不同的得分?</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">原因就是标注为“已删除”的文档。如你所知,doc更新或删除时,旧doc并不删除,而是标注为“已删除”,只有等到 旧doc所在的segment被merge时,“已删除”的doc才会从磁盘删除掉</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">索引统计(index statistic)是打分时非常重要的一部分,但,由于 deleted doc 的存在,在同一个shard的不同copy(即:各个replica)上 计算出的 索引统计 并不一致</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">个人理解:<br style="box-sizing: border-box;">a. 所谓 索引统计 应该就是df,即 doc_freq<br style="box-sizing: border-box;">b. 索引统计 是基于shard来计算的</span></p> <ol style="list-style-type: none;margin-left: 5px;margin-right: 5px;" class=" list-paddingleft-2"> <li><p style="line-height: 1.75em;"><span style="box-sizing: border-box;letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">搜索时,“已删除”的doc 当然是 永远不会 出现在 结果集中的</span></p></li> <li><p style="line-height: 1.75em;"><span style="box-sizing: border-box;letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">索引统计时,for practical reasons,“已删除”doc 依然是统计在内的</span></p></li> </ol> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">假设,shard A0 刚刚完成了一次较大的segment merge,然后移除了很多“已删除”doc,shard A1 尚未执行 segment merge,因此 A1 依然存在那些“已删除”doc</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">于是:两次请求打到 A0 和 A1 时,两者的 索引统计 是显著不同的</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">如何规避 score不能重现 的问题?使用 preference 查询参数<br style="box-sizing: border-box;">发出搜索请求时候,用 标识字符串 来标识用户,将 标识字符串 作为查询请求的preference参数。这确保多次执行同一个请求时候,给定用户的请求总是达到同一个shard,因此得分会更为一致(当然,即使同一个shard,两次请求 跨了 segment merge,则依然会得分不一致)<br style="box-sizing: border-box;">这个方式还有另外一个优点,当两个doc得分一致时,则默认按着doc的 内部Lucene doc id 来排序(注意:这并不是es中的 _id 或 _uid)。但是呢,shard的不同copy间,同一个doc的 内部Lucene doc id 可能并不相同。因此,如果总是达到同一个shard,则,具有相同得分的两个doc,其顺序是一致的</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">score 错了(Relevancy looks wrong)<br style="box-sizing: border-box;">如果你发现<span style="font-size: 16px;letter-spacing: 1px;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: justify;">具有相同内容的文档,其得分不同,完全匹配 的查询 并没有排在第一位,这可能都是由 sharding 引起的,默认情况下,搜索文档时,每个shard自己计算出自己的得分。索引统计 又是打分时一个非常重要的因素。</span></span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">如果每个shard的 索引统计相似,则 搜索工作的很好<br style="box-sizing: border-box;">文档是平分到每个primary shard的,因此 索引统计 会非常相似,打分也会按着预期工作。但,万事都有个但是:<span style="font-size: 16px;letter-spacing: 1px;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: justify;">索引时使用了 routing(文档不能平分到每个primary shard 啦),查询多个索引,索引中文档的个数 非常少,这会导致:参与查询的各个shard,各自的 索引统计 并不相似(而,索引统计对 最终的得分 又影响巨大),于是 打分出错了(relevancy looks wrong)</span></span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">那,如何绕过 score错了(Relevancy looks wrong)?</span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">如果数据集较小,则,只使用一个primary shard(es默认是5个),这样两次查询 索引统计 不会变化,因而得分也就一致啦<br style="box-sizing: border-box;">另一种方式是,将search_type设置为:dfs_query_then_fetech(默认是query_then_fetch)<br style="box-sizing: border-box;">dfs_query_then_fetch的作用是<span style="font-size: 16px;letter-spacing: 1px;color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: justify;">向 所有相关shard 发出请求,要求 所有相关shard 返回针对当前查询的 索引统计,然后,coordinating node 将 merge这些 索引统计,从而得到 merged statistics&nbsp;coordinating node 要求 所有相关shard 执行 query phase,于是 发出请求,这时,也带上 merged statistics。这样,执行query的shard 将使用 全局的索引统计。大部分情况下,要求 所有相关shard 返回针对当前查询的 索引统计,这是非常cheap的。但,如果查询中 包含 非常大量的 字段/term查询,或者有 fuzzy查询,此时,获取 索引统计 可能并不cheap,因为 为了得到 索引统计 可能 term dictionary 中 所有的term都需要被查询一遍</span></span></p> <p style="box-sizing: border-box;color: rgb(0, 0, 0);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;margin: 1.5em 5px !important;"><span style="letter-spacing: 1px;font-size: 16px;font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">英文文章地址:<span style="font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;font-size: 16px;letter-spacing: 1px;color: rgb(0, 128, 255);">https://www.elastic.co/guide/en/elasticsearch/reference/current/how-to.html</span></span></p> <section class=""> <section style="width: 50px;height: 4px;background-color: rgb(249, 110, 87);box-sizing: border-box;"> <br> </section> <section style="width: 50px;height: 4px;background-color: rgb(249, 110, 87);box-sizing: border-box;"> <br> <br> </section> </section> <section class="" style="margin-top: -4px;padding: 10px;white-space: normal;background-color: rgb(239, 239, 239);box-sizing: border-box;"> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us" style="box-sizing: border-box;"> <section class="" style="box-sizing: border-box;"> <section class="" style="box-sizing: border-box;"> <p style="text-align: justify;line-height: 2em;"><span style="letter-spacing: 1px;font-size: 14px;">在公众号后台回复</span><span style="letter-spacing: 1px;font-size: 14px;color: rgb(255, 76, 65);">"<strong>微信</strong>"</span><span style="letter-spacing: 1px;font-size: 14px;">关键字,加群主微信免费加入高大上的</span><strong><span style="letter-spacing: 1px;font-size: 14px;color: rgb(255, 76, 65);">架构之路</span></strong><span style="letter-spacing: 1px;font-size: 14px;">微信群,设为</span><strong><span style="letter-spacing: 1px;font-size: 14px;color: rgb(255, 76, 65);">星标</span></strong><span style="letter-spacing: 1px;font-size: 14px;">,备注架构之路,(</span><strong><span style="letter-spacing: 1px;font-size: 14px;color: rgb(255, 104, 39);">公众号主免进!</span></strong><span style="letter-spacing: 1px;font-size: 14px;">)</span></p> </section> </section> </section> </section> <p style="white-space: normal;text-align: center;"><br></p> <section> <section class="Powered-by-XIUMI V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section class=""> <section class="" style="display: inline-block;width: 100%;vertical-align: top;background-color: rgb(239, 239, 247);padding: 10px;box-sizing: border-box;"> <section class="Powered-by-XIUMI V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section class="" style="margin: 8px 0% -2px;font-size: 13px;box-sizing: border-box;"> <section class="" style="display: inline-block;vertical-align: top;box-sizing: border-box;"> <section class="" style="background-color: rgba(255, 255, 255, 0);color: rgb(55, 55, 93);font-size: 16px;padding-left: 5px;padding-right: 5px;margin-bottom: 4px;box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 2px;color: rgb(255, 76, 65);"><strong>猜你喜欢</strong></span></p> </section> <section style="height: 2px;width: 100%;background-color: rgb(0, 0, 0);box-sizing: border-box;"> <br> </section> </section> </section> </section> <section style="border-top: 1px dashed rgb(142, 142, 150);box-sizing: border-box;" class=""> <br> </section> <p style="line-height: 1.75em;"><span style="text-decoration: underline;font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjUwMg==&amp;mid=2247485826&amp;idx=1&amp;sn=25beda89c09d1ac93b649f9ca8f14730&amp;chksm=a6da83eb91ad0afd11ca3ebc5356950bdc8f27cf7166775971dffbe599a61b58182e837191c4&amp;scene=21#wechat_redirect" style="text-decoration: underline;font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);" data-linktype="2">Java&nbsp;并发框架全览,这个牛逼!</a></span></p> <p style="line-height: 1.75em;"><span style="text-decoration: underline;font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjUwMg==&amp;mid=2247485824&amp;idx=1&amp;sn=ef6d6015e83eb113b8a7af3223b63b5b&amp;chksm=a6da83e991ad0affa8cc0f9bc3ebfe0b5f221196dad10af6783b285031de8a76472a0be26a16&amp;scene=21#wechat_redirect" style="text-decoration: underline;font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);" data-linktype="2">分库分表就能无限扩容吗,解释得太好了!</a></span></p> <p style="line-height: 1.75em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjUwMg==&amp;mid=2247485798&amp;idx=1&amp;sn=3dd3cb125410a39648df5e15106213ac&amp;chksm=a6da830f91ad0a197d9f0a022d10d153a2077e78bfbdb194876af2b67a24576bfbd41271b4e0&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2"></a><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjUwMg==&amp;mid=2247485798&amp;idx=1&amp;sn=3dd3cb125410a39648df5e15106213ac&amp;chksm=a6da830f91ad0a197d9f0a022d10d153a2077e78bfbdb194876af2b67a24576bfbd41271b4e0&amp;scene=21#wechat_redirect" style="text-decoration: underline;font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);" data-linktype="2"><span style="font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);">一份超详细的Java问题排查工具单!</span></a></p> <p style="line-height: 1.75em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjUwMg==&amp;mid=2247485794&amp;idx=1&amp;sn=ea0af74803027091440d94e99c5d4ef6&amp;chksm=a6da830b91ad0a1dbc49f58243ea03843246545d14ee38295dfc71776811ee5f567e4a18fffc&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2"></a><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjUwMg==&amp;mid=2247485794&amp;idx=1&amp;sn=ea0af74803027091440d94e99c5d4ef6&amp;chksm=a6da830b91ad0a1dbc49f58243ea03843246545d14ee38295dfc71776811ee5f567e4a18fffc&amp;scene=21#wechat_redirect" style="text-decoration: underline;font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);" data-linktype="2"><span style="font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);">Hystrix&nbsp;到底是个什么玩意儿?</span></a></p> <p style="line-height: 1.75em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjUwMg==&amp;mid=2247485709&amp;idx=1&amp;sn=1fba3212a3f9f317e885d0cd0447f209&amp;chksm=a6da836491ad0a722796dafb67167a248667768bf22d11f42d04278f4ce9382a524638da9ff3&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2"></a><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjUwMg==&amp;mid=2247485709&amp;idx=1&amp;sn=1fba3212a3f9f317e885d0cd0447f209&amp;chksm=a6da836491ad0a722796dafb67167a248667768bf22d11f42d04278f4ce9382a524638da9ff3&amp;scene=21#wechat_redirect" style="text-decoration: underline;font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);" data-linktype="2"><span style="font-size: 14px;letter-spacing: 1px;color: rgb(121, 123, 170);">大牛是怎么思考设计SQL优化方案的?</span></a></p> </section> </section> </section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <br> </section> </section> </section> </section> <p style="margin-bottom: 5px;"><img class="" data-ratio="0.6772334293948127" data-s="300,640" src="/upload/4c819e088e4f4a8e5f522e068c91cebf.png" data-type="png" data-w="694" style=""></p> <section data-role="outer" label="Powered by 135editor.com" style="line-height: 25.6px;white-space: normal;"> <section class="" data-tools="135编辑器" data-id="89436"> <section> <section> <section class="_135editor" data-tools="135编辑器" data-id="88692" style="border-width: 0px;border-style: none;border-color: currentcolor;box-sizing: border-box !important;overflow-wrap: break-word !important;outline: currentcolor none 0px !important;"> <section> <section style="margin-top: -40px;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;outline: currentcolor none 0px !important;"> <br> </section> <section style="background-color: rgb(255, 255, 255);box-sizing: border-box;"> <section class="Powered-by-XIUMI V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section class="" style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;text-align: right;"> <span style="color: rgb(255, 104, 39);font-size: 14px;">老板,要你好看哦!</span> </section> </section> </section> </section> </section> </section> </section> </section> </section>

K8S 从懵圈到熟练:读懂此文,集群节点不下线!

作者:微信小助手

<p style="white-space: normal;text-align: center;"><img class="rich_pages" data-backh="371" data-backw="556" data-before-oversubscription-url="/upload/b382bb1897041ba873b94e44d52f0d45.jpg" data-copyright="0" data-ratio="0.6669921875" data-s="300,640" src="/upload/b382bb1897041ba873b94e44d52f0d45.jpg" data-type="jpeg" data-w="1024" style="color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;white-space: normal;background-color: rgb(235, 235, 235);text-align: center;width: 100%;height: auto;"></p> <section class="" powered-by="xiumi.us" style="white-space: normal;max-width: 100%;letter-spacing: 0.544px;line-height: 27.2px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;"> <section class="" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="margin-right: 0em;margin-left: 0em;padding: 0.5em 1em;max-width: 100%;border-style: none;background-color: rgb(235, 235, 235);box-sizing: border-box !important;word-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;line-height: 1.75em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;color: rgb(136, 136, 136);letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;">阿里妹导读:</span><span style="max-width: 100%;font-size: 15px;color: rgb(136, 136, 136);letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;">排查完全陌生的问题、不熟悉的系统组件,对许多工程师来说是无与伦比的工作乐趣,当然也是一大挑战。</span><span style="max-width: 100%;font-size: 15px;color: rgb(136, 136, 136);letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;">今天,阿里巴巴售后技术专家声东跟大家分享一例 Kubernetes 集群上的问题。这个问题影响范围较广,或许某天你也会遇到。更重要的是,作者在</span><span style="max-width: 100%;font-size: 15px;color: rgb(136, 136, 136);letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;">问题排查过程中的</span><span style="max-width: 100%;font-size: 15px;color: rgb(136, 136, 136);letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;">思路和方法,也会让你有所启发。</span></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;box-sizing: border-box !important;word-wrap: break-word !important;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(255, 129, 36);">关于问题</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">I am Not Ready</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">阿里云有自己的 Kubernetes 容器集群产品。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">随着 Kubernetes 集群出货量剧增,线上用户零星地发现,集群会非常低概率地出现节点 NotReady 情况。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">据我们观察,这个问题差不多每个月,都会有一两个用户遇到。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">在节点 NotReady 之后,集群 Master 没有办法对这个节点做任何控制,比如下发新的 Pod,再比如抓取节点上正在运行 Pod 的实时信息。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: center;"><img class="" data-ratio="0.1958128078817734" src="/upload/8a190a92fc71d3264ecdb2e6ee5cd8c3.png" data-type="png" data-w="812" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;text-align: left;"><br></span></strong></p> <p style="white-space: normal;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;text-align: left;">需要知道的Kubernetes知识</span></strong></p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">这里我稍微补充一点 Kubernetes 集群的基本知识。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">Kubernetes 集群的“硬件基础”,是以单机形态存在的集群节点。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">这些节点可以是物理机,也可以是虚拟机。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">集群节点分为 Master 节点和 Worker 节点。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">Master 节点主要用来承载集群管控组件,比如调度器和控制器。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">而 Worker 节点主要用来跑业务。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">Kubelet 是跑在各个节点上的代理,它负责与管控组件沟通,并按照管控组件的指示,直接管理 Worker节点。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.3153526970954357" src="/upload/1633431e3c0030077c5ff5fd1000734c.png" data-type="png" data-w="1446" height="227" width="718" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">当集群节点进入 NotReady 状态的时候,我们需要做的第一件事情,是检查运行在节点上的 kubelet 是否正常。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">在这个问题出现的时候,使用 systemctl 命令查看的kubelet 状态(kubelet 是 systemd 管理的一个 daemon )发现它是正常运行的。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">当我们用 journalctl 查看 kubelet 日志的时候,发现以下错误。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: center;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);"><img class="" data-ratio="0.1622340425531915" src="/upload/6555e3a66b0ab1af361a5ac346480abb.jpg" data-type="jpeg" data-w="1128"></span></p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;text-align: left;">什么是PLEG?</span></strong></p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">这个报错清楚地告诉我们,容器 runtime 是不工作的,且 PLEG 是不健康的。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">这里容器 runtime 指的就是 docker daemon 。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">Kubelet 通过操作 docker daemon 来控制容器的生命周期。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">而这里的 PLEG,指的是 pod lifecycle event generator。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">PLEG 是 kubelet 用来检查 runtime 的健康检查机制。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">这件事情本来可以由 kubelet 使用 polling 的方式来做。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">但是 polling 有其高成本的缺陷,所以 PLEG 应用而生。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">PLEG 尝试以一种“中断”的形式,来实现对容器 runtime 的健康检查,虽然实际上,它同时用了 polling 和”中断”这样折中的方案。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.561141304347826" src="/upload/9138d4f38c401bd314336b396b7bbd99.png" data-type="png" data-w="736" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">基本上,根据上边的报错,我们可以确认容器 runtime 出了问题。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">在有问题的节点上,通过 docker 命令尝试运行新的容器,命令会没有响应,这说明上边的报错是准确的。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(255, 129, 36);">Docker Stack</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">Docker Daemon调用栈分析</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">Docker 作为阿里云 Kubernetes 集群使用的容器 runtime ,在1.11之后,被拆分成了多个组件以适应 OCI 标准。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">拆分之后,其包括 docker daemon,containerd,containerd-shim 以及 runC。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">组件 containerd 负责集群节点上容器的生命周期管理,并向上为 docker daemon 提供 gRPC 接口。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.5704989154013015" src="/upload/3400cf63bbb02670dae060918df8ece2.png" data-type="png" data-w="1383" height="373" width="653" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">在这个问题中,既然 PLEG 认为容器 runtime 出了问题,我们需要从 docker daemon 进程看起。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">我们可以使用 kill -USR1 &lt;pid&gt; 命令发送 USR1 信号给docker daemon,而 docker daemon 收到信号之后,会把所有线程调用栈输出到 /var/run/docker 文件夹里。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">Docker daemon 进程的调用栈是比较容易分析的。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">稍加留意,我们会发现大多数的调用栈都长成下图中的样子。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">通过观察栈上每个函数的名字,以及函数所在的文件(模块)名称,我们可以了解到,这个调用栈的下半部分,是进程接到 http 请求,做请求路由的过程;</span><span style="font-size: 15px;color: rgb(62, 62, 62);">而上半部分则是具体的处理函数。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">最终处理函数进入等待状态,等待一个mutex实例。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: center;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);"><img class="" data-ratio="0.5206117021276596" src="/upload/4e09b0a921d5bdbb0c4856cdd14155ed.png" data-type="png" data-w="1504"></span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">到这里,我们需要稍微看一下 ContainerInspectCurrent 这个函数的实现。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">从实现可以看到,这个函数的第一个参数,就是这个线程正在操作的容器名指针。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">使用这个指针搜索整个调用栈文件,我们会找出所有等在这个容器上的线程。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">同时,我们可以看到下边这个线程。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.5325797872340425" src="/upload/5a2a5e6707d873d686fbeb6a04443421.png" data-type="png" data-w="1504" height="675" width="1267" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">这个线程调用栈上的函数 ContainerExecStart 也是在处理相同容器。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">但不同的是,ContainerExecStart 并没有在等这个容器,而是已经拿到了这个容器的操作权(mutex),并把执行逻辑转向了 containerd 调用。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">关于这一点,我们也可以使用代码来验证。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">前边我提到过,containerd 通过 gRPC 向上对 docker daemon 提供接口。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">此调用栈上半部分内容,正是 docker daemon 在通过 gRPC 请求来呼叫containerd。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">Containerd调用栈分析</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">与 docker daemon 类似,我们可以通过 kill -SIGUSR1 &lt;pid&gt; 命令来输出containerd 的调用栈。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">不同的是,这次调用栈会直接输出到 messages 日志。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">Containerd 作为一个 gRPC 的服务器,会在接到 docker daemon 的远程调用之后,新建一个线程去处理这次请求。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">关于 gRPC 的细节,我们这里其实不用太多关注。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">在这次请求的客户端调用栈上,可以看到这次调用的核心函数在 Start 一个Process 。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">我们在 containerd 的调用栈里搜索 Start,Process 以及 process.go 等字段,很容易发现下边这个线程。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.5292942743009321" src="/upload/12d41a7c2d1c5174c3f219967de069a4.png" data-type="png" data-w="1502" height="638" width="1205" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">这个线程的核心任务,就是依靠 runC 去创建容器进程。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">而在容器启动之后,runC 进程会退出。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">所以下一步,我们自然而然会想到,runC 是不是有顺利完成自己的任务。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">查看进程列表,我们会发现,系统中有个别 runC 进程还在执行,这不是预期的行为。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">容器的启动,跟进程的启动,耗时应该是差不多数量级的,系统里有正在运行的 runC 进程,则说明 runC 不能正常启动容器。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(255, 129, 36);">什么是D-Bus?</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">RunC请求D-Bus</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">容器 runtime 的 runC 命令,是 libcontainer 的一个简单的封装。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">这个工具可以用来管理单个容器,比如容器创建和容器删除。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">在上节的最后,我们发现 runC 不能完成创建容器的任务。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">我们可以把对应的进程杀掉,然后在命令行用同样的命令启动容器,同时用 strace 追踪整个过程。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.33489304812834225" src="/upload/e33136aa6d456c9067ae8daa2312aff6.png" data-type="png" data-w="1496" height="389" width="1162" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">分析发现,runC 停在了向带有 org.free 字段的 dbus socket 写数据的地方。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">那什么是 dbus 呢?</span><span style="font-size: 15px;color: rgb(62, 62, 62);">在 Linux 上,dbus 是一种进程间进行消息通信的机制。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">原因并不在 D-Bus</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.4411177644710579" src="/upload/fbc7bdd22af85830b29f795b7ad79c56.png" data-type="png" data-w="1503" height="291" width="660" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">我们可以使用 busctl 命令列出系统现有的所有 bus 。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">如下图,在问题发生的时候,我看到问题节点 bus name 编号非常大。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">所以我倾向于认为,dbus 某些相关的数据结构,比如 name,耗尽了引起了这个问题。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.4538087520259319" src="/upload/1a20b015a24d332dbe0fe52cdf386da9.png" data-type="png" data-w="1234" height="477" width="1051" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">Dbus 机制的实现,依赖于一个组件叫做 dbus daemon。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">如果真的是 dbus 相关数据结构耗尽,那么重启这个 daemon,应该可以解决这个问题。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">但不幸的是,问题并没有这么直接。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">重启 dbus daemon 之后,问题依然存在。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">在上边 strace 追踪 runC 的截图中,runC 停在向带有 org.free 字段的 bus 写数据的地方。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">在 busctl 输出的 bus 列表里,显然带有这个字段的 bus,都在被 systemd使用。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">这时,我们用 systemctl daemon-reexec 来重启 systemd,问题消失了。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">所以基本上我们可以判断一个方向,问题可能跟 systemd 有关。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(255, 129, 36);">Systemd是硬骨头</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">Systemd 是相当复杂的一个组件,尤其对没有做过相关开发工作的同学来说,比如我自己。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">基本上,排查 systemd 的问题,我用到了四个方法,(调试级别)日志,core dump,代码分析,以及 live debugging。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">其中第一个,第三个和第四个结合起来使用,让我在经过几天的鏖战之后,找到了问题的原因。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">但是这里我们先从“没用”的 core dump 说起。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">“没用的”Core Dump</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">因为重启 systemd 解决了问题,而这个问题本身,是 runC 在使用 dbus 和systemd 通信的时候没有了响应,所以我们需要验证的第一件事情,就是 systemd不是有关键线程被锁住了。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">查看 core dump 里所有线程,只有以下一个线程,此线程并没有被锁住,它在等待 dbus 事件,以便做出响应。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: center;"><img class="" data-ratio="0.13859111791730475" src="/upload/51d2e9f6e5fd54dedd4b47a9acc00d2a.png" data-type="png" data-w="1306" height="152" width="1097" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;text-align: left;"><br></span></strong></p> <p style="white-space: normal;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;text-align: left;">零散的信息</span></strong></p> <p style="white-space: normal;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">因为无计可施,所以只能做各种测试、尝试。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">使用 busctl tree 命令,可以输出所有bus 上对外暴露的接口。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">从输出结果看来,org.freedesktop.systemd1 这个 bus 是不能响应接口查询请求的。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.48759439050701187" src="/upload/385bd4037e56c30735d52f177f50608f.png" data-type="png" data-w="927" height="380" width="779" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">使用下边的命令,观察 org.freedesktop.systemd1 上接受到的所以请求,可以看到,在正常系统里,有大量 Unit 创建删除的消息,但是有问题的系统里,这个 bus 上完全没有任何消息。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">gdbus monitor --system --dest org.freedesktop.systemd1 --object-path /org/freedesktop/systemd1</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.293218085106383" src="/upload/bf439a9ed9120b586d50f59bcd702b66.png" data-type="png" data-w="1504" height="355" width="1211" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">分析问题发生前后的系统日志,runC在重复的跑一个libcontainer_%d_systemd_test_default.slice 测试,这个测试非常频繁,但是当问题发生的时候,这个测试就停止了。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">所以直觉告诉我,这个问题,可能和这个测试有很大的关系。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.375590020229265" src="/upload/aa96970e194c2062f6b95c08cb4a3c7a.jpg" data-type="jpeg" data-w="1483" height="406" width="1081" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">另外,我使用 systemd-analyze 命令,打开了 systemd 的调试级别日志,发现 systemd 有 Operation not supported 的报错。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.42884739214423695" src="/upload/76e07d65ecc814c43d8f9f1c35d01018.jpg" data-type="jpeg" data-w="1553" height="488" width="1138" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">根据以上零散的知识,可以给出一个大概的结论:</span><span style="font-size: 15px;color: rgb(62, 62, 62);">org.freedesktop.systemd1 这个 bus 在经过大量 unit 创建删除之后,没有了响应。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">而这些频繁的 unit 创建删除测试,是 runC 某一个改动引入的。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">这个改动使得 UseSystemd 函数通过创建 unit 来测试 systemd 的功能。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">UseSystemd 在很多地方被调用,比如创建容器,或者查看容器性能等操作。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">代码分析</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">这个问题在线上所有 Kubernetes 集群中,发生的频率大概是一个月两例。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">问题一直在发生,且只能在问题发生之后,通过重启 systemd 来处理,这风险极大。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">我们分别给 systemd 和 runC 社区提交了 bug,但是一个很现实的问题是,他们并没有像阿里云这样的线上环境,他们重现这个问题的概率几乎是零,所以这个问题没有办法指望社区来解决。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">硬骨头还得我们自己啃。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">在上一节最后,我们看到了,问题出现的时候,systemd 会输出一些 Operation not supported 报错。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">这个报错看起来和问题本身风马牛不相及,但是直觉告诉我,这,或许是离问题最近的一个地方,所以我决定,先搞清楚这个报错因何而来。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">Systemd 代码量比较大,而报这个错误的地方非常多。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">通过大量的代码分析(这里略去一千字),我发现有几处比较可疑地方,有了这些可疑的地方,接下来需要做的事情,就是等待。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">在等了三周以后,终于有线上集群,再次重现了这个问题。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">Live Debugging</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">在征求用户同意之后,下载 systemd 调试符号,挂载 gdb 到 systemd 上,在可疑的函数下断点,continue 继续执行。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">经过多次验证,发现 systemd 最终踩到了sd_bus_message_seal 这个函数里的 EOPNOTSUPP 报错。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.6035834266517357" src="/upload/dad96a496f994016be9531de45706b6c.png" data-type="png" data-w="893" height="515" width="853" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">这个报错背后的道理是,systemd 使用了一个变量 cookie,来追踪自己处理的 dbus message 。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">每次在加封一个新的 message 的时候,systemd 会先给 cookie的值加一,然后再把这个值复制给这个新的 message。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">我们使用 gdb 打印出 dbus<span style="color: rgb(25, 31, 37);font-family: -apple-system, system-ui, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Segoe UI&quot;, system-ui, Roboto, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 14px;text-align: left;white-space: pre-wrap;background-color: rgb(255, 255, 255);">-&gt;</span>cookie 这个值,可以很清楚看到,这个值超过了0xffffffff 。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">所以看起来,问题是 systemd 在加封过大量 message 之后,cookie 这个值32位溢出了,导致新的消息不能被加封,从而使得 systemd 对 runC 没有了响应。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;"><img class="" data-ratio="0.16549295774647887" src="/upload/ffa4c6064256632f81871a874a78ec0a.jpg" data-type="jpeg" data-w="1420" height="188" width="1136" style="margin-right: auto;margin-left: auto;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;display: block;"></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">另外,在一个正常的系统上,使用 gdb 把 bus<span style="color: rgb(25, 31, 37);font-family: -apple-system, system-ui, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Segoe UI&quot;, system-ui, Roboto, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 14px;text-align: left;white-space: pre-wrap;background-color: rgb(255, 255, 255);">-&gt;</span>cookie 这个值改到接近 0xffffffff,然后观察到,问题在 cookie 溢出的时候立刻出现,则证明了我们的结论。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="color: rgb(62, 62, 62);font-size: 15px;">怎么判断集群节点NotReady是这个问题导致的</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">首先我们需要在有问题的节点上安装 gdb 和 systemd debuginfo,然后用命令 gdb /usr/lib/systemd/systemd1 把 gdb attach 到 systemd ,在函数sd_bus_send 设置断点,然后继续执行。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">等 systemd 踩到断点之后,用 p /x bus<span style="color: rgb(25, 31, 37);font-family: -apple-system, system-ui, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Segoe UI&quot;, system-ui, Roboto, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;font-size: 14px;text-align: left;white-space: pre-wrap;background-color: rgb(255, 255, 255);">-&gt;</span>cookie 查看对应的cookie值,如果此值超过了 0xffffffff,那么 cookie 就溢出了,则必然导致节点 NotReady 的问题。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">确认完之后,可以使用 quit 来 detach 调试器。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(255, 129, 36);">问题修复</span></strong></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">这个问题的修复,并没有那么直截了当。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">原因之一,是 systemd 使用了同一个 cookie 变量,来兼容 dbus1 和 dbus2 。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">对于 dbus1 来说, cookie 是32位的,这个值在经过 systemd 三五个月频繁创建删除 unit 之后,是肯定会溢出的;</span><span style="font-size: 15px;color: rgb(62, 62, 62);">而 dbus2 的 cookie 是64位的,可能到了时间的尽头,它也不会溢出。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">另外一个原因是,我们并不能简单的让 cookie 折返,来解决溢出问题。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">因为这有可能导致 systemd 使用同一个 cookie 来加封不同的消息,这样的结果将是灾难性的。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">最终的修复方法是,使用32位 cookie 来同样处理 dbus1 和 dbus2 两种情形。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">同时在 cookie 达到 0xfffffff 的之后,下一个 cookie 则变成 0x80000000,即用最高位来标记 cookie 已经处于溢出状态。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">检查到 cookie 处于这种状态时,我们需要检查是否下一个 cookie 正在被其他 message 使用,来避免 cookie 冲突。</span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="color: rgb(255, 129, 36);"><strong><span style="font-size: 15px;">后记</span></strong></span></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><br></p> <p style="white-space: normal;text-align: left;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">这个问题根本原因肯定在 systemd,但是 runC 的函数 UseSystemd 使用不那么美丽的方法,去测试 systemd 的功能,而这个函数在整个容器生命周期管理过程中,被频繁的调用,让这个低概率问题的发生成为了可能。</span><span style="font-size: 15px;color: rgb(62, 62, 62);">systemd 的修复已经被红帽接受,预期不久的将来,我们可以通过升级 systemd,从根本上解决这个问题。</span></p> <p><br></p> <p><br></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-copyright="0" data-ratio="0.04907481898632341" data-type="gif" data-w="1243" width="auto" src="/upload/a03decb346c62b59e8414d260ef00e27.gif" style="box-sizing: border-box !important;word-wrap: break-word !important;visibility: visible !important;width: auto !important;"></p> <p style="min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 14px;font-family: monospace;white-space: pre;text-align: center;line-height: 1.75em;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="color: rgb(136, 136, 136);font-size: 15px;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;">你可能还喜欢</strong></span></p> <p style="min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 14px;font-family: monospace;white-space: pre;text-align: center;line-height: 1.75em;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="color: rgb(136, 136, 136);font-size: 12px;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;">点击下方图片即可阅读</span></p> <p style="min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-size: 14px;font-family: monospace;white-space: pre;text-align: center;line-height: 1.75em;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;mid=2247490092&amp;idx=1&amp;sn=e8fa9b319e3ba36c3c8b0a3cce73dc90&amp;chksm=e9292723de5eae35462361046e687a605323c4519642b46bf82d2d9450a8dbdd851c2a853e54&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="1" style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><span class="js_jump_icon h5_image_link" data-positionback="static" style="line-height: 0;top: auto;left: auto;right: auto;bottom: auto;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="rich_pages " data-croporisrc="/upload/d37cc9ea2f1fbb0b359332c24cca175.jpg" data-cropx1="0" data-cropx2="1280" data-cropy1="82.87769784172662" data-cropy2="688.3453237410072" data-ratio="0.4734375" data-s="300,640" data-type="jpeg" data-w="1280" src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLia0vyfftXZfEaGQTzaqklW4bF2DEicbqiaev9nI9UGBcmmyRjwnMkxqJ1vfrbdG2SvmO4JtkpxEApw/640?wx_fmt=jpeg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 556px !important;visibility: visible !important;"></span></a></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;mid=2247490092&amp;idx=1&amp;sn=e8fa9b319e3ba36c3c8b0a3cce73dc90&amp;chksm=e9292723de5eae35462361046e687a605323c4519642b46bf82d2d9450a8dbdd851c2a853e54&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" style="font-size: 14px;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;">贾扬清:我对人工智能方向的一点浅见</span></a><br style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;mid=2247490104&amp;idx=1&amp;sn=c4d92b922388e2dab74574951ba8ad3f&amp;chksm=e9292737de5eae212e8016f492b6e160b2f08be9445b043e088899d024c81179def428ff5840&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="1" style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><span class="js_jump_icon h5_image_link" data-positionback="static" style="line-height: 0;top: auto;left: auto;right: auto;bottom: auto;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="rich_pages " data-croporisrc="/upload/f266c5b5be1ffc885836842ba6d26692.jpg" data-cropx1="0" data-cropx2="1080" data-cropy1="248.63309352517985" data-cropy2="687.6258992805755" data-ratio="0.4064814814814815" data-s="300,640" data-type="jpeg" data-w="1080" src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLia0vyfftXZfEaGQTzaqklWicMgdRF4VoIgQFU13xicyDTXh0CLjZn2l0nH0a00HAtiaLBxjAb5KScuQ/640?wx_fmt=jpeg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 556px !important;visibility: visible !important;"></span></a></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;mid=2247490104&amp;idx=1&amp;sn=c4d92b922388e2dab74574951ba8ad3f&amp;chksm=e9292737de5eae212e8016f492b6e160b2f08be9445b043e088899d024c81179def428ff5840&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" style="font-size: 14px;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;">如何搞定技术面试?阿里大牛为你选了8本必备好书</span></a><br style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;mid=2247490113&amp;idx=1&amp;sn=c25c6f392d4a6e780b18b61a6c858af1&amp;chksm=e929274ede5eae5898fcf4d45a803b4407a30557b6013c0a512650433181cd27ca99de296c74&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="1" style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><span class="js_jump_icon h5_image_link" data-positionback="static" style="line-height: 0;top: auto;left: auto;right: auto;bottom: auto;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="rich_pages " data-croporisrc="/upload/1db43c8a0397c36cc3bb6ddeaee3a016.jpg" data-cropx1="0" data-cropx2="1280" data-cropy1="168.0575539568345" data-cropy2="785.0359712230215" data-ratio="0.48203125" data-s="300,640" data-type="jpeg" data-w="1280" src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naJzyjoXqDKTCTpYYHOjXWXIQeZTAzbiatZeSTqxPjgiaCJbHA3Crwd0icmIicgltkjJ7FODkepDwHmIFA/640?wx_fmt=jpeg" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 556px !important;visibility: visible !important;"></span></a></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="font-size: 14px;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;mid=2247490113&amp;idx=1&amp;sn=c25c6f392d4a6e780b18b61a6c858af1&amp;chksm=e929274ede5eae5898fcf4d45a803b4407a30557b6013c0a512650433181cd27ca99de296c74&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2" style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;">在阿里做了五年技术主管,我有话想说</a></span></p> <p style="min-height: 1em;letter-spacing: 0.5440000295639038px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100% !important;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p style="min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-align: center;max-width: 100% !important;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="__bg_gif " data-copyright="0" data-ratio="1.0616740088105727" data-type="gif" data-w="454" width="253px" src="/upload/bdb52bd95cf43cae8f9220839965a1be.gif" style="box-sizing: border-box !important;word-wrap: break-word !important;width: 253px !important;visibility: visible !important;"></p>

每秒30W次的点赞业务,怎么优化?

作者:微信小助手

<p style="text-align: left;"><img class="rich_pages" data-ratio="1.5093457943925233" data-s="300,640" src="/upload/9a2f0094132853b52f2467b733628e6e.png" data-type="png" data-w="428" style="width: 239px;height: 361px;"></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">继续答星球水友提问,<strong>30WQPS的点赞计数业务,如何设计?</strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">可以看到,这个<strong>业务的特点</strong>是:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">吞吐量超高</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">能够接受一定数据不一致</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 82, 255);"><em><span style="font-size: 15px;letter-spacing: 1px;">画外音:</span></em><em><span style="font-size: 15px;letter-spacing: 1px;">计数有微小不准确,不是大问题。</span></em></span> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">先用最朴素的思想,<strong>只考虑点赞计数,可以怎么做?</strong></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">有几点是最容易想到的:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)肯定<strong>不能</strong>用</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">数据库抗</span> <span style="font-size: 15px;letter-spacing: 1px;">实时读写流量;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)redis天然支持固化,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">可以用高可用redis集群来做固化存储</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">也可以用MySQL来做固化存储</span> <span style="font-size: 15px;letter-spacing: 1px;">,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">redis做缓存</span> <span style="font-size: 15px;letter-spacing: 1px;">,读写操作都落缓存,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">异步线程定期刷DB</span> <span style="font-size: 15px;letter-spacing: 1px;">;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)架一层</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">计数服务</span> <span style="font-size: 15px;letter-spacing: 1px;">,将计数与业务逻辑解耦;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">此时<strong>MySQL核心数据结构</strong>是:</span> </section> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">t_count(msg_id, praise_count)</span></em></span><span style="font-size: 15px;letter-spacing: 1px;"></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">此时<strong>redis的KV设计</strong>也不难:</span> </section> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">key:</span></em><em><span style="letter-spacing: 1px;">msg_id</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">value:</span></em><em><span style="font-size: 12px;letter-spacing: 1px;">praise_count</span></em></span><span style="font-size: 15px;letter-spacing: 1px;"></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <p style="text-align: left;"><img class="rich_pages" data-ratio="0.42391304347826086" data-s="300,640" src="/upload/98ad612c9fbd3f0264ec4ce0c8a8cd0f.png" data-type="png" data-w="276" style=""></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">似乎很容易就搞定了:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)服务可以水平扩展;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)数据量增加时,数据库可以水平扩展;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)读写量增加时,缓存也可以水平扩展;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">计数系统的<strong>难点</strong>,还在于</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">业务扩展性</span> <span style="font-size: 15px;letter-spacing: 1px;">问题,以及</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">效率</span> <span style="font-size: 15px;letter-spacing: 1px;">问题。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">以微博为例:</span> </section> <p style="text-align: left;"><img class="rich_pages" data-ratio="0.6947723440134908" data-s="300,640" src="/upload/bcd4c8ba5e3da2f491e3cea3e19412e2.png" data-type="png" data-w="593" style="width: 338px;height: 235px;"></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)用户微博首页,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">有多条消息</span> <span style="letter-spacing: 1px;font-size: 12px;">list&lt;msg_id&gt;</span> <span style="font-size: 15px;letter-spacing: 1px;">,这是一种<strong>扩展</strong>;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)同一条消息msg_id,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">不止有点赞计数,还有阅读计数,转发计数,评论计数</span> <span style="font-size: 15px;letter-spacing: 1px;">,这也是一种<strong>扩展</strong>;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">假如用最朴素的方式实现,多条消息多个计数的获取伪代码如下:</span> </section> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">// (1)</span></em></span><span style="font-size: 12px;color: rgb(255, 76, 0);"><em><span style="font-size: 12px;letter-spacing: 1px;">获取首页所有消息</span></em></span><span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">msg_id</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">list&lt;msg_id&gt; = getHomePageMsg(uid);</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">// (2)对于首页的所有消息要</span></em></span><span style="font-size: 12px;color: rgb(255, 76, 0);"><em><span style="font-size: 12px;letter-spacing: 1px;">拉取多个计数</span></em></span><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;"></span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">for( msg_id in list&lt;msg_id&gt;){</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(3.1)获取</span></em></span><span style="font-size: 12px;color: rgb(255, 76, 0);"><em><span style="font-size: 12px;letter-spacing: 1px;">阅读计数</span></em></span><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;"></span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getReadCount(msg_id);&nbsp;</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(3.2)获取</span></em></span><span style="font-size: 12px;color: rgb(255, 76, 0);"><em><span style="font-size: 12px;letter-spacing: 1px;">转发计数</span></em></span><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;"></span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getForwordCount(msg_id);</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(3.3)获取</span></em></span><span style="font-size: 12px;color: rgb(255, 76, 0);"><em><span style="font-size: 12px;letter-spacing: 1px;">评论计数</span></em></span><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;"></span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getCommentCount(msg_id);</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(3.4)获取</span></em></span><span style="font-size: 12px;color: rgb(255, 76, 0);"><em><span style="font-size: 12px;letter-spacing: 1px;">赞计数</span></em></span><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;"></span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getPraiseCount(msg_id);</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">}</span></em></span><span style="font-size: 15px;letter-spacing: 1px;"></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">由于同一个msg_id多了几种业务计数,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">redis的key需要带上业务flag</span> <span style="font-size: 15px;letter-spacing: 1px;">,升级为:</span> </section> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">msg_id:read</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">msg_id:forword</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">msg_id:comment</span></em></span></p> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="font-size: 12px;letter-spacing: 1px;">msg_id:praise</span></em></span><span style="font-size: 15px;letter-spacing: 1px;"></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">用来区分共一个msg_id的四种不同业务计数,redis不能支持key的模糊操作,必须访问四次reids。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">假设首页有100条消息,<strong>这个方案</strong>总结为:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)for循环每一条消息,100条消息100次;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)每条消息4次RPC获取计数接口调用;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)每次调用服务要访问reids,拼装key获取count;</span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 82, 255);"><em><span style="font-size: 15px;letter-spacing: 1px;">画外音:这种方案的扩展性和效率是非常低的。</span></em></span> <em><span style="font-size: 15px;letter-spacing: 1px;"></span></em> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">那如何进行优化呢?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">首先看下<strong>数据库层面元数据扩展</strong>,常见的扩展方式是,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">增加列</span> <span style="font-size: 15px;letter-spacing: 1px;">,记录更多的业务计数。</span> </section> <p style="text-align: left;"><img class="rich_pages" data-ratio="0.3150406504065041" data-s="300,640" src="/upload/b3e22b807e1bdf50d0413bcb34ec2037.png" data-type="png" data-w="492" style=""></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">如上图所示,由一列点赞计数,扩充为四列阅读、转发、评论、点赞计数。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">增加列这种业务计数扩展方式的<strong>缺点</strong>是:</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">每次要扩充业务计数时,总是需要修改表结构</span> <span style="font-size: 15px;letter-spacing: 1px;">,增加列,很烦。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">有没有不需要变更表结构的扩展方式呢?</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">行扩展</span> <span style="font-size: 15px;letter-spacing: 1px;">是一种扩展性更好的方式。</span> </section> <p style="text-align: left;"><img class="rich_pages" data-ratio="0.6335616438356164" data-s="300,640" src="/upload/2adb893a830e410820f7d9b62fd3763e.png" data-type="png" data-w="292" style=""></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">表结构固化为:</span> </section> <p style="line-height: normal;"><span style="font-size: 12px;"><em><span style="letter-spacing: 1px;">t_count(msg_id, count_key, count_value)</span></em></span><span style="font-size: 15px;letter-spacing: 1px;"></span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">当要扩充业务计数时,增加一行就行,不需要修改表结构。</span> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(0, 82, 255);"><em><span style="font-size: 15px;letter-spacing: 1px;">画外音:</span></em><em><span style="font-size: 15px;letter-spacing: 1px;">很多配置业务,会使用这种方案,方便增加配置。</span></em></span> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">增加行这种业务计数扩展方式的<strong>缺点</strong>是:</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">表数据行数会增加</span> <span style="font-size: 15px;letter-spacing: 1px;">,但这不是主要矛盾,数据库水平扩展能很轻松解决数据量大的问题。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">接下来看下<strong>redis批量获取计数</strong>的优化方案。</span> </section> <p style="text-align: left;"><img class="rich_pages" data-ratio="0.6855670103092784" data-s="300,640" src="/upload/9f1309b28bbbad6a9707b6de679b106f.png" data-type="png" data-w="194" style=""></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">原始方案,通过拼装key来区分同一个msg_id的不同业务计数。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">可以升级为,同一个value来存储多个计数。<br></span> </section> <p style="text-align: left;"><img class="rich_pages" data-copyright="0" data-ratio="0.26804123711340205" data-s="300,640" src="/upload/91f88babd902efa615f2fb84aab6f3da.png" data-type="png" data-w="194" style=""></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">如上图所示,</span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">同一个msg_id的四个计数</span> <span style="font-size: 15px;letter-spacing: 1px;">,存储在一个value里,从而避免多次redis访问。<br></span> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(0, 82, 255);"><em>画外音:</em><em>通过value来扩展,是不是很巧妙?</em></span> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;letter-spacing: 1px;">总结</span></strong> <span style="font-size: 15px;letter-spacing: 1px;"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">计数业务,在数据量大,并发量大的时候,要考虑的一些技术点:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(1)用缓存抗读写;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(2)服务化,计数系统与业务系统解耦;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(3)水平切分扩展吞吐量、数据量、读写量;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(4)要考虑扩展性,数据库层面常见的优化有:列扩展,行扩展两种方式;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">(5)要考虑批量操作,缓存层面常见的优化有:一个value存储多个业务计数;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">&nbsp;</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;letter-spacing: 1px;">计数系统优化先聊到这里,希望大家有收获。</span> </section> <section style="text-align: center;color: rgb(51, 51, 51);clear: both;box-sizing: border-box;background-color: transparent;line-height: 1.75em;"> <img class="rich_pages " style="box-sizing: border-box;margin: 0px;max-width: 677px;padding: 0px;visibility: visible !important;overflow-wrap: break-word;width: 317px !important;height: auto !important;" data-ratio="0.596" data-w="750" data-s="300,640" data-type="png" src="/upload/d0d66cab6277fcb1b00294a045b8323b.png"> </section> <section style="background-color: rgb(255, 255, 255);box-sizing: border-box;clear: both;color: rgb(51, 51, 51);line-height: 1.75em;"> <span style="margin: 0px;padding: 0px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;letter-spacing: 1px;">欢迎大家继续提问,有问必答。<br style="box-sizing: border-box;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;word-wrap: break-word;"></span> </section> <p style="background-color: rgb(255, 255, 255);box-sizing: border-box;clear: both;color: rgb(51, 51, 51);"><br style="box-sizing: border-box;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;word-wrap: break-word;"></p> <section style="background-color: transparent;box-sizing: border-box;color: rgb(51, 51, 51);"></section> <section style="background-color: transparent;box-sizing: border-box;clear: both;color: rgb(51, 51, 51);line-height: 1.75em;"> <span style="letter-spacing: 1px;"><span style="margin: 0px;padding: 0px;letter-spacing: 1px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;"><strong style="box-sizing: border-box;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;word-wrap: break-word;">答球友问</strong><span style="font-size: 15px;margin: 0px;padding: 0px;text-align: justify;color: rgb(0, 0, 0);text-transform: none;text-indent: 0px;letter-spacing: 1px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;">:</span></span></span> <span style="margin: 0px;padding: 0px;text-align: justify;color: rgb(0, 0, 0);text-transform: none;text-indent: 0px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;letter-spacing: 1px;"><br>《<a style="box-sizing: border-box;color: rgb(87, 107, 149);margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;text-decoration: none;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);word-wrap: break-word;" href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&amp;mid=2651962667&amp;idx=1&amp;sn=7cb8c095550f9cd777da13bdbc02c8b8&amp;chksm=bd2d08f78a5a81e198424bcba45d16bc696073485204aca49e3e5cd8854aabe1491c463ec5fb&amp;scene=21#wechat_redirect" target="_blank" data-linktype="2" data-itemshowtype="0">用DB自增键生成uid了,还能分库吗?</a>》</span> </section> <section style="background-color: transparent;box-sizing: border-box;clear: both;color: rgb(51, 51, 51);line-height: 1.75em;"> <span style="margin: 0px;padding: 0px;text-align: justify;color: rgb(0, 0, 0);text-transform: none;text-indent: 0px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;letter-spacing: 1px;">《<a style="box-sizing: border-box;color: rgb(87, 107, 149);margin-bottom: 0px;margin-left: 0px;margin-right: 0px;margin-top: 0px;max-width: 100%;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;padding-top: 0px;text-decoration: none;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);word-wrap: break-word;" href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&amp;mid=2651962677&amp;idx=1&amp;sn=7a777eb502fba4667d7559c0f98b03f6&amp;chksm=bd2d08e98a5a81ff374aed4b8111b38b209ae3ba67dd456884db775bcede8f0f20803ded0b0b&amp;scene=21#wechat_redirect" target="_blank" data-linktype="2" data-itemshowtype="0">亿级数据“定时任务”,如何缩短执行时间?</a>》</span> </section> <section style="line-height: 1.75em;"> <span style="margin: 0px;padding: 0px;text-align: justify;color: rgb(0, 0, 0);text-transform: none;text-indent: 0px;overflow-wrap: break-word;max-width: 100%;box-sizing: border-box;font-size: 15px;letter-spacing: 1px;">《<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&amp;mid=2651962693&amp;idx=1&amp;sn=03c8aa29078a4321d18f5ee1369aa408&amp;chksm=bd2d08998a5a818fb837de67d378b3f6085bb2e0a19334e000b4e6640ff8d0282ba390deb6e5&amp;scene=21#wechat_redirect" target="_blank" data-linktype="2" data-itemshowtype="0">粉丝关系链,10亿数据,如何设计?</a>》<br>《<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&amp;mid=2651962701&amp;idx=1&amp;sn=19a3bb1c5c4ca4025bfa5a500817341e&amp;chksm=bd2d08918a5a8187ed1a0d77f1aa5bcdc686799b3f9d61a33612f5596286e34a7558feec7365&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2">几万条群离线消息,如何高效拉取?</a>》<br>《<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&amp;mid=2651962715&amp;idx=1&amp;sn=968ca2c19425d03a214e87bc38497c40&amp;chksm=bd2d08878a5a819126dee5bf05ad95826a8a378780f16aba6e2f2a8ef66f21695073fd2a2941&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2">盘口数据频繁变化,100W用户如何实时通知?</a>》<br><br><strong>调研</strong>:<br>大伙是用redis搞计数么?<br></span> </section> <p><br></p>

JAVA 开发常遇到的问题汇总

作者:じ☆ve宝贝

1、QQ互联开启防火墙后连接超时? ``` 原因是因为没有开启443端口。 ``` 2、WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. ``` 警告:过量使用内存设置为0!在低内存环境下,后台保存可能失败。为了修正这个问题,请在/etc/sysctl.conf 添加一项 'vm.overcommit_memory = 1' ,然后重启(或者运行命令'sysctl vm.overcommit_memory=1' )使其生效。.按这个提示来做,警告排。 ``` 3、 mysql启动报错: InnoDB: Unable to lock ./ibdata1, error: 11 InnoDB: Check that you do not already have another mysqld process InnoDB: using the same InnoDB data or log files. 注意:"Check that you do not already have another mysqld process " 即:"请检查您还没有另一个mysqld进程". ``` ps aux |grep mysq* //输入命令 ps aux |grep mysq* 查看mysql进程 kill number //关闭启动的进程 ``` 4、Specified VM install not found异常解决 使用ant编译项目的时候出现,Specified VM install not found: type Standard VM, name jre6 解决方法:删除工作目录下--\.metadata\.plugins\org.eclipse.debug.core\.launches 文件夹中的所有文件; 重启eclipse,ok

互联网公司面试必问的mysql题目(上)

作者:微信小助手

<section style="box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.6057298772169167" data-s="300,640" src="/upload/2ab63de539c847c0701a7999be391b76.png" data-type="png" data-w="733" style="color: rgb(107, 107, 107);font-size: 14px;background-color: rgb(246, 246, 246);"><br></p> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="display: inline-block;width: 100%;vertical-align: top;background-color: rgb(246, 246, 246);padding: 10px;box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: 5px 0%;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(107, 107, 107);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;">介绍:MySQL是一个关系型数据库管理系统,目前属于&nbsp;Oracle&nbsp;旗下产品。虽然单机性能比不上oracle,但免费开源,单机成本低且借助于分布式集群所以受到互联网公司的青睐,是互联网公司的主流数据库。</p> <p style="white-space: normal;box-sizing: border-box;"><br></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> </section> </section> </section> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;width: 100%;vertical-align: top;box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: center;color: rgba(62, 62, 62, 0.1);font-size: 104px;line-height: 1;box-sizing: border-box;"> <p style="box-sizing: border-box;">01</p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><span style="font-size: 16px;color: rgb(62, 62, 62);box-sizing: border-box;">什么是数据库事务?如果没有事物会有什么后果?事务的特性是什么?</span></p> <p style="white-space: normal;box-sizing: border-box;">事务是指作为单个逻辑工作单元执行的一系列操作,可以被看作一个单元的一系列SQL语句的集合。要么完全地执行,要么完全地不执行。</p> <p style="white-space: normal;box-sizing: border-box;">如果不对数据库进行并发控制,可能会产生 脏读、非重复读、幻像读、丢失修改的异常情况。</p> <p style="white-space: normal;box-sizing: border-box;">事务的特性(ACID)</p> <p style="white-space: normal;box-sizing: border-box;"><strong>A, atomacity 原子性</strong> 事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处理操作子集的可能性。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>C, consistency 一致性</strong></p> <p style="white-space: normal;box-sizing: border-box;">事务将数据库从一种一致状态转变为下一种一致状态。也就是说,事务在完成时,必须使所有的数据都保持一致状态(各种 constraint 不被破坏)。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>I, isolation 隔离性</strong> 由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。换句话说,一个事务的影响在该事务提交前对其他事务都不可见。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>D, durability 持久性</strong></p> <p style="white-space: normal;box-sizing: border-box;">事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。</p> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="1.1804008908685968" data-s="300,640" src="/upload/99bc35d8555ea7ed84415e0211e0b787.jpg" data-type="jpeg" data-w="449" style=""></p> <p style="white-space: normal;box-sizing: border-box;">“A向B汇钱100”<br></p> <ol class=" list-paddingleft-2" style="list-style-type: decimal;"> <li><p style="white-space: normal;box-sizing: border-box;">读出A账号余额(500)。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">A账号扣钱操作(500-100)。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">结果写回A账号(400)。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">读出B账号余额(500)。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">B账号做加法操作(500+100)。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">结果写回B账号(600)。</p></li> </ol> <p style="white-space: normal;box-sizing: border-box;">原子性:</p> <p style="white-space: normal;box-sizing: border-box;">保证1-6所有过程要么都执行,要么都不执行。如果异常了那么回滚。</p> <p style="white-space: normal;box-sizing: border-box;">一致性</p> <p style="white-space: normal;box-sizing: border-box;">转账前,A和B的账户中共有500+500=1000元钱。转账后,A和B的账户中共有400+600=1000元。</p> <p style="white-space: normal;box-sizing: border-box;">隔离性</p> <p style="white-space: normal;box-sizing: border-box;">在A向B转账的整个过程中,只要事务还没有提交(commit),查询A账户和B账户的时候,两个账户里面的钱的数量都不会有变化。</p> <p style="white-space: normal;box-sizing: border-box;">持久性</p> <p style="white-space: normal;box-sizing: border-box;">一旦转账成功(事务提交),两个账户的里面的钱就会真的发生变化</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: center;color: rgba(62, 62, 62, 0.1);font-size: 104px;line-height: 1;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">02</strong></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span style="font-size: 16px;color: rgb(62, 62, 62);box-sizing: border-box;">什么是脏读?幻读?不可重复读?什么是事务的隔离级别?Mysql的默认隔离级别是?</span></strong></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <ul class=" list-paddingleft-2" style="list-style-type: circle;"> <li><p style="white-space: normal;box-sizing: border-box;">脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据</p></li> <li><p style="white-space: normal;box-sizing: border-box;">不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。</p></li> <li><p style="white-space: normal;box-sizing: border-box;">幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。</p></li> </ul> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong>Read uncommitted</strong></p> <p style="white-space: normal;box-sizing: border-box;">读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>Read committed</strong></p> <p style="white-space: normal;box-sizing: border-box;">读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。</p> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="1.1804008908685968" data-s="300,640" src="/upload/99bc35d8555ea7ed84415e0211e0b787.jpg" data-type="jpeg" data-w="449" style=""></p> <p style="white-space: normal;box-sizing: border-box;"><span style="color: rgb(152, 152, 152);font-size: 14px;text-align: justify;">小A去买东西</span>(卡里有1万元),当他买单时(事务开启),系统事先检测到他的卡里有1万,就在这个时候!!小A的妻子要把钱全部转出充当家用,并提交。当系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。A就会很郁闷<br></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。</p> <p style="white-space: normal;box-sizing: border-box;"><br></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong>Repeatable read</strong></p> <p style="white-space: normal;box-sizing: border-box;">重复读,就是在开始读取数据(事务开启)时,不再允许修改操作</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">事例:<span style="color: rgb(152, 152, 152);font-size: 14px;text-align: justify;">小A去买东西</span>(卡里有1万元),当他买单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有1万。这时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">什么时候会出现幻读?</p> <p style="white-space: normal;box-sizing: border-box;">事例:小A去买东西,花了2千元,然后他的妻子去查看他的消费记录(全表扫描FTS,妻事务开启),看到确实是花了2千元,就在这个时候,小A花了1万买了一部电脑,INSERT了一条消费记录,并提交。当妻子打印小A的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;">Serializable 序列化</strong></p> <p style="white-space: normal;box-sizing: border-box;">Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">Mysql的默认隔离级别是Repeatable read。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: center;color: rgba(62, 62, 62, 0.1);font-size: 104px;line-height: 1;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">03</strong></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><span style="color: rgb(62, 62, 62);box-sizing: border-box;"><span style="font-size: 16px;box-sizing: border-box;"><strong style="box-sizing: border-box;">事物隔离是怎么实现的?</strong></span></span></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><span style="box-sizing: border-box;">是基于锁实现的.</span></p> <p style="white-space: normal;box-sizing: border-box;"><span style="color: rgb(62, 62, 62);box-sizing: border-box;"><span style="font-size: 16px;box-sizing: border-box;"><strong style="box-sizing: border-box;">有哪些锁?分别介绍下</strong></span></span></p> <p style="white-space: normal;box-sizing: border-box;">在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>行级锁</strong></p> <p style="white-space: normal;box-sizing: border-box;">行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁&nbsp;和&nbsp;排他锁。</p> <p style="white-space: normal;box-sizing: border-box;">特点</p> <p style="white-space: normal;box-sizing: border-box;">开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>表级锁</strong></p> <p style="white-space: normal;box-sizing: border-box;">表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。</p> <p style="white-space: normal;box-sizing: border-box;">特点</p> <p style="white-space: normal;box-sizing: border-box;">开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>页级锁</strong></p> <p style="white-space: normal;box-sizing: border-box;">页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。</p> <p style="white-space: normal;box-sizing: border-box;">特点</p> <p style="white-space: normal;box-sizing: border-box;">开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: center;color: rgba(62, 62, 62, 0.1);font-size: 104px;line-height: 1;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">04</strong></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><span style="color: rgb(62, 62, 62);box-sizing: border-box;"><span style="font-size: 16px;box-sizing: border-box;"><strong style="box-sizing: border-box;">什么是死锁?怎么解决?(前几问题是我个人最喜欢的连环炮,基本可以看出面试者的基础功)</strong></span></span></p> <p style="white-space: normal;box-sizing: border-box;">死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对付的资源,从而导致恶性循环的现象。<br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;">常见的解决死锁的方法</p> <p style="white-space: normal;box-sizing: border-box;">1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。</p> <p style="white-space: normal;box-sizing: border-box;">2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;</p> <p style="white-space: normal;box-sizing: border-box;">3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;</p> <p style="white-space: normal;box-sizing: border-box;">如果业务处理不好可以用分布式事务锁<span style="letter-spacing: 0px;box-sizing: border-box;">或者使用乐观锁</span></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><span style="box-sizing: border-box;"></span><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: center;color: rgba(62, 62, 62, 0.1);font-size: 104px;line-height: 1;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">05</strong></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span style="font-size: 16px;color: rgb(62, 62, 62);box-sizing: border-box;">SQL的生命周期?关键字的先后顺序?</span></strong><br style="box-sizing: border-box;"></p> <ol class=" list-paddingleft-2" style="list-style-type: decimal;"> <li><p style="white-space: normal;box-sizing: border-box;">应用服务器与数据库服务器建立一个连接</p></li> <li><p style="white-space: normal;box-sizing: border-box;">数据库进程拿到请求sql</p></li> <li><p style="white-space: normal;box-sizing: border-box;">解析并生成执行计划,执行</p></li> <li><p style="white-space: normal;box-sizing: border-box;">读取数据到内存并进行逻辑处理</p></li> <li><p style="white-space: normal;box-sizing: border-box;">通过步骤一的连接,发送结果到客户端</p></li> <li><p style="white-space: normal;box-sizing: border-box;">关掉连接,释放资源</p></li> </ol> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="1.2806236080178173" data-s="300,640" src="/upload/1861efb61adb4103caa9388823d37df4.png" data-type="png" data-w="449" style=""></p> <p style="white-space: normal;box-sizing: border-box;">1、 FROM:对 FROM 子句中的前两个表执行笛卡尔积(交叉联接),生成虚拟表 VT1。</p> <p style="white-space: normal;box-sizing: border-box;">2、 ON:对 VT1 应用 ON 筛选器,只有那些使为真才被插入到 TV2。<br style="box-sizing: border-box;">3、 OUTER (JOIN):如果指定了 OUTER JOIN(相对于 CROSS JOIN 或 INNER JOIN),保留表中未找到<br style="box-sizing: border-box;">匹配的行将作为外部行添加到 VT2,生成 TV3。如果 FROM 子句包含两个以上的表,则对上一个联接生成的<br style="box-sizing: border-box;">结果表和下一个表重复执行步骤 1 到步骤 3,直到处理完所有的表位置。<br style="box-sizing: border-box;">4、 WHERE:对 TV3 应用 WHERE 筛选器,只有使为 true 的行才插入 TV4。<br style="box-sizing: border-box;">5、 GROUP BY:按 GROUP BY 子句中的列列表对 TV4 中的行进行分组,生成 TV5。<br style="box-sizing: border-box;">6、 CUTE|ROLLUP:把超组插入 VT5,生成 VT6。<br style="box-sizing: border-box;">7、 HAVING:对 VT6 应用 HAVING 筛选器,只有使为 true 的组插入到 VT7。<br style="box-sizing: border-box;">8、 SELECT:处理 SELECT 列表,产生 VT8。<br style="box-sizing: border-box;">9、 DISTINCT:将重复的行从 VT8 中删除,产品 VT9。</p> <p style="white-space: normal;box-sizing: border-box;">10、 ORDER BY:将 VT9 中的行按 ORDER BY 子句中的列列表顺序,生成一个游标(VC10)。<br style="box-sizing: border-box;">11、 TOP:从 VC10 的开始处选择指定数量或比例的行,生成表 TV11,并返回给调用者。</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: center;color: rgba(62, 62, 62, 0.1);font-size: 104px;line-height: 1;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">06</strong></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span style="font-size: 16px;color: rgb(62, 62, 62);box-sizing: border-box;">什么是乐观锁?悲观锁?实现方式?</span></strong></p> <p style="white-space: normal;box-sizing: border-box;"><strong>悲观锁</strong>:</p> <p style="white-space: normal;box-sizing: border-box;">悲观锁指对数据被意外修改持保守态度,依赖数据库原生支持的锁机制来保证当前事务处理的安全性,防止其他并发事务对目标数据的破坏或破坏其他并发事务数据,将在事务开始执行前或执行中申请锁定,执行完后再释放锁定。这对于长事务来讲,可能会严重影响系统的并发处理能力。 自带的数据库事务就是典型的悲观锁。</p> <p style="white-space: normal;box-sizing: border-box;"><strong>乐观锁:</strong></p> <p style="white-space: normal;box-sizing: border-box;">乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景,这样可以提高吞吐量。</p> <p style="white-space: normal;box-sizing: border-box;">一般是加一个版本号字段 每次更新时候比较版本号</p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: center;color: rgba(62, 62, 62, 0.1);font-size: 104px;line-height: 1;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">07</strong></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span style="font-size: 16px;color: rgb(62, 62, 62);box-sizing: border-box;">大数据情况下如何做分页?</span></strong></p> <p style="white-space: normal;box-sizing: border-box;">可以参考阿里巴巴java开发手册上的答案</p> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.2716627634660422" data-s="300,640" src="/upload/636f3e78dddbf75d094a67fe95399927.png" data-type="png" data-w="854" style=""></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: center;color: rgba(62, 62, 62, 0.1);font-size: 104px;line-height: 1;box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong style="box-sizing: border-box;">08</strong></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><span style="color: rgb(62, 62, 62);box-sizing: border-box;"><span style="font-size: 16px;box-sizing: border-box;"><strong style="box-sizing: border-box;">什么是数据库连接池?</strong></span></span></p> <p style="white-space: normal;box-sizing: border-box;">从上一个sql生命周期题目,可以看到<span style="letter-spacing: 0px;box-sizing: border-box;">其中的连接在里面发挥着重大作用,但频繁的创建和销毁,非常浪费系统资源。由于数据库更适合长连接,也就有个连接池,能对连接复用,维护连接对象、分配、管理、释放,也可以避免创建大量的连接对DB引发的各种问题;另外通过请求排队,也缓解对DB的冲击。</span></p> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin: -50px 0% 5px;box-sizing: border-box;"> <section style="text-align: justify;font-size: 14px;color: rgb(152, 152, 152);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br style="box-sizing: border-box;"></p> </section> </section> </section> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="box-sizing: border-box;"> <section style="text-align: justify;color: rgb(62, 62, 62);line-height: 1.8;box-sizing: border-box;"> <p style="white-space: normal;box-sizing: border-box;"><br></p> <h3 style="margin-top: 1.5rem;margin-bottom: 1rem;font-size: 20px;max-width: 100%;box-sizing: border-box;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(21, 153, 87);line-height: 1.35;text-align: start;word-wrap: break-word !important;font-family: Menlo, Monaco, &quot;Source Code Pro&quot;, Consolas, Inconsolata, &quot;Ubuntu Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Courier New&quot;, &quot;Droid Sans Mono&quot;, &quot;Hiragino Sans GB&quot;, 微软雅黑, monospace !important;">推荐阅读</h3> <ul class=" list-paddingleft-2" style=""> <li><h2 class="" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&amp;mid=2247484841&amp;idx=1&amp;sn=f1646b751c38a4182ba6152668056816&amp;chksm=fd9853c8caefdade2dcec4657e388fb1f6f79ff6447b873ca4b2ce2263066115430be2ab7c8e&amp;token=185053168&amp;lang=zh_CN&amp;scene=21#wechat_redirect" target="_blank" data-linktype="2" style="color: rgb(87, 107, 149);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">【2018总结】即使平凡,也要热爱自己的生活</a></h2></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;word-wrap: break-word !important;font-size: 14px !important;"><span style="max-width: 100%;box-sizing: border-box;line-height: 22px;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&amp;mid=2247484188&amp;idx=1&amp;sn=40037de4844f62316465bbe4e910c69c&amp;chksm=fd98557dcaefdc6bedcaeb275aae7c340d46cf6ab0dc96e49c51982f9c53d6a44de283efc9a8&amp;token=1398134989&amp;lang=zh_CN&amp;scene=21#wechat_redirect" data-linktype="2" style="color: rgb(30, 107, 184);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;font-size: 15px !important;word-break: break-all !important;">近几个月Github上最热门的Java项目一览</a></span></span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;word-wrap: break-word !important;font-size: 14px !important;"><span style="max-width: 100%;box-sizing: border-box;line-height: 22px;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&amp;mid=2247484333&amp;idx=1&amp;sn=8c97b029692877a537d55175a8c82977&amp;chksm=fd9855cccaefdcdaffe0558ba5e8dca415495935b0ad1181e6b148b08e1c86ce5d841e9df901&amp;token=1398134989&amp;lang=zh_CN&amp;scene=21#wechat_redirect" data-linktype="2" style="color: rgb(30, 107, 184);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;font-size: 15px !important;word-break: break-all !important;">推荐10个Java方向最热门的开源项目(8月)</a></span></span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;word-wrap: break-word !important;font-size: 14px !important;"><span style="max-width: 100%;box-sizing: border-box;line-height: 22px;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&amp;mid=2247484644&amp;idx=1&amp;sn=5016caaf97e498b76de2189e3f55e9dc&amp;chksm=fd985285caefdb93f4e3c7545d30edac6ad31b99f1fcc4503350101f0b20bba9a9705ed7d124&amp;token=1398134989&amp;lang=zh_CN&amp;scene=21#wechat_redirect" data-linktype="2" style="color: rgb(30, 107, 184);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;font-size: 15px !important;word-break: break-all !important;">Github上 Star 数相加超过 7w+ 的三个面试相关的仓库推荐</a></span></span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;word-wrap: break-word !important;font-size: 14px !important;"><span style="max-width: 100%;box-sizing: border-box;line-height: 22px;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&amp;mid=2247484730&amp;idx=1&amp;sn=86e35dfea1478221b6d14a263e88ac89&amp;chksm=fd98535bcaefda4d4f03bf0cd2e0a8fd9f44b1a2b118457a0c8b3de2ff8a1f4c4b7cd083f40e&amp;token=1398134989&amp;lang=zh_CN&amp;scene=21#wechat_redirect" data-linktype="2" style="color: rgb(30, 107, 184);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;font-size: 15px !important;word-break: break-all !important;">11月 Github Trending 榜最热门的 10 个 Java 项目</a></span></span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;color: rgb(74, 74, 74);line-height: 22px;word-wrap: break-word !important;font-size: 14px !important;"><span style="max-width: 100%;box-sizing: border-box;line-height: 22px;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&amp;mid=2247484817&amp;idx=1&amp;sn=12f0c254a240c40c2ccab8314653216b&amp;chksm=fd9853f0caefdae6d191e6bf085d44ab9c73f165e3323aa0362d830e420ccbfad93aa5901021&amp;token=1398134989&amp;lang=zh_CN&amp;scene=21#wechat_redirect" data-linktype="2" style="color: rgb(30, 107, 184);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;font-size: 15px !important;word-break: break-all !important;">盘点一下Github上开源的Java面试/学习相关的仓库,看完弄懂薪资至少增加10k</a></span></span></p></li> <li><h2 class="" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&amp;mid=2247484845&amp;idx=1&amp;sn=415ea425b9f8be53b7c72b11de5f66e7&amp;chksm=fd9853cccaefdada543639063b2b9ad21aaae828ea776990eeeab8fe82125162630d94487d9a&amp;token=185053168&amp;lang=zh_CN&amp;scene=21#wechat_redirect" target="_blank" data-linktype="2" style="color: rgb(87, 107, 149);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;">12月GithubTrending榜Java项目总结,多了几个新面孔</a></h2></li> </ul> <blockquote style="margin-top: 1em;margin-bottom: 1em;padding: 15px 15px 15px 1rem;max-width: 100%;box-sizing: border-box;word-wrap: normal;border-left-width: 6px;border-left-color: rgb(220, 230, 240);letter-spacing: 0.544px;white-space: normal;color: rgb(129, 145, 152);font-size: 0.9em;line-height: inherit;background: rgb(242, 247, 251);overflow: auto;word-break: normal;"> <p style="max-width: 100%;box-sizing: border-box;min-height: 1em;font-size: inherit;color: inherit;line-height: 2em;word-wrap: break-word !important;">专注Java知识分享!开源 Java 学习指南——JavaGuide(21k+ Star)的作者。<span style="max-width: 100%;font-size: 15.3px;letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;">公众号多篇文章被各大技术社区转载。欢迎关注!</span></p> </blockquote> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <figure style="max-width: 100%;box-sizing: border-box;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;word-wrap: break-word !important;"> <img class="" data-ratio="1" data-type="jpeg" data-w="258" title="我的公众号" width="258px" src="/upload/cbd716d5fdc5e6264bbdc979a33185e7.jpg" style="margin-right: auto;margin-left: auto;box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;font-size: inherit;color: inherit;line-height: inherit;display: block;word-wrap: break-word !important;visibility: visible !important;width: 175px !important;"> </figure> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 0, 0);letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;">如果喜欢本文的话,小伙伴们不要忘记给本文点个好看以及转发分享。</span></p> <p style="white-space: normal;box-sizing: border-box;"><br></p> </section> </section> </section> </section> </section> </section> </section> <p style="text-align: center;"><br></p>

AJAX加载了HTML但是HTML里面的CLICK事件无效

作者:じ☆ve宝贝

``` $('body').on('click' , '.load' , function(){ do something ... }); ``` 将事件委托到body(当然可以是其它父元素),等事件冒泡到父元素上面再进行事件处理。

The MySQL server is running with the --secure-file-priv option so it cannot execute this

作者:じ☆ve宝贝

## 问题 MySQL 使用SELECT ... INTO OUTFILE将选中的行写入一个文件。列和行结束符可以指定生成一个特定的输出格式,结果提示:** The MySQL server is running with the --secure-file-priv option so it cannot execute this ** ## 解决方案 ` SHOW VARIABLES LIKE '%secure%'; # 查看secure_file_priv的value地址 ` ** 将SQL改为(注意地址"\","/"的区别) ** ``` SELECT * INTO OUTFILE "${value}/test.sql" FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM user; ```