热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ElasticSearch那些事儿(四)

在使用过程中,陆陆续续踩了不少坑,每次觉得无法逾越时,心里都想放弃,一是因为这东西要完全掌握不是那么容易,需要花很多时间;二是如果继续使用曾经用过的zabbix,说不定可以很快满足

在使用过程中,陆陆续续踩了不少坑,每次觉得无法逾越时,心里都想放弃,一是因为这东西要完全掌握不是那么容易,需要花很多时间;二是如果继续使用曾经用过的zabbix,说不定可以很快满足眼前的需求,从而可以抽身做其他事情。但坚持下来,就一定能从坑里爬起来,从而对这个系统更加了解,并利用这头”猛兽”帮助我做更多事情。原因很简单,ElasticSearch除了是一个分布式数据库,还是一个扩展性和可用性都很强的近实时搜索引擎。

目前为止,踩过以下几个坑:

  1. 集群搭建不成功
  2. 未使用内网IP,导致恢复缓慢
  3. 未使用队列及logstash,导致数据丢失
  4. Master和DataNode未分离,导致集群不稳定
  5. Logstash吞吐量问题
  6. Logstash如何创建Mapping
  7. head插件安装错误

犯了这么多错误基本上都是使用不当、以偏概全的原因,以为看了一点文档,就凭直觉可以猜测到系统的所有内容,造成了后续问题的不断涌现,下面就逐一说一下淌坑过程

集群搭建不成功

一开始是在单机上玩ElasticSearch的,上生产环境肯定要使用它的集群功能,但文档说只需要在elasticsearch.yml中设置cluster.namenode.name即可,ElasticSearch节点启动时会自动发现集群并加入到集群,但全部设置完毕后,竟无法使各个节点组成集群,最后发现这种方法只在一台机器上有效,而要组成集群,需要在每台节点做以下配置:

 


discovery.zen.ping.unicast.hosts: ["Node1_IP:9300", "Node2_IP:9300", "Node3_IP:9300"]

ElasticSearch一般会开两个端口,一个是集群维护端口,如上面的9300; 一个是对外提供的端口,默认是9200。

未使用内网IP,导致恢复缓慢

在部署集群时,我挑选了几台配置相近的同网段机器,但当时其中一台机器操作系统没有加载内网网卡,为了偷一下懒,便直接使用了外网IP,集群是跑起来了,运行了一段时间也没有什么问题,但随着流量越来也大,终于有一天Master突然down掉了,我当时心想,ElasticSearch集群本身具有故障转移功能,马上会分配一个Master节点,然后我只需要把原先的Master节点重启即可,然而重启了之后,通过bear页面查看恢复情况,发现集群长时间处于黄色状态(有replica shard丢失),而丢失的shard一直处于未分配状态,并没有如我预期的:启动后,该节点可以重用在磁盘上的shard数据,上报给Master,不需要数据拷贝,立马恢复为绿色状态。过了几分钟后,我发现恢复的shard数正以缓慢的速度增加,便推导出这样的错误结论:ElasticSearch在某一台机器挂掉后,只会从primary shard复制数据,即便节点迅速恢复,也不会复用该节点上的数据,如果是这种实现方式,我认为这种恢复速度是无法接受的,顿时产生了无法继续使用下去的念头,当时的心情是无比失落的。

而ElasticSearch的使用是相当广泛的,所以可以断定是我的使用方法有问题,要么是我选的版本不稳定,要么是其他的原因,而稳定版一般出问题的几率不大,因此在换版本之前,需要找其他方面的原因,很久之前看过一篇google的slide,上面有一页介绍了不同介质数据的传输速度:外网的传输速度在10ms级别,而内网却在20微秒级,这种速度的差异便会造成以下几个方面的影响

  • 集群无法提供正常服务:因为每个请求,ElasticSearch节点都会经过转发和收集两个过程,如果使用外网网卡,便会造成延迟大,访问量上不去,而流量到达一定程度后,集群很快便无法提供正常服务
  • 由于ES集群已经无法正常服务,所以down机、恢复困难一系列综合症的情况便会陆续发生

后续我将集群切到了内网中,再测试重启某一个节点,便不会再出现恢复一个节点需要半天的情况了。

slide

未使用队列或logstash,导致数据丢失

最初用到的架构非常简单: 使用ES(ElasticSearch缩写)集群作为存储,beats和rsyslog作为shipper向ES集群发送数据,使用这种架构的主要原因是配置简单,ES本身是一个高可用集群,直接把数据发过去就好。而自己心里还产生了为什么会有ELK架构,感觉Logstash是多余的想法,在发生了几次down机之后,才发现之前的想法很傻很天真,之前的架构也有明显的问题

old

  • 在某一个节点down掉后,如果不马上恢复,在不了解beats负载均衡机制的前提之下,很难判断数据还会不会发送给down掉的节点,而新增一个节点,需要修改所有beat的配置,即这里至少要使用一个负载均衡器给所有ES节点做负载均衡
  • ES是一个高可用集群,但目前还没有足够的使用经验,所以可能今后还会出现集群故障的问题,而出故障,很可能造成数据的丢失,为了避免这种情况发生,需要在beats和ES集群之间构建一套可持久化的队列,最简单的队列是redis,而logstash放在redis两边分别作为生产者和消费者。想到的方案便是beats->logstash->redis->logstash->ES,这样便解决了丢数据的问题,当然最新版的logstash可以将数据持久化到磁盘上,也许可以对此模型进行简化

Logstash和Redis的使用都非常简单,这里就不一一介绍,值得注意的是,如果要使用redis做持久化,需要使用Redis的List的方式,而不是Sub-Pub的方式,以下是具体的架构图,箭头的方向是数据流动的方向。

new

Master和DataNode未分离,导致集群不稳定

在ES集群中,节点分为Master、DataNode、Client等几种角色,任何一个节点都可以同时具备以上所有角色,其中比较重要的角色为Master和DataNode:

  • Master主要管理集群信息、primary分片和replica分片信息、维护index信息。
  • DataNode用来存储数据,维护倒排索引,提供数据检索等。

可以看到元信息都在Master上面,如果Master挂掉了,该Master含有的所有Index都无法访问,文档中说,为了保证Master稳定,需要将Master和Node分离。而构建master集群可能会产生一种叫做脑裂的问题,为了防止脑裂,需要设置最小master的节点数为eligible_master_number/2 + 1

脑裂的概念:

如果你有2个Master候选节点,并设置最小Master节点数为1,则当网络抖动或偶然断开时,2个Master都会认为另一个Master挂掉了,他们都被选举为主Master,则此时集群中存在两个主Master,即物理上1个集群变成了逻辑上的2个集群,而当其中一个Master再次挂掉时,即便它恢复后回到了原有的集群,在它作为主Master期间写入的数据都会丢失,因为它上面维护了Index信息。


根据以上理论,我对集群做了如下更改,额外选取3个独立的机器作为Master节点,修改elasticsearch.yml配置

 


node.master = true
node.data = false
discovery.zen.minimum_master_nodes = 2

修改其他节点配置,将其设置为DataNode,最后挨个重启

 


node.master = false
node.data = true

Logstash吞吐量问题

在使用了新的架构后,我发现了当流量上来后,Redis的队列会持续增长,消费速度跟不上生产速度,造成的问题是数据在Redis中堆积,图表展示有大量的延迟。解决这个问题有以下几个思路

  1. 可能是ES插入速度太慢,需要调整参数提升插入性能
  2. 可能是Logstash吞吐量低,需要增加每次向Redis拿数据的缓存、增加向ES输出的缓存、增加线程数、增加每次批量操作的content length

对于ES调优中,我调整了线程数,增加线程队列,增大shard数,但都没有解决问题。

而Logstash调优,我首先调整了LS_HEAP_SIZE参数,让Logstash可以同时处理大量的数据,然后主要专注在调整Logstash的Input和Output插件参数上,插件中可以设置线程数、batch_count数值等,而当我将Redis插件参数改为batch_count=>10000后,发现队列不再一直增长了,它会涨到一定程度后,瞬间减少到2-3位数,即队列的长度在一定范围内浮动,当时欣喜若狂,以为自己解决了,但跑了大概5个小时候,发现队列又开始不断增长了,问题并没有得到解决。而产生解决了的假象应该是我增加了Logstash内存的原因,数据只是先把Logstash内存填满,再开始填队列,而填满Logstash内存花了几个小时,关键的Logstash到ES的吞吐量还是没有上去,在access日志中,无论如何也无法让bulk API的content length增加,如下图中的长度一直维持在2K左右。

accesslog

最后,我采用了替换Logstash版本的策略,更新了时下最新的5.1.1版本,由于新版的配置和旧版配置不一样,所以认真研究了一下配置,在这个过程中,我发现了一个-b参数可以修改批量插入的大小,也许就是我需要的。果然,将这个参数由默认的125改为了1000,顺利的解决了这个难题,同时也证明了并不是版本问题,还是使用问题,而这个参数也正是修改content length的方法,顺便说一下,如果你使用nginx作为负载均衡器,你需要同时增加client_max_body_size参数,避免产生content length过大而返回413错误码。

Logstash如何创建Mapping

当使用Logstash进行转发时,有可能你的数据都在一个Index中,当然你也可以设置不同的Index,这篇文章中就有根据type来划分Index的方法,不管划不划分Index,都会默认生成一个或多个mapping结构,mapping结和不同的type即对应MySQL中的数据库和表结构信息,当然我这里不是为了说明它们的区别,而是我们无法自定义字段的类型。

这会产生各种各样的问题,比如它会默认产生analyzed类型的string字段,会自动将带有连接符的字符串分为两个字符串输出,即"idc-1"这样的字符串会输出为"idc"和"1",这并不是我想要的,让我相当困扰,而Mapping在生成后是无法修改字段的,除非你换一个新的字段。

解决这个问题的方法并不在mapping上,而我却花了很多时间在这个上面,最终答案却是使用template,在template中可以定义你需要的mapping,这样便解决以上问题。到此,我还是不能完全理解里面的机制,以后抽空了解后再补上。

head插件安装失败

上文有介绍head插件,它是一个可以显示集群状态及操作ES集群的UI,可以取代官方的X-Pack,后者只有30天的试用期,因为创业公司,能用免费的尽量采用免费的。在集群中,有几个节点安装该插件会失败,提示:Unable to veryfy checksum for download plugin ...,google上查了一圈仍然没有找到解决办法,最后试着手动将该插件下载然后解压到/usr/share/elasticsearch/plugins/目录下,并将目录改为head即可解决该问题。

以上问题是我这段时间来碰到的坑,每个都花了不少时间去解决,自己也比较幸运,花在上面的时间没有白费。因为个人觉得这个技术栈实在是比较好,而资料主要以英文的为主,把自己的经历写下来,希望今后不再犯同样的错误,也希望可以帮助其他使用该技术的同学.


推荐阅读
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 006_Redis的List数据类型
    1.List类型是一个链表结构的集合,主要功能有push,pop,获取元素等。List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,List的设 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 本文介绍了Redis中RDB文件和AOF文件的保存和还原机制。RDB文件用于保存和还原Redis服务器所有数据库中的键值对数据,SAVE命令和BGSAVE命令分别用于阻塞服务器和由子进程执行保存操作。同时执行SAVE命令和BGSAVE命令,以及同时执行两个BGSAVE命令都会产生竞争条件。服务器会保存所有用save选项设置的保存条件,当满足任意一个保存条件时,服务器会自动执行BGSAVE命令。此外,还介绍了RDB文件和AOF文件在操作方面的冲突以及同时执行大量磁盘写入操作的不良影响。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
author-avatar
haodan1006
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有