Elasticsearch 集群在QQ阅读评论服务的实践

- 8 mins

背景

目前评论数据存储用户和书籍两个维度的数据,共计8亿条记录左右,还在快速持续增长中;数据链路采用 DCache & Redis & MySQL 存储模式,DCache 存储了一份评论全量数据,Redis 存储评论数据各种维度检索的索引的各种数据结构,MySQL 集群采用分库分表[10*10]策略存储评论原子结构数据。随着评论业务线需求逐渐迭代和复杂化,评论数据的各种维度查询服务逐渐复杂化,Redis 存储的索引数据结构比较隐晦,越来越多,越来越复杂,不易维护;由于评论更新流程是3写,没有数据一致性校验阶段,导致存储侧各种数据不一致。所以,考虑接入Elasticsearch,代替Redis存储侧,简化 MySQL 存储侧各维度评论原子数据为一份;减少依赖链路长度,保证数据一致性。

内容

本文是本人 Elasticsearch 集群从部署,到管理与监控,到代理层 Server 和 Client 封装,到测试集群压测,到压测暴露问题的调优,到简单集群运维等,整个链路的初探。记录了整个流程中各阶段的具体操作,遇到问题的解决方案等具体细节。

1 集群部署

Elasticsearch 集群的部署,为了保证集群节点配置和插件的统一,可以采用官网的推荐的部署模块 Elasticsearch Puppet,也可以采用Docker部署的方式;当然,如果节点较少,也可以采用手动逐个节点部署的方式。

1.1 集群节点配置

以下是集群节点的配置,未提及的属性使用默认值,后期如果由于性能需求可以调整;如果个别属性不清楚请问 Google。

集群名称,默认是elasticsearch,不同的集群用名字来区分,es会通过ZenDiscovery服务自动发现在同一网段下的es,配置成相同集群名字的各个节点形成一个集群。如果在同一网段下有多个集群,就可以用这个属性来区分不同的集群。

    cluster.name: elasticsearch-jew

集群节点名称

    node.name: node-9200
    node.attr.rack: r1

Data & Log

    path.data: /path/to/data
    path.logs: /path/to/logs

Node Host

    network.host: 192.168.0.1

HTTP & TCP,设置对外服务的http端口 默认为9200;内部tcp端口 默认9300;不能相同,否则会冲突。

    http.port: 19200
    http.pipelining.max_events: 30000
    transport.tcp.port: 9302

cors 跨域支持

    http.cors.enabled: true
    http.cors.allow-origin: "*"

集群节点类型:master | data | client

    node.master: false
    node.data: true
    node.ingest: false

集群节点发现机制

    discovery.zen.ping.unicast.hosts: ["10.211.0.165:9300", "10.211.0.199:9300"]

防止脑裂 [total number of master-eligible nodes / 2 + 1]

    discovery.zen.minimum_master_nodes: 2

Elastic X-Pack Basic License Disable Security

    xpack.security.enabled: false

Fixed Err: unable to intall syscall filter, CONFIG_SECCOMP not compiled into kernel

    bootstrap.system_call_filter: false

Fixed Err: max virtual memory areas vm.maxmapcount [65530] is too low

    sudo sysctl -w vm.max_map_count=262144

1.2 集群健康、节点、索引、分片、统计

Elasticsearch 提供丰富的 cat APIs,以下会列出一些常用的,如果有不清楚或不能满足需求的,请问 Google。

Cluster Health

curl -XGET -u elastic:elastic 'http://localhost:9200/_cat/health?v&pretty'
curl -XGET -u elastic:elastic 'http://localhost:9200/_cluster/health?pretty'

集群索引清单:每个索引细节「状态、分片数、未分配分片数」

curl -XGET -u elastic:elastic 'http://localhost:9200/_cluster/health?level=indices&pretty'

集群索引清单:每个索引分片细节「状态、分片数、未分配分片数」

curl -XGET -u elastic:elastic 'http://localhost:9200/_cluster/health?level=shards&pretty'

Cluster Nodes

curl -XGET -u elastic:elastic 'http://localhost:9200/_cat/nodes?v&pretty'

单个节点监控统计:「索引、操作系统、进程、JVM、线程池、文件系统、网络、断路器」

curl -XGET -u elastic:elastic 'http://localhost:9200/_nodes/stats?pretty'

集群统计:「分片数、文档数、存储空间、缓存信息、内存作用率、插件内容、文件系统内容、JVM作用状况、系统CPU和OS信息、段信息」

curl -XGET -u elastic:elastic 'http://localhost:9200/_cluster/stats?human&pretty'

索引列表

curl -XGET -u elastic:elastic 'http://localhost:9200/_cat/indices?v&pretty'

索引统计

curl -XGET -u elastic:elastic 'http://localhost:9200/_all/_stats?pretty'
curl -XGET -u elastic:elastic 'http://localhost:9200/weibo,elastic/_stats?pretty'

每个Index所包含的Type,6.0版本开始,计划每个索引只能有一个Type

curl -XGET -u elastic:elastic 'http://localhost:9200/_mapping?pretty=true'

对索引级别进行完全控制:每个索引默认5个分片和1个副本,更改为1个分片;大拇指法则表明最佳的分片数量取决于节点数量

curl -XPUT -u elastic:elastic 'http://localhost:9200/twitter?pretty' -H 'Content-Type: application/json' -d'                                     
{
    "index" : {          
        "number_of_shards" : 1,        
        "number_of_replicas" : 1
    }                                              
}'

修改副本个数

curl -XPUT "http://localhost:9200/notes/_settings" -H 'Content-Type: application/json' -d'
{
    "number_of_replicas": 2
}'

索引分片状态

curl -XGET "http://localhost:9200/_cat/shards?v"

索引分片的 segment.count 统计

curl -XGET "http://localhost:9200/_cat/shards/notes?v&h=n,iic,sc"

恢复状态:集群出现波动时,查看数据迁移和恢复速度

curl -XGET "http://localhost:9200/_cat/recovery?v&active_only&h=i,s,shost,thost,fp,bp,tr,trp,trt"

查看线程池状态

curl -XGET "http://localhost:9200/_cat/thread_pool?v"

Elastic X-Pack Updating Your License

curl -XPUT -u elastic 'http://localhost:9200/_xpack/license' -H "Content-Type: application/json" -d @license.json

内存使用 & GC指标

集群统计 重点监控指标

1.3 IK 中文分词

关于IK中文分词具体部署细节,不在这里赘述,感兴趣的话,请问 Google。

1.4 小结

关于更多 Elasticsearch 内部实现、部署、运维等细节,请问 Google;包括但不限于如下:

2 集群管理与监控

目前 Elasticsearch 集群的监控和管理是通过如下2个开源工具和Kibana来进行的,官方提供的一些插件是收费的,关于更多管理和监控的细节,请问 Google。

2.1 ElasticHD

2.2 Elasticsearch-head

2.3 Kibana

Kibana 部署并连接ES集群,最好连接一个非主节点和非数据节点,一个ES路由节点,能够构建搜索负载均衡

3 代理层 Server & Client

Elasticsearch集群作为基础服务组件,一定要做好与业务隔离性,做好接口收敛,屏蔽掉业务无关性,封装一些通用的ES接入接口;官方提供了各种语言的Client,可以根据需求自行封装服务,然后与自家的中间件层集成,这样就可以接入自家平台的发布部署、监控、CI相融合。
我这里封装了 Tencent TAF Proxy 接入集团 Tencent TAF 服务治理和链路监控,同时封装Client给业务接入方使用,可以做到细粒度到接口层面的ES接入控制,统一版本迭代。
关于代理层 Server 和 Client 的更多细节就不再这里赘述。

4 性能压测

本次压测使用 Gatling 服务端性能压测框架,优秀的 DSL 设计,关于更多细节,请问 Google。

4.1 压测基础设施

压测的吞吐量大小主要依赖于搭建的基础设施,我先罗列下目前压测的基础设施:

4.2 压测结果汇总

目前压测比较稳定的报告汇总(Benchmark Web APIs 和 Proxy 单节点部署):

   Gatling      R/W    Scene           TPS                 Benchmark          Proxy        Async
10.62.21.158     W       1      5500/120/140/5300      10.188.1.23:10002    10.188.1.23   Chained

10.62.21.158     R       1      12000/120/120/11600    10.188.1.23:10002    10.188.1.23   Chained

10.62.21.158     F       6      350/300/320/2350       10.188.1.23:10002    10.188.1.23   Chained
10.62.21.158     Q       6      350/180/190/2300       10.188.1.23:10002    10.188.1.23   Parallel

10.62.21.158    F/W      8      300/300/315/2450       10.188.1.23:10002    10.188.1.23   Chained
10.62.21.158    Q/W      8      300/180/185/2400       10.188.1.23:10002    10.188.1.23   Parallel

ES Node         F/W      8      450/180/185/3550                                          Chained
ES Node         Q/W      8      450/180/185/3500                                          Parallel

针对上述压测报告汇总中的名词解释:

4.3 压测报告分析 单条查询

4.3.1 压测结果

   Gatling      R/W    Scene           TPS                 Benchmark          Proxy        Async
10.62.21.158     R       1      12000/120/120/11600    10.188.1.23:10002    10.188.1.23   Chained

4.3.2 压测报告

压测报告信息汇总


虚拟用户注入时间分布


请求响应时间分布


请求和响应吞吐量


4.4 压测报告分析 单条写入

4.4.1 压测结果

   Gatling      R/W    Scene           TPS                 Benchmark          Proxy        Async
10.62.21.158     W       1      5500/120/140/5300      10.188.1.23:10002    10.188.1.23   Chained

4.4.2 压测报告

压测报告信息汇总


虚拟用户注入时间分布


请求响应时间分布


请求和响应吞吐量


4.5 压测报告分析 Elasticsearch 集群单节点多场景混合

4.5.1 压测结果

   Gatling      R/W    Scene           TPS                 Benchmark          Proxy        Async
ES Node         F/W      8      450/180/185/3550                                          Chained
ES Node         Q/W      8      450/180/185/3500                                          Parallel

4.5.2 压测报告

压测报告信息汇总


虚拟用户注入时间分布


请求响应时间分布


请求和响应吞吐量


4.6 压测报告分析 读写全索引搜索多场景混合

4.6.1 压测结果

   Gatling      R/W    Scene           TPS                 Benchmark          Proxy        Async
10.62.21.158    F/W      8      300/300/315/2450       10.188.1.23:10002    10.188.1.23   Chained
10.62.21.158    Q/W      8      300/180/185/2400       10.188.1.23:10002    10.188.1.23   Parallel

4.6.2 压测报告

压测报告信息汇总


虚拟用户注入时间分布


请求响应时间分布


请求和响应吞吐量


4.7 压测问题汇总及解决方案

01.Elastic X-Pack License Expired,集群读写正常,健康检查、索引管理、集群监控和统计 功能无法使用 ?

fixed:重新申请 Free Basic License

02.Basic License Disable Security ?

fixed:配置 xpack.security.enabled: false

03.部署测试ES集群 5个节点 集群间无法通信 ?

调整配置文件;跟运维@张京 沟通服务器外网和端口开放问题

04.Fixed err: unable to intall syscall filter, CONFIG_SECCOMP not compiled into kernel

bootstrap.system_call_filter: false

05.Fixed err: max virtual memory areas vm.maxmapcount [65530] is too low

sudo sysctl -w vm.max_map_count=262144

06.多播模式:配置不配置 network.host & transport.host 节点之间不能互相发现

07.单播模式:必须配置 network.host,hosts 列表必须配置端口或端口范围

08.更新 License,从trial到basic,Elastic X-Pack Updating Your License

curl -XPUT -u elastic 'http://localhost:9200/_xpack/license’ -H "Content-Type: application/json" -d @license.json

09.Elastic X-Pack Basic License Disable Security

xpack.security.enabled: false

10.集群控制台ElasticHD配置域名[*.**.qq.com]连接后,集群可以连接,Rest API报错,502: Bad Gateway ?

fixed: nginx层反向代理的问题,域名连接加80端口[*.**.qq.com:80]

11.并发量上来 restClient close 问题

fixed bug: httpClient async request timeout「设置0」

12.并发量上来大量「502 504」,分析发现是域名解析超时,临时干掉nginx域名解析反向代理层

13.fixed bug: Cannot assign requested address「无可用端口,短链接关闭后,链接处于 TIME_WAIT 状态,本地端口仍被占用中」

    # 端口复用内核参数设置
    net.ipv4.tcp_tw_reuse=1
    net.ipv4.tcp_tw_recycle=1
    net.ipv4.tcp_timestamps=1
    net.ipv4.tcp_max_tw_buckets=50000
    net.ipv4.ip_local_port_range=1024 65000
    net.ipv4.tcp_keepalive_time=6000

14.开启端口复用后,请求一直连接超时;并且一直触发GC「Minor GC,不是 Full GC」,新生代中没有合适区域存放分配的数据结构

fixed: JVM调大堆内存,调高新生代和老生代比例

15.调整 ArslanElasticBenchmark & ArslanElasticServer 线程数、队列长度、超时时间、Gatling配置 多轮压测

16.master被压挂了,索引分片丢失,30mins恢复索引分片同步

17.ES单节点堆内存不超过32G,为了充分利用服务器[64G内存]资源,节点由3个扩容到5个

18.ES集群节点从3个扩容到5个,集群分片动态迁移达到均衡状态,每个节点2个分片

19.副本从1调整到2,提升搜索性能;压测脚本重构,从链式异步改成并行异步;压测脚本区分场景

20.Vert.x web 重构 Tencent TAF 3.0 HTTP 压测基准 Web APIs ArslanElasticBenchmarkV2

21.跟@帆总一起排查 “Tencent TAF主控连接关闭问题”

bug: 同时创建多个communicator时,并发高时会出现窜包问题,即连接和回包的对应关系在特定场景下出现匹配错乱; 深层次原因,初步认为与连接异步创建和回包超时淘汰有关,等后续 base-taf 版本迭代fix

参考资料

comments powered by Disqus
rss github weibo twitter instagram pinterest facebook linkedin stackoverflow reddit quora mail