关于作者:
李萌,他是数据领域的专家,是国内顶级的Elastic Stack实务专家,也是中国首批21位Elastic官方认证工程师之一。 他于 2012 年创立了 Elasticsearch,在 Elastic Stack 技术栈的开发、架构、运维、源代码和算法方面拥有丰富的实践经验。 他负责过多个 Elastic Stack 项目,包括大数据分析、机器学习、业务查询加速、日志分析和基本指标监控。 拥有超过10年的技术实践经验,擅长大数据、混合技术栈和系统架构。
序言
图:Elasticsearch目前在db-engine中排名第8位
Elasticsearch博大精深,提供了非常丰富的应用场景功能,以及丰富的API命令操作,有些API非常好用,有些API使用起来很难防范。
以下围绕某客户在客户端应用中误用集群状态命令展开,从问题定位到问题解决,记录自己的流程和方法,以及一些经验总结(注:具体客户信息不方便透露,以下部分**信息仅为示意图)。
一、案例介绍一、项目背景简介
客户使用ES解决日常数据查询和存储问题,并利用ES优异的水平扩展特性,满足多种场景应用。
ES 集群版本属于 56.已经超过Elastic官方支持的版本,集群中节点少于10个,节点硬件配置均衡一致,标准基于性能的硬件配置在合理范围内,应用于业务系统提供查询或更新等,并提供日常定期巡检, 基本正常稳定,但一直专注于集群运维本身,很少深入应用端程序进行检查分析,业务线太多,资金有限。
ES 集群配置不采用主节点与数据分离的设计,所有节点都具有相同的角色权限。 ES集群中的数据量也在正常支持容量范围内,集群索引中的分片数量在2W以上。
客户端应用基于 Spring Data Elasticsearch 开发框架,该框架引用了 trasnport-client 直连模式,不使用任何代理加载产品。
客户端应用部署多个实例,递增2倍,需要在ES集群中做一些“大”的数据写入和查询,以及瞬时并发操作,不管怎么操作,ES的并发性都不高,但是应用端程序就是运行速度不快,这是非常不合理和不合理的,常识告诉我这是不正常的。
图:客户公司应用项目架构示意图,客户端采用传输-客户端直连方式。
二、问题现象及事故原因
只要客户端应用开始运行,ES集群就会立刻变慢,但从ES集群的整体资源消耗来看,ES所在节点的CPU MEM硬盘IO并不高,其数据节点甚至很低,远远没有达到节点的瓶颈。
仔细观察发现,集群的主节点流量特别高,其他节点的数据流量传输到主节点,超出了主节点单节点网络IO的限制,明显异常。 但是,在生产环境中进行故障排除并不容易。 后来,在本地开发环境进行模拟压测后,最终确定问题是由客户端的集群管理操作API引起的。
最终找到了集群状态 api statistics 命令,客户端应用在做实际业务之前,每次都会调用这个 api 命令来获取集群的一些索引和映射信息,因为客户端是多线程的,部署了多个实例,只要并发数量高,所有流量都不可避免地会打到主节点, 导致整个集群的响应速度较慢。由于整个集群有近 2 个 W 分片,因此需要运行 state 命令收集集群中的所有索引分片,最后汇总到主节点,导致主节点的实际网络 I/O 超出限制。
图:集群状态 API 返回内容,索引越多,返回的内容越大。
二、调查过程与分析手段我们已经简要地谈到了问题现象和事故原因,现在我们将重点介绍问题排除过程以及所采用的工具和方法。
特别是由于远程协同分析排查和客户公司的行业特点,外部无法直接操作任何远程节点,必须由客户公司的运维人员间接指导操作和排查,过程略显曲折。
1. 检查服务器端集群
首先是ES集群问题的调查,这是一种非常正常和直接的思维,调查是在问题的爆发点进行(PS:类似于警察先赶到案发现场取证)。 由于集群版本为 56.X,由于一些原因没有开启官方的xpack功能,所以没有内置的Kibana监控可视化报表,国内早期用户大多都是在使用开源免费版搭建集群,客户公司基于Zabbix搭建了集群节点的基础指标监控,最后还有一个,非常罕见。
1) Zabbix监控与分析
很快,基于Zabbix,对每个ES机器节点的指标进行监控分析,按照常规例程,对CPU、内存、磁盘IO等进行分析,一切正常,但不高。 这是非常令人困惑的,显然集群响应速度很慢,客户端应用开发者也如实响应,而且部署的实例很少,所以经过初步分析,并没有明显的问题所在。
然后,对节点网络IO进行分析,发现问题点,其中主节点流量特别高,超出了网卡的限制。 按照这个套路,我继续查看其他数据节点的网络IO,也比较高,然后观察到数据节点的网络IO流量刚好等于Master节点的网络IO流量,终于找到了突破口。
需要注意的是,虽然Zabbix可以监控每个独立节点的网络流量,但它无法看到节点之间以及应用客户端和服务器之间的网络流量,这是非常不友好的。
图:Zabbix网络流量的图,提供单个节点的快速视图。
2) IFTOP监测与分析
在zabbix的帮助下,已经找到了突破口,下一步就是需要网络流量关联图。 这时,首先想到的就是对Elastic Stack Packetbeat网络IO流量报文的可视化监控和监控,客户公司当即讨论是否可以安装配置。 后来,客户公司的运维工程师临时安装了Linux网络命令iftop,终于能够分析出ES各节点网络中IO流量的流向,但观察分析比较辛苦,无法绘制网络图, 所以观察仍然不够全面。
iftop 只在单个节点上执行,所以你只能看到进出单个节点的网络流量,但这已经很好了,但需要更长的时间。
基于对网络IO流量进出的初步分析和观察,迅速做出决策,先重启已有的Master节点,让ES集群重新选择新的Master节点,但发现新选的Master节点的流量仍然很大。 然后,我也临时申请了新增 2 个 ES 节点,以为可以分散客户端访问的压力,但实际上并没有从根本上调研。 这时判断是,有些业务指标查询导致流量比较大,恰好在主节点中进行了转移和汇总,但是这里没有分析客户端的流量,所以做了一些无用的紧急服务器端调整,但也证明问题不在ES服务器上。
图:IFTOP网络流量示意图,可以分析单个节点的流量进出,也不错。
3) Packetbeat 监控分析
由于某些原因,Elastic Stack 监控分析产品没有部署,尤其是 packetbeat 网络流量监控分析产品,官方默认提供的网络流量图非常有用,可以更快速地定位流量方向,相比 ITTOP,更全面,可以概括为网络版的 IFTOP。 PacketBeat 内置了一些官方可视化报表,如果觉得还不够,可以根据 ES 提供的分析能力自行设计。
图:PacketBeta网络IO流量监控分析图表、输入和输出。
2. 客户端故障排除
第二种是从客户端应用进行检查。 但事实上,当客户公司的运维人员发现问题并第一时间联系我时,我的第一个问题是客户端应用在做什么业务,业务类型是什么。 运维人员也如实告知了正在做的业务类型和应用,其实我只能总结一下,并不知道详细的业务运营流程和影响,对我来说,反正我知道有业务运营影响集群,还要继续调查到底是怎么影响的。 必须说明的是,这可能是国内IT运维行业的一个通病,似乎运维属于端支撑,本质应该更多地参与到业务系统的前沿,而其背后的运维问题应该从业务中去理解。
然后,通过ES服务器端的排查,已经掌握了一些信息,但是远远不够定位问题,客户端排查还有很长的路要走,必须找到问题。 ES集群中有很多慢响应,但是服务端只能发现问题,却无法从根本上解决,所以通过在服务器上运行线程池和任务命令,发现集群的管理线程池非常大,任务一直都满载着, 这是不正常的,这更能确定客户端的某些应用程序一定是恶意操作这些命令。
1) 线程池监控与分析
集群响应慢,集群线程池是必须考虑的一个点,会看到累计任务量,打开指令观察后,管理线程池特别高,所以判断客户端正在做一些任务,并且属于管理线程池,具体还不确定, 因为客户端应用程序没有看到特定的**调用模式。
图:线程池示意图,用于监控 ES 节点上的任务数。
2) 任务监控和分析
借助线程池分析,您可以定位管理线程池来大规模执行任务,并使用该任务查看正在分析的具体任务。 (ps:在实际客户环境中,发现有大量的状态和统计任务,其中状态任务数量明显高,非常异常,这里不方便透露,这个结果如何压测,后面会详细列出)。
图:任务的示意图,可用于查看特定任务类型。
3)统计监控分析
借助任务监控分析,发现有大量的统计指令,然后在服务端执行一次,看看情况如何,实际响应速度比较慢,但逻辑上正常,生成的队列数量不高, 但是执行速度较慢,根据上面的判断,应该是其他任务阻塞造成的。
stats 负责集群监控和检查响应,常规集群黄、红、绿三色由此而来; 另外,它还收集索引和节点的统计信息,返回的数据量不多,所以一般可以忽略,但要注意后期需要传输客户端访问。
图:stats 命令执行示意图。
4) 状态监测和分析
借助任务监控分析,发现有大量的状态指令,然后在服务器上执行一次,找到了问题点,执行时间很长,响应返回的内容超过70MB,这就是问题所在,可以回答为什么之前的主节点流量这么高。 最后,问题变得越来越清晰和确定。
图:状态命令执行示意图。
5) 传输客户端应用程序访问
借助前面的服务器端现象分析,越来越确定问题出在客户端应用**上,最有可能的是操作错误。
首先,与客户沟通,让客户端应用**访问ES和程序版本,客户端开发团队配合很好的,很快就得知应用客户端是基于Spring Data Elasticsearch框架的,使用transport-client机制来访问操作ES,但是这时候无法定位为客户端导致的, 也不能要求客户匆忙提供源代码。不久之后,相应的测试程序源代码在本地编写。
传输客户端绑定。
模拟 Spring Data Elasticsearch 配置 transport-client,示例来自官方文档*
configuration
public class transportclientconfig extends elasticsearchconfigurationsupport
bean(name = )
public elasticsearchtemplate elasticsearchtemplate() throws unknownhostexception
6)JMe压力测试模拟
由于某种原因,我们只能提供间接服务,所以为了彻底解决上述问题,我们需要在本地模拟测试,并且必须先模拟生产问题,然后才能要求客户端提供源代码。 根据之前从服务器和客户端应用中学到的信息,下一步是做一个压力测试,特别是选择jmeter工具,快速配置本地集群,并附加客户端应用访问**。 在压力测试过程中,可以同步观察ES服务器的ThreadPool和Task,并可以重现生产问题,并快速获得所需的结果。
图:JMe压测示例,开启线程数,线程数超过ES测试服务器上的线程数。
图:JMe压力测试示例,一个状态命令的执行会消耗大量资源。
由于在生产中也发现了同样的问题,借助 jmeter 压力测试在本地环境中,最后一步是审核客户应用开发团队,速度非常快,很快就能找到客户应用端,然后再进行具体的业务操作,就会调用集群状态 api 来判断业务逻辑, 确定索引是否存在,确定索引字段是否存在等。
最终,问题找到了,原因知道了,事情也就结束了。
对客户申请的访问。
使用状态确定索引的映射信息
public map getmappingbyfield(string indexname, string type) throws ioexception
map mapping = mappings.get(type).getsourceasmap();
map properties = (map) mapping.get(es_properties);
return properties;
3. 回顾问题分析过程
服务器端分析,寻找突破口。
客户端分析,以缩小故障排除范围。
模拟测试以复制生产问题并确定问题的原因。
分析应用端,找出问题所在。
修改观察结果以确认问题已解决。
吸取的经验教训,审查所有其他相关**。
图:故障排除过程和过程。
3. ES技术架构原理
本次 ES 故障排除涉及到很多知识点和技术原理,这里专门讲解与此相关的架构原理,供大家日后参考和分析。
1. ES架构原理
虽然 ES 声称是可以水平扩展的分布式架构,但它指的是数据节点或其他非管理节点。 实际上,ES 是一种典型的主从架构模式,一个集群只有一个活跃的主节点,主节点负责管理集群的所有元数据信息,包括节点信息、索引信息、分片信息、节点和索引路由信息、节点和分片路由信息等,集群需要先在主节点中执行一个管理命令, 然后将其分发到其他节点。
这对于理解和解释为什么主节点的网络流量正好等于此 ES 故障中其余节点的网络流量之和非常重要。 当客户端应用发起状态计数时,主节点先接受指令,然后分发给其他节点进行状态统计,最后汇总到主节点,导致主节点网络流量极高,超出网卡限制,ES集群响应缓慢, 但实际CPU和内存消耗并不高。
随着集群规模越来越大,大老板的压力越来越大,如果大老板失败了,大老板就会连任,这听起来好像不符合社会组织。 下次能不能修改一下,设计一个大老板和第二个主人的模型,然后把大老板和两个主人的职责分开,大老板太忙了,两个主人分担一些。
图:ES主从架构的分布式示意图,集群只有一个活动主节点。
2. ES线程池
ES是内部设计了多个任务线程池的数据库产品,不同的线程池有不同的任务和职责; 线程池也分为各种类型,不同的线程池类型响应不同的任务场景。 线程池的数量和类型因 ES 版本而异,尤其是在 5 中x 与 7X版,这种跨专业版,差别挺大的。
作为机构的ES老师,我经常与J**A学生交流,发现了一些严重的认知误区: 1很多同学认为,由于GC机制的原因,J**A无法开发数据库产品; 2.大部分人学习掌握 J**线程池只用于简单的多线程业务场景,从未想过 ES 集成了几十个线程池。 因此,必须承认,ES对于J**A开发大师来说是一个非常好的产品,特别是对于做后端开发,想要更深入、更高级的同学来说。
了解 ES 线程池的内部设计非常重要,这可以解释为什么在这次 ES 故障中,只有 Active Master 节点的管理线程池特别忙,其余的线程池一般都非常空闲,其余节点的线程池也非常繁忙。 客户端应用发起状态计数,第一个接收任务的任务是主节点的管理线程池,线程池类型为伸缩,最大线程数为固定值,不超过实际CPU复合数,也不能超过固定值5, 而不是根据节点的CPU核心数自动弹性设计。
当客户端应用采用多线程执行模式时,每次在执行业务操作之前,都会执行一次状态统计,做出业务逻辑判断,无形中增加了集群的负载和主节点的任务数量。 正是因为负责执行状态任务的线程池是固定值,主节点的CPU不会满,导致所有业务操作受阻。
有时候官方文档没有列出,需要通过ES源码来检查,我还是没弄清楚,不仅在以前的历史版本中,而且在现在的最新版本中,比如现在的715.x,有些线程池在官方文档中没有列出,但可以在集群监控中查看。
图示:ES 内部线程池划分(版本 7。13.x,来自机构的 ESVIP 课程)。
ES 线程池初始化源码:orgelasticsearch.threadpool.threadpool */
public class threadpool implements reportingservice, scheduler
3. ES集群统计的执行过程
集群状态 API 执行一条指令一次,指令传输到主动主节点,主动主节点将指令分发给每个节点,每个节点收集信息并发送回主节点,然后主节点响应客户端。
在故障排除之初,最初的判断是错误的,认为客户端在做大量的业务数据查询任务,并且所有节点的数据量都很高,其中很多都依赖于主节点的外部输出,但事实并非如此。
图:集群状态API执行过程示意图。
4. ES动态创建索引
ES是典型的免费schema数据产品,可以动态创建索引,也可以动态创建索引字段,无需优先级声明,也无需逻辑判断应用中是否存在**,是否需要创建,这是ES非常优秀的动态扩展能力之一, 基于此为应用开发带来了很多便利,比如著名的“大宽表模式”查询场景,解决了海量数据关联的实时查询问题。
ES可以提前创建索引,也可以不创建索引,可以通过写入第一条数据来动态创建索引,同时可以自动映射索引的内部结构。 如果在第二次数据写入中添加了大量新的数据内容结构,则当前索引的映射将自动更新,并且映射将自动刷新。 如果缺少新添加的数据字段,则不会出现错误。 默认情况下,ES 内部会根据字段计算字段的类型。
动态创建空索引。
put my-index-000001
添加数据,动态创建索引,并自动估计字段类型。
put my-index-000001/_doc/1
create_date": "2015/09/02"
更新数据并动态添加新的字段类型。
put my-index-000001/_doc/1
my_float": "1.0",
my_integer": "1" ,"create_date": "2015/09/02"
5、transport-client
Transport Client 是早期正式推出的应用访问机制,自 REST API 上线以来,官方一直试图要求切换,原因没有具体说明。 transport 是一种直接连接方式,直接连接到 ES 集群,连接后保持持久连接,需要定期执行一些内部 stats 命令来检查集群监控状态,这实际上是非常冗余的,极端情况下会消耗集群资源。
ES 集群中其他指令的内部通信或执行是通过 Transport 机制进行的,即使由 REST API 执行,也会在内部转换为 Transport 机制进行执行。
REST访问比传输更解耦,也可以尽量避免恶意干扰传输通信。
图:transport-client 和 REST API 之间的连接示意图。
四、专家建议
这一次,花了几天时间才找到问题,定位问题,解决问题,还有一些经验建议需要解释。
1.全面的监控系统
监控系统是运维之眼,集群的各类运行信息需要借助强大的监控系统来提供实时分析。 在这种情况下,客户公司的监控系统比较传统和落后,虽然有Zabbix,但在一些新的问题分析方式上并不好,而且非常缺乏,比如分析集群每个节点的流量,包括服务器和客户端之间的关系。
选择一款全面且具有非常独立视角的监控产品非常重要,而 Elastic Stack 是新时代的产品,可以帮助我们改进优化故障排除思维。
2. 权限安全隔离
大多数数据库产品都提供了一些基本的安全策略和保护,可以通过设置一些安全用户组和角色权限来限制这些策略和保护。
例如,传统的关系数据库 MySQL 可以通过为客户端应用程序分配较少的权限来限制。 在早期的 ES 版本中,由于 ES 没有提供安全保护机制,很多应用团队直接使用它,并没有实现基于用户组的权限隔离。 最新版本的 ES 提供了开源且免费的基础安全策略,可以避免客户端应用程序通过用户组权限进行无意操作。
3. 全面的知识体系
在这种情况下,从集群的后端运营分析,到应用端的源码分析,再到本地环境的仿真测试,涉及的技术点非常广泛,无法从单一维度发现和解决,也不能仅从ES知识层面解决。 没有人可以只从ES集群中跑出表面定位问题,很多问题都在尽头,但原因其实在另一端,这需要跨界能力和思维,当然最重要的是建立自己的知识体系,有自己独立的解决问题的想法,也要掌握必要的工具和软件, 不仅限于 ES 的范围。
为了用好 ES,我们需要掌握开发技能,熟练使用 ES 提供的开发特性,了解 ES 各种特性的边界,防止滥用。 我们需要掌握ES集群架构的基本原理和基本操作机制,避免认知误区,比如ES是典型的主从架构分布,而不是无中心分布。 我们需要掌握一般的运维技能,从操作系统的基础环境到ES运行的各种指标信息。
4. 全栈工程师理念
随着业务需求和社会的发展,我们需要更多的全栈工程师,当然也要说明,不需要一个工程师同时承担多个工作,也不是按照国内一些企业的“挤全栈”的说法。 相反,强调工程师的专业水平,工程师可以根据自己的工作岗位轻松转换角色,而不仅仅是固定的岗位。 很多优秀的IT产品,不是由在自己工作岗位上工作的人制作的,而是由一些跨界人士制作的。
在这种情况下,看似集群的问题是服务器,其实是开发知识的局限性造成的,最终的解决方案也是修改应用端来解决,这是一个典型的跨界问题,逐渐被服务器发现是应用端的问题。 为了模拟生产环境的问题,需要使用压力测试工具,这似乎是测试的责任,但为了解决问题,有必要从后向前工作。 为了确定线程池设置问题,对应的版本源码,去检查并阅读相应的线程池设置,因为官方文档没有。 若要识别客户端应用问题,请根据客户端开发人员提供的信息编写模拟的客户端应用行为。
目前,公司在中国的工程师大多是单一职责的岗位和技能,尤其是专注于前后端分离后,前端和后端的技能比较认真,前端很多工资都很高,上升速度快,看不起后端, 后端逐渐远离前端应用,更关注前端操作模式;后端应用和大数据开发也分离,将大数据开发与应用开发分开,导致工程师的专业素质迅速下降,很多大数据工程师没有良好的编程技能,这是一个值得思考的问题。
引用
状态参考文档。
ThreadPool 参考文档。
Elasticsearch 传输客户端参考文档。
Spring Data Elasticsearch 参考文档。
JMemeter HTTP 请求参考文档。
DBAPLUS 社区欢迎 editor@dbaplus 技术人员的贡献cn