ES - 集群点滴

这里主要记录一下集群使用用碰到过的要点, 以及对性能优化比较有意义的知识点. 会逐渐完善拆解

内存:

首先应该记住, 必须给予Elasticsearch足够的内存,而且是物理内存. 一般来说, 运行Elasticsearch的JVM进程不应该超过可用内存的50%或60%, 这样做是因为要留一些可用内存给操作系统以及操作系统的I/O缓存 (Page Cache). 通常把Xmx和Xms参数设置为相同的值以避免JVM堆的大小调整.

搜索引擎是为速度而生的, 通常来说秒级的访问才能留住用户, 不过当前的互联网环境下, 优秀的大公司都不厚道的把服务做到了及时响应, 这里还包括网络延迟. 所以, 交给集群运算的任务, 要尽量在内存中完成, 有IO等待的话, 基本上是达不到及时响应的. 

这是基本思想, 优化做的事核心都是一样的,  优化内存和cache的使用. 官方文档记录了集中常见的cache算法, 包括field cache, filter cache, bulk queue, indexing buffer和page cache (page cache其实是操作系统级别的). 还有一个比较重要的概念是段合并, 倒排索引是在segments中完成的, 知道出发了某个阈值限制, 才会写到磁盘上, 且一旦创建, 是不能更改的[Elasticsearch from the Bottom Up]. 随着index的增长, segments会以一定的规则merge, 这个对性能提升很有意义可参考[how segement merging works]

从过去遇到的问题总结来看, 大多都关于内存, 我们本着省钱优先的原则, 系统不崩溃是不会升级的, 所以需要很了解内存的使用情况. 需要好好了解下JVM的调试方法和基本的几个状态查看API. 

关于集群需要多少内存这件事, 通常需要综合考虑搜索的类型和数据增长, 更新的情况等等. 比如, 如果对数据的操作主要是简单查询, 不做分析和聚合, 通常会加载很多的字段, 这种对内存的需求比较低, 但是page cache使用的会多. 而对于分析型的请求, page cache可能用的很少, 但是堆空间会使用的很多. 我觉得没有特别通用的计算法则, 需要测试, 关注内存和cache的使用情况, 很好的监控, 一个比较简单的做法是先尽量多开内存, 然后适当减少调整. 这里有一个点, 很多文章里也提到了, 通常给JVM的内存不能超过32G, 否则垃圾回收的开销会很大. 但是对于page cache可定是越多越好.


合适的分片和副本数量:

集群的默认配置是5个分片, 1个副本. 看上去有过度分配的嫌疑, 不过这个是标准配置, 给新手同学提供的, 是在数据量增长和多酚片搜索结果合并之间做了平衡. 就提数量多少, 需要我们根据业务量和index的管理上综合考虑, 比如, 如果我们定义了一个有限的, 明确的数据集, 其实只使用一个分片也不为过.

当然, 如果没有特别明确的定义, 通常来说, 最理想的分片数量应该参考集群当前的或者设计的节点数量. 这里, 我们需要结合副本数量一起考虑, 为的是保证高可用和数据的吞吐量. 一般性的公式如下:

设计最大节点数 = 分片数 * (副本数 + 1)

关于index的管理, 分片及副本数量, 其实需要再展开一点, 貌似看上去, 如果硬件资源允许, 用更少的分片就可以了. 不过更多的分片在某些场景下是有优势的, 因为一个分片事实上是一个lucene索引, 更多的分片意味着每个在小的lucene索引上执行的操作会更快, 尤其是索引. 不过可以很容易想到, 虽然一个分片上的索引和查询快了, 但是结果的合并代驾也是比较大的. 但是这个对于那种查询都是基于用户上下文的多租户的系统是可以避免的, 因为我们可以通过路由的方法, 将每个用户的数据都索引到一个独立的分片中, 在查询时就只查询那个分片.

多分片和多索引的关系, 索引是根据业务定义的数据集合, 分片是为了水平扩展和高可用而设计的. 在应用场景上来说, 很多时候使用多个索引是更好的选择, 比如将基于时间的数据索引到按照时间切分的不同索引中, 这样我们可以从更高的层面上控制数据的查询范围, 对于时间序列的分析尤其适用, 所以索引和分片的配置关系可以根据业务定义平衡使用.

关于副本, 这里也有一个使用技巧, 副本解决的是数据安全和吞吐量的问题, 而且他有一个很好的特点是, 副本的数量可以动态控制, 这样一来, 我们就可以通过增加副本数量, 将日益增加的查询吞吐分配到不同的集群几点上. 当然, 副本造成的数据同步和索引的开销也不小.

关于路由的实践正好是这两周的一个工作任务,下一篇会详细写一下.


索引别名:

索引别名是个很有使用价值的功能, 多了别名这一层封装, 可以方便的控制数据访问范围, 切换索引, 重建索引等, 好处就是后端应用不会感知.

什么是索引别名: 它是一个或多个索引的一个附加名称,允许使用这个名称来查询索引. 一个别名可以对应多个索引, 反之亦然, 一个索引可以是多个别名的一部分. 然而, 请记住, 你不能使用对应多个索引的别名来进行索引或实时的GET操作. 如果你这样做, Elasticsearch将抛出一个异常(但可以使用对应单个索引的别名来进行索引操作), 因为Elasticsearch不知道应该把索引建立到哪个索引上,或从哪个索引获取文档.

使用别名的好处:
1 提高检索效率
2 简化代码控制
3 控制冷热数据

创建别名:
curl -XPOST 'localhost:9200/_aliases' -d '{
"actions" : [
{ "add" : { "index" : "mc_statis-2017.07.01", "alias" : "mc_statis-active" } },
{ "add" : { "index" : "mc_statis-2017.07.02", "alias" : "mc_statis-active" } },
{ "add" : { "index" : "mc_statis-2017.07.03", "alias" : "mc_statis-active" } }]}'

curl -XGET 'localhost:9200/mc_statis-2017.07.*/_search?q=test'
-->
curl -XGET 'localhost:9200/mc_statis-active/_search?q=test'

修改别名:
curl -XPOST 'localhost:9200/_aliases' -d '{
"actions" : [
{ "remove" : { "index" : "mc_statis-2017.07.01", "alias" : "mc_statis-active" } }
]}'

获取别名, GET /_aliases/*

移除别名, DELETE /mc_statis-active/_alias/mc_statis-2017.01.01

add 和 remove命令可以在一个请求中发送. 

别名添加过滤器:
curl -XPOST 'localhost:9200/_aliases' -d '{
"actions" : [{
"add" : {
"index" : "data", "alias" : "client", "filter" : { "term" : { "clientId" : "12345" } }}}]}'

别名添加路由:

跟在别名中使用过滤器类似,可以在别名中添加路由值. 假设我们在使用基于用户标识符的路由, 且想在别名中使用相同的路由值, 则在名为client的别名中, 我们将在查询中使用路由值12345, 12346, 12347, 而在索引建立中只使用12345. 为此, 使用下面的命令创建别名:

curl -XPOST 'localhost:9200/_aliases' -d '{
"actions" : [{
"add" : {
"index" : "data",
"alias" : "client",
"search_routing" : "12345,12346,12347",
"index_routing" : "12345"}}]}'

这样,使用client别名索引数据时,将使用index_routing属性的值. 在查询时,将使用search_routing属性值.还有一件事。请看发送到上述别名的如下查询:
curl -XGET 'localhost:9200/client/_search?q=test&routing=99999,12345'
它将使用12345作为路由值. 这是因为Elasticsearch将使用search_routing属性值和查询路由参数值的共同值,在我们的例子中是12345.


集群的再平衡设置:

rebalance这件事通常发生在节点加入或者离开集群, 或者集群中index的数量发生较大的变化, es会根据资源配置重新分配索引, 这个神奇的事情对用户透明, 配置如下:

cluster.routing.allocation.allow_rebalance, 指定平衡何时开始

always:该值表明再平衡可以在需要时随时开始

indices_primaries_active:该值表明当所有的主分片都初始化后,再平衡才会开始

indices_all_active:该值是默认设置,意味着所有分片和副本都初始化后,再平衡才会开始

cluster.routing.allocation.cluster_concurrent_rebalance, 集群中同时在节点间移动的分片数量, 默认为2

cluster.routing.allocation.node_concurrent_recoveries, 单个节点可同时初始化的分片数量, 默认为2

为了加快这个过程, 可以根据集群的运行状态, 进行调整.


数据预热:

有时, 可能需要为了处理查询而准备Elasticsearch. 也可能因为你严重依赖字段数据缓存, 需要在生产查询到达之前加载它们,或者你可能想预热操作系统I/O缓存. 不管什么原因, Elasticsearch允许为类型和索引定义预热查询(warning query).

定义一个新的预热查询, 预热查询跟普通查询没什么区别,只是它存储在Elasticsearch一个特殊的名为_warmer的索引中. 假设想使用下面的查询来做预热, 为了存储为library索引的预热查询,执行以下命令

curl -XPUT 'localhost:9200/library/_warmer/tags_warming_query' -d '{
"query" : {
"match_all" : {}
},

"facets" : {
"warming_facet" : {"terms" : {"field" : "tags"}}
}}'

上诉命令将我们的查询注册为一个名为tags_warming_query的预热查询. 你的索引可以有多个预热查询, 但每一个查询都需要一个唯一的名称.

应该记住,不要让你的Elasticsearch集群加载过多的预热查询,因为最终你可能会花太多的时间预热,而不是处理你的生产查询.

你可能感兴趣的:(ES - 集群点滴)