ElasticSearch之跨集群实践
背景:使用多个ES集群来存储用户日志,然后提供给运营分析。日志采集架构大概为nginx-->openresty-->kafka/aws kinesis-->es。但是国内使用es的公司日志规模都会比较大,单集群很难承载所有日志。如果使用单集群,考虑到es是单线程,稳定性会随着集群规模不断变大不断下降。考虑到一般情况下日志业务场景差距很大,因此将日志根据不同业务场景存储在不同集群中,但是需要对外提供统一的API,就像nginx的反向代理。调用者感知不到有多个集群,也感知不到集群内部的变化。
es官方有两种解决方案:tribenode和cross cluster search(ccs),下面分别介绍。
tribenode核心原理: merge 每个集群的 ClusterState 对象成一个公共的 ClusterState 对象,ClusterState 包含了索引、shard 和节点数据分布表。而 Elasticsearch 的工作逻辑都是基于 ClusterState 元数据驱动的,所以对外看起来就是一个包含全部索引的的 clientnode。tribenode 通过配置多个 Elasticsearch 集群地址,然后以 clientnode 角色分别连接每个集群,每个集群看起来会多了一个 clientnode。tribenode 通过该 clientnode 角色获取到集群的 ClusterState 信息,并绑定 listener 监听 ClusterState 变化。tribenode 将获取的所有集群的 ClusterState 信息 merge 到一起,形成一个对外部访问使用的 ClusterState 对象,对外提供服务。tribenode 除了注册 listener 和 merge ClusterState,其他的所有逻辑都是复用了 clientnode 的代码。
ccs核心原理:首先要特别注意,ccs只针对_search API,因此如果集群不只是提供_search服务,ccs是不可用的。ccs首先需要将独立的集群联系起来,可以通过修改elasticsearch.yml文件或通过_cluster/setting API添加/删除其它集群。相互注册之后就可以跨集群相互访问了,而且ccs支持*通配符来匹配所有集群。
两者比较:tribenode可以满足跨集群访问的需求,而且对外是透明的。但是tribenode存在一定的问题,tribenode 不会持久化 ClusterState 对象,重启时需要从每个 Elasticsearch 集群获取元数据。而在获取元数据期间,tribenode 就已经能够提供访问,会导致查询到还在初始化中的集群索引访问失败。tribenode 连接的集群多了,初始化会变得很慢。可以通过备份集群的方式来解决这个问题,重启的时候将流量引向备份集群。而且tribenode不允许不同集群有相同的index,而ccs是可以的。
可见官方的两种方式都存在一定的问题,目前官方还没有稳定的解决方案,只能自己实现proxy的功能。后面会介绍自己通过netty实现es proxy的思路。