实现elasticsearch网关,兼容不同版本elasticseach读定请求,滚动升级

实现elasticsearch网关,兼容不同版本es,滚动升级

通用ES读写特征

  • 读特征,以_search结尾

localhost:9200/[index_name]/[type_name]/_search?a=b&c=d

localhost:9200/filebeat_2020*/_search

localhost:9200/filebeat_202001*,filebeat_202002*/_search

索引按年月日分割,查询方式以url限制时间段和type,并不在查询的body里添加index或type的查询条件,只是在url里传入,这减少了分发的实现难度,只用管url就可以

因为6.8只支持单type,index_name->type_name 关系为1:1,很容易维护已有的index和type的映射

为了描述简单,我们假设index_name 为 filebeat_202003_log,filebeat_202003_metrics 最后的_后字符串即为type_name

  • 写特征,大批量写入通常用bulk

localhost:9200/_bulk

官方示例为

[Bulk API | Elasticsearch Reference 7.11] | Elastic

POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

[Bulk API | Elasticsearch Reference 6.8] | Elastic

6.8和7.X的区别是需要传入_type参数

POST _bulk
{ "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "_doc", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "_doc", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

方案介绍

es 升级迁移数据成本较高,考虑以remote的方式实现,不迁移旧版本数据至新集群而采用新旧集群多版本串联的方式,逐步升级

因为索引的特征是按月分割,假设以2021年3月分割完成

202103及之前的月度数据都存储在old es cluster 6.8.14内

202103之后的月度数据存储在new es cluster 7.10.2

es地址 版本 索引数据
old_es:9200 6.8.14 202103之前,例filebeat_202003
new_es:9200 7.10.2 202103之后,例filebeat_202004

现集群读写

读写 -> old es cluster 6.8.0

操作方式

  1. 布署新集群es 7.10.2
  2. 在 es 7.10.2内 注册旧集群es 6.8.14 为remote cluster 考虑url长度问题,remote cluster name 为单字符 o,含义是old
  3. 启动网关服务
  4. 将所有对es集群的日常读写(仅限_search,bulk,scroll)请求,提交至网关
  5. 网关接收请求url,并根据外部维护的索引信息,变更url为真实的url,提交至新es 7.10.2

升级后集群读写

流程图

读写->

[自实现网关,重写request url,request body]->

新es 7.10.2->

旧数据的访问通过es remote cluster

分别举例如下,只讲最简单的几项,更复杂和细节的url,以此类推

_search 读

请求es6.8.14 原始url

es6:9200/filebeat_202103_log,filebeat_202104_log/log/_search

重写为

es7:9200/o:filebeat_202103_log,filebeat_202104_log/_search

filebeat_202103_log 在es6内,es6 做为name为o的remote cluster 注册在es7内

通过o:filebeat_202103_log,es7会调用es6 获取数据

以上是只在url里限制index,type的情况,如需在request_body里添加条件,也需更改body内容

_bulk 写

bulk 需要重写body,另es不支持通过remote cluster写入,需要将请求拆分

这里有两个方向的调整

  1. 是以6.8.14的为准,变更为兼容7.10.2

    优点是,写入方不需要做任何变化,统一在网关层做适配

    但最终所有服务都要以7.10.2的规范为标准做改造

  2. 还是以7.10.2的为准,变更为兼容6.8.14

    整体上和6.8.14的优缺点相反

其实两类方案并不互斥,可以都做

网关公开两个host:port ,分别提供方案1和方案2的服务

  • 方案1,接收6.8.14标准的请求,为兼容老服务

接收

POST _bulk
{ "index" : { "_index" : "filebeat_202103_log", "_type" : "log", "_id" : "1" } }
{ "field1" : "value1" }
{ "index" : { "_index" : "filebeat_202104_log", "_type" : "log", "_id" : "2" } }
{ "field1" : "value1" }

对分别属于es6,es7的index拆分为两个请求

es6

POST _bulk
{ "index" : { "_index" : "filebeat_202103_log", "_type" : "log", "_id" : "1" } }
{ "field1" : "value1" }

es7

{ "index" : { "_index" : "filebeat_202104_log", "_id" : "2" } }
{ "field1" : "value1" }
  • 方案2,接收7.10.2标准的请求,接入适配完7.10.2的服务

接收

POST _bulk
{ "index" : { "_index" : "filebeat_202103_log", "_id" : "1" } }
{ "field1" : "value1" }
{ "index" : { "_index" : "filebeat_202104_log", "_id" : "2" } }
{ "field1" : "value1" }

对分别属于es6,es7的index拆分为两个请求

es6

POST _bulk
{ "index" : { "_index" : "filebeat_202103_log", "_type" : "log", "_id" : "1" } }
{ "field1" : "value1" }

es7

{ "index" : { "_index" : "filebeat_202104_log", "_id" : "2" } }
{ "field1" : "value1" }

两种方案只是接收格式不同,拆分的结果是一致的

返回内容也需要根据分别对es6,es7请求的结果,合并统计,再以es bulk response的标准返回给client

最后,可以结合外部存储,例如sql来维护index的版本信息,最近月的数据在es7,其他索引默认在es6

另外执行必要的index迁移服务,迁移某索引至7.10.2,则添加该索引的信息,使路由到es7


方案已经确定,然后开始实施

实施前评估主要的技术点

1 读_search request url的解析适配

2 写 bulk的body解析,及拆分

3 拆分为对es6,es7的请求,如果采用es 的sdk 可能有不兼容的问题,必要时直接拼接json http request 而不使用sdk

3 合并分发bulk的response 为es标淮的bulk response

4 mysql 维护index 索引位置信息,及可选的type信息

5 服务不能每次都查mysql,需简单做个缓存

6 限流,限频,熔断,线程池请求队列等暂不做考虑

7 gc是个需要留意的项

8 高并发量下的瓶颈问题

风险点

已经做过些可行性验证,但未必能覆盖全量数据,会有功能开发完成,但部分请求不适用的情况隐患

posted @ 2021-03-21 19:08  cclient  阅读(122)  评论(0编辑  收藏  举报