ELK的心脏,ElasticSearch学习方法论

栏目: 服务器 · Apache · 发布时间: 7年前

内容简介:从初次了解elastic产品到正式投入使用,拖拖拉拉的也有小半年了,刚接触的时候看到一些帖子都是安装教程,后来看到一些都是深入教程,此篇文章较居中一点,总结了我在踩的一些坑和记录一些周边插件的使用方式、方法,便于自己后续回顾,也希望能给新用户一些引导,少走一些弯路;核心其实是想表达一下对rockybean和KennyW的爱,这期间非常感谢两位的协助,在非工作日深夜排查问题多次,正文多处采用二位给予的讲解,万分感谢。通过上述配置PUT到 _template/ur_name下在分片上的定义已经成功,但是像ag

写在前面

从初次了解elastic产品到正式投入使用,拖拖拉拉的也有小半年了,刚接触的时候看到一些帖子都是安装教程,后来看到一些都是深入教程,此篇文章较居中一点,总结了我在踩的一些坑和记录一些周边插件的使用方式、方法,便于自己后续回顾,也希望能给新用户一些引导,少走一些弯路;核心其实是想表达一下对rockybean和KennyW的爱,这期间非常感谢两位的协助,在非工作日深夜排查问题多次,正文多处采用二位给予的讲解,万分感谢。

ElasticSearch简介

  • 基于Lucene构建的分布式, RESTful 搜索和分析引擎;

  • 实时搜索、分析,稳定,可靠,快速;

  • JAVA编写,开源,使用JSON开源通过HTTP来索引数据;

项目介绍

  • 历史:

    由前同事工作交接,原有一套ES1.7集群,但是经常jvm跑满导致集群不可用,没有ES调优经验,甚至没有使用经验,从零了解ES,过度版本ES5.3~5.6;

  • 背景:

    数据源主要是Nginx访问日志,由于Nginx是集群,相应的日志分布落在每台机器上,当对整体日志做一些数据分析、故障排查等,因数据分散且量很大,通过脚本已经不能做分析处理了,为了对Nginx日志做全文搜索、分析,实时监控等,所以踏上ELK之路;

  • 数据量:

    每天6-7T,Docs在100亿左右

架构图

ELK的心脏,ElasticSearch学习方法论

第一部分:日志收集(Nginx + Rsyslog)

  • 采用Nginx内置的syslog模块,每台机器启用本地的rsyslog,通过UDP方式传输本地的514端口(Rsyslog),然后Rsyslog在将数据转发至Kafka;

  • 选型比较:日志收集有很多种方式,如flume、filebeat、 lua 脚本等,但是这些组件都需要额外安装客户端,而rsyslog在 linux 都集成了。简单对比过Rsyslog和其他区别,首先在Nginx中的syslog对于一个更改相对灵活,JSON日志与落地日志毫无干系(目前是两份格式:人肉读取的本地日志格式,机器读取JSON网络传输格式),日志输出直接通过网络传输走(网络消耗很低)不受本地磁盘影响,对不同的server_name或location等可以灵活的修改,总之控制权在Nginx手里,Nginx的维护同学就可以自定义源数据格式,管理成本相对较低;

  • Rsyslog配置(双打Kafka)

    现有的版本是0.8,而刚开始测试的用logstash5.x需要kafka0.10(最终hangout替换logstash),所以新搭建了一组新的集群,Rsyslog向两个Kafka集群分别写数据,配置如下

    Module (load="imudp") Module (load="omkafka") Input (type="imudp" port="514") Module (load="mmsequence") $MaxMessageSize 4k local5.none /var/log/messages local5.none @log.domain.com:514 set $!newmsg = replace($msg,'\\x','\\u00') template(name="kafka_topic" type="string" string="%programname%") template(name="kafka_msg" type="string" string="%!newmsg%") if ($syslogfacility-text == 'local5' and $syslogseverity-text == 'info') then{ action(type="omkafka" topic="kafka_topic" partitions.auto="on" dynatopic="on" dynatopic.cachesize="1000" confParam=["compression.codec=snappy"] #kafka broker addr broker=["10.10.10.1:9092","10.10.10.2:9092",] template="kafka_msg" errorfile="/var/log/omkafka/log_kafka_failures.log") action(type="omkafka" topic="kafka_topic" partitions.auto="on" dynatopic="on" dynatopic.cachesize="1000" confParam=["compression.codec=snappy"] #kafka broker addr broker=["20.20.20.1:9092","20.20.20.2:9092",] template="kafka_msg" errorfile="/var/log/omkafka/log_kafka_failures.log") stop } 复制代码
  • 配置Nginx JSON格式日志

    log_format json_format  '{"@timestamp":"$time_iso8601",'         '"cookie_id":"$cookie_id",' #内部cookie_id         '"client_ip":"$remote_addr",'         '"remote_user":"$remote_user",'         '"request_method":"$request_method",'         '"domain":"$host",'         '"user_agent":"$http_user_agent",'         '"xff":"$http_x_forwarded_for",'         '"upstream_addr":"$upstream_addr",'         '"upstream_response_time":"$upstream_response_time",'         '"request_time":"$request_time",'         '"size":"$body_bytes_sent",'         '"idc_tag":"tjtx",'         '"cluster":"$host_pass",'         '"status":"$status",'         '"upstream_status":"$upstream_status",'         '"host":"$hostname",'         '"via":"$http_via",'         '"protocol":"$scheme",'         '"request_uri":"$request_uri",'         '"http_referer":"$http_referer"}';复制代码
  • Nginx内置 syslog模块 配置,并且引用刚刚定义的json日志格式

    access_log syslog:local5:info:127.0.0.1:514:nginx_aggregation_log json_format; #nginx_aggregation_log   这是自定义的Topic复制代码

    NginxSyslog模块介绍

    注:

    1) UDP传输虽快,但是以太网(Ethernet)数据帧的长度必须在46-1500字节之间,UDP不能像TCP重组数据包,去除IP和UDP的数据包,最终可使用只剩1472字节。如果传输大于这个长度的消息,并不会想UDP本身一样直接丢弃,只是会损坏源数据格式,截断超过限制字节以外的数据;

    2) 对于Nginx日志来说,只要不保留POST数据,基本一条消息不会超过限制字节,我在NginxSyslog介绍中没看到支持TCP,用lua脚本实现的TCP方式传输,但是看了很多帖子都不建议在Nginx中用TCP日志传输。就是因为TCP传输可靠,但像网络抖动、传输异常,可能会不停的重试多次或等待,直接影响这条请求,也直接影响到了用户;

    3) 消息超过了UDP传输限制怎么办,我这目前是保留一条消息的重要字段,如上述的json_format的格式,将 request_uri、http_referer等可能会较大的字段放到最后,如果真的发现消息不完整,直接丢弃http_referer,取request_uri问号前的内容;(在logstash或hangout中filters实现,具体配置详见下文Hangout-filters)

第二部分-存储中间件(Kafka)

  • Kafka性能很强,顺序写入磁盘,高吞吐量的分布式发布订阅消息系统

  • Kafka一直不是瓶颈,也没太多深入优化,Topic数据保留了12小时,副本为1

  • 针对不同的Topic,对Partition的数量有稍微改变,目前是5台服务器,之前简单测过增加Partition的性能,从8、16、32、64增加来看,明显情况就是Partition增加,CPU使用也会随之增加,因为kafka本身不是瓶颈,其他明显问题也未遇到;

  • 目前这边最大的Topic是一天近5T数据,64Partition没有任何问题,部分小的Topic都是16Partitio,Kafka整个集群的CPU空闲都在80%以上,内存、IO均无压力,后续也考虑缩减机器。这边的kafka团队有个建议值,供大家参考:【每天数据规模小于50G选择4分区、50G且小于100G选择8分区、大于100G且小于500G选择16分区、大于500G,选择24分区】

  • Kafka监控插件: kafka-monitorkafka-manager

    注:

    目前我们这kakfa集群是kafka_2.10-0.8.1.1版本,但是logstash5.x对kafka有版本要求>0.10版本。后来采用hangout,更换了几个jar包解决了此问题

第三部分-数据搬运工(Hangout)

  • 模仿 logstash 做的一个应用,功能没有logstash多,但是基本使用都有了,java编写,性能可以翻好几倍,用到的功能就是从kafka订阅消息,做一些简单的过滤,然后写入ES;目前hangout部署到2台服务器上,每个进程开8G内存,CPU在60-70左右;

    inputs:    - Kafka:     topic:          nginx_aggregation_log: 32     codec:          json     consumer_settings:         group.id: es-nginx_aggregation_log         zookeeper.connect: "10.10.10.1:2181,10.10.10.2:2181"         auto.commit.interval.ms: "20000"         socket.receive.buffer.bytes: "1048576"         fetch.message.max.bytes: "1048576"         num.consumer.fetchers: "1" filters:    - Filters:    if:         - '<#if message??>true</#if>'          #如果不是完整的JSON,会出现message,则走此逻辑    filters:        - Grok:            match:              - '(?<msg>{"@timestamp":.*"request_uri":([^\?]+)\?)'              #正则匹配@timestamp开始到request_uri后边的第一个?截止        - Gsub:            fields:                msg: ['$','"}']                #补全符号,完整新的JSON格式        - Json:            field: msg            remove_fields: ['message']             #干掉错误的数据 - Convert:     fields:         request_time:             to: float             remove_if_fail: true         upstream_response_time:             to: float             remove_if_fail: true         size:             to: integer             remove_if_fail: true - GeoIP2:     source: client_ip     database: '/opt/soft/hangout/etc/other/GeoLite2-City.mmdb'     - Json:          field: geoip - Remove:         fields:             - msg - Add:        fields:           request_url: '<#assign a=request_uri?split("?")>${a[0]}'           #request_uri这个term的cardinality很高,所以?前用于聚合,原有的用于搜索        if:          - '<#if request_uri??>true</#if>' outputs: - Elasticsearch: cluster: es-nginx timezone: "Asia/Shanghai" hosts: "10.10.10.1:9300,10.10.10.2:9300" index: 'hangout-nginx_aggregation_log-%{+YYYY.MM.dd}' 复制代码
  • Hangout进程管理工具( supervisord

    主要是守护hangout进程,在web界面对hangout进行启、停、重启等操作

  • topic: nginx_aggregation_log: 32,无论是logstash还是hangout都有这个概念,这个32代表需要建立多少子线程去kafka读取数据,数量最好与Partition相等,如果少于Partition,会一个线程同时去2个Partition读取消息,若大于Partition则会有不工作的进程

第四部分-Elasticsearch(后面简称ES)

  • 硬件环境

    CPU:32C,内存:128G ,硬盘:STAT 6T * 12,网卡:万兆 复制代码
  • 软件环境:

    【系统】: Centos7 内核3.10 【JDK】: 1.8.0_66/31G (据说此版本JDK有BUG,请安装最新JDK) 【系统参数修改1】: vm.swappiness=1 [降低对硬盘的缓存] 【系统参数修改2】: vm.max_map_count=262144 [Elasticsearch针对各种文件使用NioFS和MMapFS的混合。以便有足够的虚拟内存可用于mmapped文件] 复制代码
  • ES配置文件

    cluster.name: es-nginx node.name: 10.10.10.1  #为后期冷热数据使用 node.attr.rack_id: hdd  path.data: /data  path.logs: /opt/logs/elasticsearch/ network.host: 0.0.0.0  http.port: 9200 #设置新节点被启动时能够发现的主节点列表 discovery.zen.ping.unicast.hosts: ["10.10.10.1","10.10.10.2","10.10.10.3"] #防止脑裂(n/2+1) discovery.zen.minimum_master_nodes: 2 node.master: true node.data: false复制代码
  • ES跳入的第一坑:node.master与node.data同时服务

    刚刚开始测试ES的第一个版本是ES5.3,先搞了3台机器,每个机器一个节点,配置是master和data共同提供服务,高可用架构集群搭建完成,但是写入性能特别差,cpu使用在20-30%,少量io.wait,下图是当时3w左右的性能图当时觉得既然ES硬件很空闲一定是logstash出问题了,查看logstash确实有很严重的Full GC,开始从2台服务器扩至4台服务器,后来发现无果,期间各种调整ES的shard的数量都没效果,又怀疑kafka性能,从2、4、6、8...64分区依旧无果。当时这个坑可爬了一段时间,后来在Google的游荡中无意中看到帖子说,不要将master和data都启用,然后我照着做了改变,master单点,data两台,问题搞定,效果图找不到了,起码翻倍是有的;

    [Master除了网卡,其他没什么消耗] 复制代码
  • template

    因shard数量、字段类型、其他设置等都是都是在创建时生成,所以要提前创建好相应的模板,便于规范管理和引用,下面针对shard和 aliases 做的一些设置,如下:

    {       "template": "agg-nginx-*",       "aliases": {           "agg-nginx": {}         },       "settings": {         "number_of_shards": 4,         "number_of_replicas": 1,         "index.routing.allocation.include.rack_id": "ssd"       }复制代码

通过上述配置PUT到 _template/ur_name下在分片上的定义已经成功,但是像agg-nginx-

  • mapping

    ES的mapping非常类似于静态语言中的数据类型:声明一个变量为int类型的变量, 以后这个变量都只能存储int类型的数据。同样的, 一个number类型的mapping字段只能存储number类型的数据。同语言的数据类型相比,mapping还有一些其他的含义,mapping不仅告诉ES一个field中是什么类型的值, 它还告诉ES如何索引数据以及数据是否能被搜索到

    下列是一个删减版的mapping复制代码
    "mappings": {     "ngx_log": {        "_all": {         "enabled": false       },       "properties": {         "@timestamp": {           "type": "date"         },         "client_ip": {           "type": "ip"         },         "domain": {           "type": "keyword"         },         "geoip": {           "properties": {             "city_name": {               "type": "keyword"             },             "country_name": {               "type": "keyword"             },             "latitude": {               "type": "float"             },             "location": {               "type": "geo_point"             },             "longitude": {               "type": "float"             },           }         },         "request_time": {           "type": "float"         },         "request_url": {           "type": "keyword"         },         "status": {           "type": "keyword"   ype": "keyword"         },                }     }   }复制代码
  1. _all 字段

    该_all字段是一个特殊的catch-all字段,它将所有其他字段的值连接成一个大字符串,使用空格作为分隔符,然后对其进行分析和索引,但不存储。也就是说它能被查询,但不能被取回显示。因为Nginx每个Key对应的value都是提前定义好的,所以不用全文查询,不需要开启_all字段,另外也节省了一半的存储空间

  2. 默认的text类型

    上边这英文有点多,其实简单理解就是不分词,你就最好别用text了,而且Text类型也会相应的多占用空间,依照上述,数据主要是日志分析,每条数据的格式已经很明确,主要用于日志分析,所以不需要分词。像一些所有引擎的业务更适合需要分词;

  3. 比如说像这个字段,get_ip中location这个字段类型默认text,但是如果不指定geo_point类型,根本无法使用地图功能,类型的指定是很重要的

  4. 向request_time这样的数据类型需要做计算,比如说平均值、和、大于、小于等等的,默认的text也能使用,但是效率远远小于float类型

  5. 字段类型有很多种,什么IP啊、DATE啊等等,根据相应的需要去官网查看详解吧, mapping-types介绍

  • shard & replicas

    [摘取部分苏若年博客内容]

    1)分片算法:

    shard = hash(routing) % number_of_primary_shards

    routing值是一个任意字符串,它默认是_id但也可以自定义,这个routing字符串通过哈希函数生成一个数字,然后除以主切片的数量得到一个余数(remainder),余数的范围永远是0到number_of_primary_shards - 1,这个数字就是特定文档所在的分片。

    这也解释了为什么主切片的数量只能在创建索引时定义且不能修改:如果主切片的数量在未来改变了,所有先前的路由值就失效了,文档也就永远找不到了。

    所有的文档API(get、index、delete、bulk、update、mget)都接收一个routing参数,它用来自定义文档到分片的映射。自定义路由值可以确保所有相关文档.比如用户的文章,按照用户账号路由,就可以实现属于同一用户的文档被保存在同一分片上。

    2)分片与副本交互:

    新建、索引和删除请求都是写(write)操作,它们必须在主分片上成功完成才能复制到相关的复制分片上,下面我们罗列在主分片和复制分片上成功新建、索引或删除一个文档必要的顺序步骤:

    1、客户端给Node 1发送新建、索引或删除请求。

    2、节点使用文档的_id确定文档属于分片0。它转发请求到Node 3,分片0位于这个节点上。

    3、Node 3在主分片上执行请求,如果成功,它转发请求到相应的位于Node 1和Node 2的复制节点上。当所有的复制节点报告成功,Node 3报告成功到请求的节点,请求的节点再报告给客户端。

    客户端接收到成功响应的时候,文档的修改已经被应用于主分片和所有的复制分片。你的修改生效了。

    一个索引要分多少片?什么时候该扩容?

    取决于硬件和你对响应速度的要求,一般来说一个shard的数据量控制在1、2千万的级别,速度都还好,过亿会比较缓慢。 但是任何事物都有两面,shard划分比较小,必然数量就比较多。 在用户做1、2天数据搜索的时候可能还好,如果搜更长时间的数据,一次搜索需要并行搜索的shard就比较多。如果节点数量有限,就会比较吃力,需要扩充更多的节点

  • routing

    据说是优化之王道,经常拿城市举的例子,比如说我想看下网站的北京pv是多少,如果按照默认hash逻辑,一定要全shard扫描,然后聚合结果,但是如果提前设置好routing,比如说指定城市字段做hash计算,routing值一样的放到特定几个分片,这样查起来也不需要全shard扫了;这样弊端就是会造成shard大小不均,所以routing优化需要花一些功夫来观察、测试;目前kibana还不支持routing查询,所以目前在kibana上还没有使用routing,这是优化的重点所以先记录下来。后续我的想法是,像nginx日志的域名的字段都是英文字母,针对首字母做下routing,当想看某一个域名时不在全盘扫,查询优化会有明显效果,后续有结果在与大家分享;

    另外hangout开始对routing的支持,后来在GitHub提了一个小issue,很快就加上了,点个赞;

第五部分-Kibana图形展示

Kibana 是一个开源的分析与可视化平台,设计出来用于和Elasticsearch一起使用的。你可以用kibana搜索、查看、交互存放在Elasticsearch索引里的数据,使用各种不同的图表、表格、地图等kibana能够很轻易地展示高级数据分析与可视化。

先介绍下几块功能:

  • X-pack 可以免费使用部分功能,最强就是monitoring功能了,基本重要指标都收集了

  • Dev_tools的代码补全神器,类似于IDE;还有强劲的可视化Search Profiler,便于直接定位问题点

  • 其他就是常用的Discover、Visualize、Dashboard、Timelion搜索和绘图功能了,没有找到合适的帖子,直接吧迷妹儿的帖子放过来吧,主要介绍了 如何优雅的使用kibana的搜索框

  • 还有就是Elastic官方提供了一个 Demo ,便于大家做图形展示的时候参考和借鉴

(╯﹏╰)吐槽一下,用SF写到现在,Chrome都快没法用了,打完字一会才显示出来

  • 直接上几张最终成果图吧

  • [QPS展示]

  • [QPS环比]

  • [异常状态码趋势]

    ELK的心脏,ElasticSearch学习方法论
  • [慢请求QPS]

    ELK的心脏,ElasticSearch学习方法论
  • [状态码比例]

    ELK的心脏,ElasticSearch学习方法论
  • [Domin与URL TOP]

    ELK的心脏,ElasticSearch学习方法论
  • 再来一张深夜[热图],北京和上海的孩子总是不碎觉

    ELK的心脏,ElasticSearch学习方法论
  • 上图中环比图是Timelion完成的,其他都是Visualize的功能

    Timelion语法:

    .es(index=index1,timefield=@timestamp).label('Today').title(QPS).color(#1E90FF),  .es(offset=-24h,index=index2,timefield=@timestamp).label('Yesterday').lines(fill=1,width=0.5).color(gray)复制代码
  • kibana认证问题

    由于x-pack试用版将认证功能被阉割掉了,直接暴露内容太风险,所以利用Nignx插件auth_basic的功能,做了一个简单验证模块

最后调优

核心问题:查询慢、查询15Min数据都超时

  • 数据量:

    每天数据在6-7T,Docs在100亿左右,其中一个大的索引在4-5T

  • ES升级

    版本升级会带来一些新特性,以及一些bug修复,当然也会引发新问题,我就踩到了新版本的坑;

    ES5.x升级到5.5是滚动升级,相对升级步骤简单,但是由于数据太大,动辄几十T,一台台完成升级,却是一个漫长的过程。另外,1.x升级据说很痛苦,有兴趣的去看看,连接放在这里 reindex-upgrade

    简述下5.x升级的过程

    1)关掉分片自动分配:"cluster.routing.allocation.enable": "none"

    2)强制刷新,尽可能将缓存中的数据,写入磁盘: _flush/synced

    3)停止一个节点,开始升级及升级插件,然后启动

    4)打开分片自动分配:"cluster.routing.allocation.enable" :"all"

    5)等待集群恢复至绿色,继续下一台

  • 扩容

    扩容很简单,没什么可说的,除了配置文件中node.name不一样,其他都一样;

    最初扩容只是将data节点从3台扩至20台,写入没问题,1-2k的数据,单机性能写入在30-40k;

  • mapping字段优化:

    主要像上述的mapping介绍,做类型优化,不分词的keyword,数学计算的改成整型or浮点等

    status这个字段的类型,value一般都是200、301、302、404、502,最多估计也就几百个,像这样的字段就不适合做long,long类型的索引是为范围查找优化的,用的是二叉树这样的索引,适合值范围比较大的字段,比如body_size,可能最大值和最小值相差很多,而用keyword索引是倒排,只用存放一个所有status的词典,所以keyword更适合

  • shard数量调整:

    开始主分片数量是每台机器1个,副本1(20shard x 1replicas),每个shard已经达到将近200G,看这个量级已经超过官方建议值30~50G之间(具体要根据实际情况测试为准)。于是开始将数量翻倍40shard * 1replicas,调整后查询并没有明显改善,对写入没有什么改变,继续double,依旧没效而且分片越多,写入的时候消耗的CPU就越高

    如果过度分配shard,就增大了Lucene在合并分片查询结果时的复杂度,从而增大了耗时,在新建索引时,更是一笔大的开销。

    一般来说,刚开始的时候尽量少分片为佳, 只有到一个分片上数据太多,单次查询太慢在考虑加分片。

    加分片也有负面作用,提高了并发量,随之开销就会越大,更多的shard一般也伴随更多的segment文件。如果说节点数量没变,每个节点上会有更多的小文件,搜索的时候并发量是高了,前提是在磁盘io和cpu都还能应付的过来的时候,速度才会快

  • 拆分索引

    更改shard已经得不到显著效果,于是从拆索引下手。数据都是Nginx日志,从源头拆分没什么好的方法,于是从hangout这层开始做处理,很简单就是将域名的第一个字母取出来,写入相应的索引时候带过去,例如:nginx-log-{首字母},这样一拆,一下创建26个索引(shard20 * 1replicas),CPU立马load 30+,负载直接上来,然后ES数据还跟不上,拒绝了很多内容,如下图,最终还是无果而告终此方案

    ELK的心脏,ElasticSearch学习方法论

    上述的索引拆分是比较傻瓜式,首先已知的问题就是可能A开头的域名很大,其他很小就是很不均匀

  • Pcle-SSD测试

    经过上面的折腾,已经没有什么突破点,于是借用了8台SSD的机器,修改ES配置node.attr.rack_id: ssd,将数据写入SSD,全程io无压力,写入一个一天4-5T的索引,CPU在50%左右,但是查询依旧不给力,经过无数shard调整依旧不给力,IO一直没空闲,最终结论就是没有将ssd的性能发挥出来,还是未解决根本问题

  • kibana BUG

    之前没有ES相关经验,能想到的办法、关注点都没有什么在突破的地方了,在束手无策的时候,又非常有幸认识了KennyW,再次感谢KennyW的支持;问题根本原因是kibana5.4-5.5这两个版本在查询问题,为了节省空间,我关掉了_all这个字段,如果搜索框不输入内容的时候,则会补充*查询所有字段,生成的bool条件就非常多,引发kibana的缺陷,引用:

    ELK的心脏,ElasticSearch学习方法论 当时的版本KennyW给的知道是临时修复方法如下: ELK的心脏,ElasticSearch学习方法论

    详细问题请看这里 ES 5.4+ 引起的Kibana性能问题 ,Kibana5.5.2后已经修复此问题,所以最终版本还是升级到了5.6,也是目前的最新版

  • 回归HDD

    经过SSD的折腾,查到了kibanaBug问题,其实SSD并未发现其他的性能亮点,经过与KennyW的交流,他们自己有做过在SSD和多块HDD的盘对比,写入量并无明显提升,所以在磁盘并不是真正的瓶颈,查询方面SSD明显提高。但是SSD的高额付出换来那么几秒钟的意义不大。相对,对一些公司的搜索业务,数据量级小,还有像一些监控业务,要求实时性非常高,对SSD是很好的选择,速度快,容量不需要太多,也比较经济实惠

    [KennyW经验指导]

    当做复杂计算,bucket很多的时候主要消耗的是CPU和内存,磁盘并不是瓶颈,hdd和ssd在我们实际用下来,感觉在大数据场景分别不大,ssd优势在大量的随机磁盘io,ES本身做了很多优化,让数据变成顺序的磁盘访问,而且搜索过的数据块,ES都能利用文件系统缓存加速,所以即使使用hdd,可能第一次搜索磁盘访问会带来额外的几秒耗时,但多次执行同一个搜索时,后面几次几乎没什么磁盘io开销,速度会有明显提升

  • RAID0的重要性

    当所有的集群全部更改回hdd的集群时候,发现一个之前没太关注的指标,每块盘的利用率。刚开始解决的时候我们的机器都是裸盘直接挂上,path.data:data1,data2,data...这样挂载,但是在5.x版本发现这样磁盘问题(CMD:iostat -x 1) ELK的心脏,ElasticSearch学习方法论

    这样看来很奇怪,为什么这块盘这么忙,多观察一会发现,一会又发现其他的盘又很忙,然后df查看磁盘使用率,扎心了

    ELK的心脏,ElasticSearch学习方法论

    挂了这么多盘,真实写入连一半的盘都不到,既然这样,没得说的了,直接上raid0吧

  • 收尾

    做到目前这些调整,现在一天小于1T的索引任何查询都没有问题,查询在10s左右返回所有数据(上图kibana展示),但是那个一天4-5T的索引还是有问题,一查询IO就跑满,到30s直接超时了,先说下IO跑满的问题吧,问题是request_uri台过于分散,聚合出现问题如图:15分钟就出现了2000多万不同值,如果长时间计算,不可想象的恐怖

    ELK的心脏,ElasticSearch学习方法论

    【KennyW指导】

    request_uri 会产生大量的磁盘IO。 ES做terms聚合的时候,为了节省内存,不会将所有term的内容直接读出来做bucket,因为有些term的内容可能很长,会比较耗费内存。 所以他会借助一种叫做oridinals的数据结构, 这种数据结构类似这样

    1 abc

    2 efg

    3 hfa

    .............

    一个该字段所有不同值的顺序列表。 做分桶聚合的时候,只需要拿这个顺序数字做key就可以了,等聚合出结果,再通过这个key查ordinals表,得到实际的key值填充结果。 但是这个ordinals是随着segment 文件生成的,每个segment文件的ordinals顺序可能不一样。 因此在聚合的时候,需要一个全局的global ordinals。 这个数据结构是在聚合的时候,实时生成后缓存在内存里的。 如果某个字段的不同值非常多,计算价值非常的昂贵,那么这个构造过程就非常的缓慢,除了大量的磁盘IO消耗,还会有很大的内存消耗。

    下图是关掉这个有问题的visualize前后对比图,虽然不快,但是latency降了很多 ELK的心脏,ElasticSearch学习方法论

    后来对uri的?后边的参数全部丢弃,像这样的问题只能减少然后做聚合使用,原有数据做搜索使用,但是由于数据太大,做复杂计算还是会超时30s,这种情况只能是降低team的cardinality,或者加分片、加机器或者拆索引了,所以对kibana的超时时间做了一点调整,还有一些周边小的修改如下

    1)kibana默认的30s超时改成2min,kibana.yml中修改

    elasticsearch.requestTimeout: 120000

    2)kibana默认地图使用高德,kibana.yml中新增

    tilemap.url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}'

    3)结合 cerebro 插件,高效管理索引

后续

说到这里顺便给大家推荐一个交流学习群:650385180,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,相信对于已经工作和遇到技术瓶颈的码友,在这个群里一定有你需要的内容。

到这里基本的一期项目算是结束,虽然部分查询并没有迅速返回,但是基本数据都可以展示,后续会关注几个点继续深入优化和调整,有结果在与大家分享

  • routing优化查询

  • curator管理过期索引

  • 比较大index索引做拆分

  • 增加client节点,减少集群影响

  • 冷热数据分离(node.attr.rack)、定期对冷数据force_merge,优化查询速度

总结

首先在这里还是先要感谢rockybean和KennyW的大力支持。

对自己的总结就是,对ES经验太少,踩了很多不必要的坑,另外就是没有好好统一阅读下官网文档,这样极其影响效率与进度,好多时候也会束手无策,不知从何下手。

第一次写技术帖,而且时间稍紧,有哪些地方写的不好或敏感烦请指出,我会及时更正。希望这篇文章,能给予像我这样的小白用户少踩一点坑,多一点爱。

文章有点长,大家觉得作者总结的还可以,可以关注一下作者的公众号《Java技术zhai》,公众号聊的不仅仅是 Java 技术知识,还有面试等干货,后期还有大量架构干货。大家一起关注吧!关注技术zhai,你会了解的更多..............


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Pro Git

Pro Git

Scott Chacon / Apress / 2009-8-27 / USD 34.99

Git is the version control system developed by Linus Torvalds for Linux kernel development. It took the open source world by storm since its inception in 2005, and is used by small development shops a......一起来看看 《Pro Git》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器