写这篇文章的目的并不是给出解决方案,而是我希望通过提出问题,并提供思路的方式,来摸索问题的答案。当然有能力的人看到这篇文章,欢迎在评论区给出好的意见。
我的疑惑和问题
第一个问题是关于集群规划的问题
对于上述的需求,6T数据,20亿条,来检索。
- 到底多大的集群规模能够承载这些数据?
- 我们需要多少个节点?
- 我们需要什么样的硬件资源,多大的内存空间?
- 每个节点我们分配多少个CPU核心更好?
- 如果将这些数据都放在同一个索引,如果做才能达到普通检索1秒以内,聚类检索3秒以内的要求?
分享一个真实的案例:
我先说一下我对集群规划的理解(查看的官方文档,以及网上多数的集群规划相关的文章)。关于节点数,一个节点能够承载的分片数,取决于堆内存的大小,公式计算是,1G堆内存不超过20个分片。而单个分片大小,理论值是 20G - 40G性能最好。按理说,我6T的数据 = 6144G ,如果每个分片30G,那么6144/30 = 205个分片。 我的一个节点是64G内存,我分31G给堆内存。理论上来说,31能够支撑的分片数是 600个。按照这么算的话,我这么多数据一个节点就够了。
然而实际上并不是,我并没有把这些数据只用一个集群来分配。我的测试集群是 512G内存,48核心10T固态硬盘的配置(阿里云数据中心的人说,es的单个节点最佳配置是 16个核心,64G内存,2T固态硬盘。这被多数人认可,但是我现在认为es的集群总的核心数,应该和单个索引的最大分片数对齐,甚至能多则再多一点,因为还要有一些线程去做段合并之类的。这个是根据es的检索原理来的,实际上单个分片对es来说是最小的资源分片单元,一个分片实际上就是一个lucene实例。等我再研究清楚lucene再补一篇文章来证明)。现在想想es的工作原理,我们知道这个机器配置非常的不均衡,问题在CPU核心上。我是每台机器四个数据节点,一个master节点。我有测过我单台机器的IO在每秒2G以上。我用这三台机器组成了集群,来侧这6T的数据,得到的效果挺一般的。
我发现检索速度和我的条件有很大的关系,当我的检索结果集超过两亿以后,集群的检索时间在5秒左右。如果检索的结果集有一两千万,那么检索时间通常在一秒左右,不超过两秒。但是聚类分析通常要在 5秒左右。
第二个问题是关于索引应该如何划分的问题
像这样的大索引,我们是否有必要将数据做拆分?我们的集群是否能负载这么大的索引。
第三个问题是关于索引拆分能够提升的问题
将索引拆分成小索引,然后拆分后的小索引设置相同的别名。这样是否能提升性能?拆分成多少个索引性能最好?
我把特定条件的数据拆分了出来,然后做了检索的对比,比方说我一共有20亿数据,其中中国的的3亿。我把这3亿单独拆出来放一个索引。我发现去相同的搜索条件,去两个索引里边搜索,明显只有中国3亿数据的索引,搜索时间更短。这是我测过的得出的结论:大的目标搜索集,和小的目标搜索集,即使要搜的内容两个搜索集的交集是相同的,也是在小的搜索集搜索的时间更短!请记住这个结论,你可以去测试一下看看!
第四个问题:es对频繁修改并不友好,我们该如何应对频繁的更新的问题
这个问题其实非常的致命,这也是网上很多人在问的一个问题,为什么es用着用着越来越慢?
可能性有以下几点:
- 集群规模无法承载更多的数据量,到达极限以后,走下坡路了。这个时候我们应该去扩充集群。那么问题来了,什么时候是集群的极限承载能力,什么时候集群就开始走下坡路了?
- 如果索引中的数据没有再增加,理论上不会说越来越慢。我们还可以对索引进行强行的段合并。
- 如果es中数据在不断的增长,有两种情况,一种是数据不会发生修改,只是累积增长。第二种情况是我们的数据有唯一key,新增的数据会覆盖原来的数据,也就是发生了修改操作。第二种操作是非常致命的。特别是频繁的更新操作,会给集群带来非常大的负担。这和es的更新机制有关系,es在维护数据的时候有段的概念。对于已经放进去数据,不再修改,如果要有修改操作,也是把原来的数据标记删除,然后再添加一条新的数据。并没有办法把原来的数据修改了。在极差的情况下,一个段中有一半以上的数据都是标记删除的数据。并且段合并到一定程度,就永远都无法再进行段合并了(这个可以去了解lucene底层的段合并原理)。