目标
灵雀云私有云平台的日志系统从4年前就在使用 Elasticsearch 作为日志的接收平台,从2.X 到 5.6 再到 6.7。根据客户实际日志量,需要确定何等的集群规模大概支持多少日志量。现在很多客户在要求日志系统支撑5w/s的日志量不丢失,不延迟,且带备份。根据官方的调优文档指导,我们需要实践出一套部署的规格和调参实践。
ES集群的部署
es集群基于k8s部署,使用chart去管理 ,我们使用两个deployment,第一个部署master节点,master 节点主要作为管理metadata 的节点,不做存储,聚合,io,因此配置可以稍微差些,但我们做测试,为了最大化利用资源master 同时也做了data 节点,启动master 后,继续部署下一个deployment,需要确保两个deployment部署的es 集群名称相同。且data 中指定master 的任一可达的IP。
我们继续部署一个kibana 作为监控。我们单个节点的配置是8C64G,1T SSD,es pod 的jvm为31G,节点不再部署其他负载。master 3台(也做data),data 节点9台,共12个节点。
参数调整
-
使用Bulk requests,这个很显然,一条日志索引一次,显然是不明智的,官方推荐,在一个节点上的单个shard,尝试从100一个一个bulk开始,不断double,等到了稳定延迟的时候则停止,但是不宜过多,根据日志的size,要考虑批次内容太多的时候,会对内存造成压力(index buffer)
-
使用 多 线程,增加并发写入,这个也不难理解,需要观察下返回值什么时候出现,TOO_MANY_REQUESTS,出现则意味着ES处理到达了极限。
-
不去设置或者增加 refresh interval 这个参数。ES是一个日志管理平台,管理的核心就是Lucence,就像k8s 和docker 的关系,lucence 管理的是shard,每一个shard有一个提交点(本质是一个文件,描述了当前的segment和translog信息等),一个shard是由一个个的segment组成的,而segment并不是实时产生的。这里需要展开讲下,ES是一个准实时的系统为什么?为什么不是写入就能查到?正是 refresh interval 这个参数,当前有很多索引请求到了以后,es不是直接写盘。如图:
这个时候,相当于我们写代码的时候,接收者收到了自己的接收buffer里,这里记住,默认是你JVM的10%,还是字节流。这个阶段,我们是查不到的,因为字段没有实例化,如果调用了lucence 的接口,也就是refresh 。图就变成了这样:
这个阶段就是可以查的了,这个阶段就像写代码:fd = fopen(“/a/b/c.log”,'rw') fd.write(segment_obj)
这个时候,你read 文件实际就可以获取内容了,但是掉电以后就没了,因为你没flush没有写到磁盘上。以上是refresh interval 参数的意义。
-
禁用swapping。这个很好理解,而且必须做的,不用说,docker 也不喜欢的。
-
足够的操作系统缓存,官方推荐,至少机器的一半内存。用到它的地方很多,比如write,比如translog 的写入,等等。不能含糊的,这个影响很多。
-
自动产生文件id,这个需要检查下自己的代码,有没有使用了
BulkIndexRequest().Id()
,有的话去掉了。 -
更快的硬件,SSD优先,分布式存储再见,NFS SMB别用了。
-
索引buffer 的size,这个在3里提到了,默认10%
-
translog 的配置,这个地方也可以展开说了,第三步里我们如果只write的话,机器down的话,就会有数据丢失。那么如何保持数据的持久化呢,3里面我们提到,一次完整的提交,是需要把segment flush 到磁盘上的,但是现在你只是write了,可以查了,还不能保证掉电的数据安全,ES增加了一个translog,或者说transaction log, 它记录了所有的es 的操作请求,是一个严格的二进制,数据密度高 ,所以当buffer 到了以后,同步的translog也有更新:
当你refresh 的时候,buffer 的数据,序列化到了segment里(注意,还没有落盘哦,只是write了下)如下图:
其中translog忠实的记录你的buffer内容,因为是原封不动的写入文件,所以比较快,当然translog它也是先到内存里。
接着,在内存里docs,开始写入新的segment,清空buffer,修改提交点,fsync写入磁盘,删除translog。安全了。
问题:
translog 安全么?
在文件被 fsync 到磁盘前,被写入的文件在重启之后就会丢失。默认 translog 是每 5 秒被 fsync 刷新到硬盘, 或者在每次写请求完成之后执行(e.g. index, delete, update, bulk)。这个过程在主分片和复制分片都会发生。最终, 基本上,这意味着在整个请求被 fsync 到主分片和复制分片的translog之前,你的客户端不会得到一个 200 OK 响应。
这个行为可以通过设置 durability 参数为 async 来启用:
PUT /my_index/_settings
{
"index.translog.durability": "async",
"index.translog.sync_interval": "5s"
}
如果你不确定这个行为的后果,最好是使用默认的参数( "index.translog.durability": "request"
)来避免数据丢失。
结论
,我们认为12台8C64G的主机ssd盘,是能够支撑