Elasticsearch 最全调优,最佳实践(二)

接着上一篇  Elasticsearch 最全调优,最佳实践(一)

15、在 Elasticsearch 中,是怎么根据一个词找到对应的倒排索引的?

  • Lucene 的索引过程,就是按照全文检索的基本过程,将倒排表写成此文件格式的过程。

  • Lucene 的搜索过程,就是按照此文件格式将索引进去的信息读出来,然后计算每篇文档打分(score)的过程。

16Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?

(1)64 GB 内存的机器是非常理想的, 但是 32 GB 和 16 GB 机器也是很常见的。少于 8 GB 会适得其反。

  • 如果你要在更快的CPUs 和更多的核心之间选择,选择更多的核心更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。

  • 如果你负担得起SSD,它将远远超出任何旋转介质。 基于SSD 的节点,查询和索引性能都有提升。如果你负担得起,SSD 是一个好的选择。

  • 即使数据中心们近在咫尺,也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。

  • 请确保运行你应用程序的JVM 和服务器的JVM 是完全一样的。 在

Elasticsearch 的几个地方,使用Java 的本地序列化。

  • 通过设置gateway.recoverafternodes、gateway.expectednodesgateway.recoverafter_time 可以在集群重启的时候避免过多的分片交换,这可能会让数据恢复从数个小时缩短为几秒钟。

  • Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。最好使用单播代替组播。

  • 不要随意修改垃圾回收器(CMS)和各个线程池的大小。

  • 把你的内存的(少于)一半给Lucene(但不要超过 32 GB!),通过 ESHEAPSIZE 环境变量设置。

  • 内存交换到磁盘对服务器性能来说是致命的。如果内存交换到磁盘上,一个 100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出swapping 对于性能是多么可怕。

  • Lucene 使用了大量的文件。同时,Elasticsearch 在节点和HTTP 客户端之间进行通信也使用了大量的套接字。 所有这一切都需要足够的文件描述符。你应该增加你的文件描述符,设置一个很大的值,如 64,000。

索引阶段性能提升方法

  • 使用批量请求并调整其大小:每次批量数据 5–15 MB 大是个不错的起始点。

  • 存储:使用SSD

  • 段和合并:Elasticsearch 默认值是 20 MB/s,对机械磁盘应该是个不错的设置。如果你用的是SSD,可以考虑提高到 100–200 MB/s。如果你在做批量导入,完全不在意搜索,你可以彻底关掉合并限流。另外还可以增加 index.translog.flushthresholdsize 设置,从默认的 512 MB 到更大一些的值,比如 1 GB,这可以在一次清空触发的时候在事务日志里积累出更大的段。

  • 如果你的搜索结果不需要近实时的准确度,考虑把每个索引的

index.refresh_interval 改到 30s。

  • 如果你在做大批量导入,考虑通过设置index.numberofreplicas: 0 关闭副本。

16、对于 GC 方面,在使用 Elasticsearch 时要注意什么?

  • 倒排词典的索引需要常驻内存,无法GC,需要监控data node 上

segmentmemory 增长趋势。

  • 各类缓存,field cache, filter cache, indexing cache, bulk queue 等等,要设置合理的大小,并且要应该根据最坏的情况来看heap 是否够用,也就是各类缓存全部占满的时候,还有heap 空间可以分配给其他任务吗?避免采用clear cache 等 “自欺欺人”的方式来释放内存。

  • 避免返回大量结果集的搜索与聚合。确实需要大量拉取数据的场景,可以采用 scan & scroll api 来实现。

  • cluster stats 驻留内存并无法水平扩展,超大规模集群可以考虑分拆成多个集群通过tribe node 连接。

  • 想知道heap 够不够,必须结合实际应用场景,并对集群的heap 使用情况做持续的监控。

  • 根据监控数据理解内存需求,合理配置各类 circuit breaker,将内存溢出风险降低到最低

17Elasticsearch 对于大数据量(上亿量级)的聚合如何实现?

Elasticsearch 提供的首个近似聚合是cardinality 度量。它提供一个字段的基数,即该字段的distinct 或者unique 值的数目。它是基于HLL 算法的。

HLL 会先对我们的输入作哈希运算,然后根据哈希运算的结果中的bits 做概率估 算从而得到基数。其特点是:可配置的精度,用来控制内存的使用(更精确= 更多内存);小的数据集精度是非常高的;可以通过配置参数,来设置去重需要的固定内存使用量。无论数千还是数十亿的唯一值,内存使用量只与你配置的精确度相关。

18、在并发情况下,Elasticsearch 如果保证读写一致?

  • 可以通过版本号使用乐观并发控制,以确保新版本不会被旧版本覆盖,由应用层来处理具体的冲突;

  • 另外对于写操作,一致性级别支持quorum/one/all,默认为quorum,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点上重建。

  • 对于读操作,可以设置replication 为sync(默认),这使得操作在主分片和副本分片都完成后才会返回;如果设置replication 为async 时,也可以通过设置搜索请求参数_preference 为primary 来查询主分片,确保文档是最新版本。

19、如何监控 Elasticsearch 集群状态?

Marvel 让你可以很简单的通过Kibana 监控Elasticsearch。你可以实时查看你的集群健康状态和性能,也可以分析过去的集群、索引和节点指标。

20、介绍下你们电商搜索的整体技术架构。

21、介绍一下你们的个性化搜索方案?

基于 word2vec 和 Elasticsearch 实现个性化搜索

  • 基于 word2vec、Elasticsearch 和自定义的脚本插件,我们就实现了一个个性化的搜索服务,相对于原有的实现,新版的点击率和转化率都有大幅的提升;

  • 基于 word2vec 的商品向量还有一个可用之处,就是可以用来实现相似商品的推荐;

  • 使用 word2vec 来实现个性化搜索或个性化推荐是有一定局限性的,因为它只能处理用户点击历史这样的时序数据,而无法全面的去考虑用户偏好,这个还是有很大的改进和提升的空间;

22、是否了解字典树?

常用字典数据结构如下所示:

Trie 的核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。它有 3 个基本性质:

  • 根节点不包含字符,除根节点外每一个节点都只包含一个字符。

  • 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。

  • 每个节点的所有子节点包含的字符都不相同。

  • 可以看到,trie 树每一层的节点数是 26^i 级别的。所以为了节省空间,我们还可以用动态链表,或者用数组来模拟动态。而空间的花费,不会超过单词数×单词长度。

  • 实现:对每个结点开一个字母集大小的数组,每个结点挂一个链表,使用左儿子右兄弟表示法记录这棵树;

  • 对于中文的字典树,每个节点的子节点用一个哈希表存储,这样就不用浪费太大的空间,而且查询速度上可以保留哈希的复杂度O(1)。

23、拼写纠错是如何实现的?

  • 拼写纠错是基于编辑距离来实现;编辑距离是一种标准的方法,它用来表示经过插入、删除和替换操作从一个字符串转换到另外一个字符串的最小操作步数;

  • 编辑距离的计算过程:比如要计算batyu 和beauty 的编辑距离,先创建一个 7×8 的表(batyu 长度为 5,coffee 长度为 6,各加 2),接着,在如下位置填入黑色数字。其他格的计算过程是取以下三个值的最小值:

如果最上方的字符等于最左方的字符,则为左上方的数字。否则为左上方的数字

+1。(对于 3,3 来说为 0)

左方数字+1(对于 3,3 格来说为 2)上方数字+1(对于 3,3 格来说为 2)

最终取右下角的值即为编辑距离的值 3。

对于拼写纠错,我们考虑构造一个度量空间(Metric Space),该空间内任何关系满足以下三条基本条件:

d(x,y) = 0 -- 假如x 与y 的距离为 0,则x=y

d(x,y) = d(y,x) -- x 到y 的距离等同于y 到x 的距离

d(x,y) + d(y,z) >= d(x,z) -- 三角不等式

  1. 根据三角不等式,则满足与query 距离在n 范围内的另一个字符转B,其与 A 的距离最大为d+n,最小为d-n。
  2. BK 树的构造就过程如下:每个节点有任意个子节点,每条边有个值表示编辑距离。所有子节点到父节点的边上标注n 表示编辑距离恰好为n。

比如,我们有棵树父节点是”book”和两个子节点”cake”和”books”,”book”

到”books”的边标号 1,”book”到”cake”的边上标号 4。从字典里构造好树后,无论何时你想插入新单词时,计算该单词与根节点的编辑距离,并且查找数值为 d(neweord, root)的边。递归得与各子节点进行比较,直到没有子节点,你就可以创建新的子节点并将新单词保存在那。比如,插入”boo”到刚才上述例子的树中,我们先检查根节点,查找d(“book”, “boo”) = 1 的边,然后检查标号为 1 的边的子节

点,得到单词”books”。我们再计算距离d(“books”, “boo”)=2,则将新单词插在”books”之后,边标号为 2。

3、查询相似词如下:计算单词与根节点的编辑距离d,然后递归查找每个子节点标号为d-n 到d+n(包含)的边。假如被检查的节点与搜索单词的距离d 小于n,则返回该节点并继续查询。比如输入cape 且最大容忍距离为 1,则先计算和根的编辑距离d(“book”, “cape”)=4,然后接着找和根节点之间编辑距离为 3 到 5 的,这个就找到了cake 这个节点,计算d(“cake”, “cape”)=1,满足条件所以返回cake, 然后再找和cake 节点编辑距离是 0 到 2 的,分别找到cape 和 cart 节点,这样就得到cape 这个满足条件的结果。

24.在数十亿级别数据量情况下,Elasticsearch 如何提高查询效率啊?

1、性能优化--filesystem cache

往 es 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到filesystem cache 里面去。

es 的搜索引擎严重依赖于底层的filesystem cache,你如果给filesystem cache 更多的内存,尽量让内存可以容纳所有的idx segment file 索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。

要让es 性能要好,最佳的情况下,就是你的机器的内存,至少可以容纳你的总数据量的一半。 是仅仅在es 中就存少量的数据,就是你要用来搜索的那些索引,如果内存留给filesystem cache 的是 100G,那么你就将索引数据控制在 100G 以内,这样的话,你的数据几乎全部走内存来搜索,性能非常之高,一般可以在 1 秒以内。

2、数据预热

如果 es 集群中每个机器写入的数据量还是超过了filesystem cache 一倍,比如说你写入一台机器 60G 数据,结果filesystem cache 就 30G,还是有 30G 数据留在了磁盘上。 对于那些你觉得比较热的,经常会有人访问的数据,最好做一个专门的

缓存预热子系统,就是对热数据每隔一段时间,就提前访问一下,让数据进入

filesystem cache 里面去。

例如:拿微博来说,你可以把一些大 V,平时看的人很多的数据,你自己提前后台搞个系统,每隔一会儿,自己的后台系统去搜索一下热数据,刷到filesystem cache 里去,后面用户实际上来看这个热数据的时候,他们就是直接从内存里搜索了,就能快速查找到

3、冷热分离

es 可以做类似于mysql 的水平拆分,就是说将大量的访问很少、频率很低的数据,单独写一个索引,然后将访问很频繁的热数据单独写一个索引。最好是将冷

数据写入一个索引中**,然后热数据写入另外一个索引中,这样可以确保热数据在被预热之后,尽量都让他们留在 filesystem os cache 里,别让冷数据给冲刷掉。

**

你看,假设你有 6 台机器,2 个索引,一个放冷数据,一个放热数据,每个索引 3个 shard。3 台机器放热数据index;另外 3 台机器放冷数据index。然后这样的 话,你大量的时候是在访问热数据index,热数据可能就占总数据量的 10%,此时数据量很少,几乎全都保留在filesystem cache 里面了,就可以确保热数据的访问性能是很高的。但是对于冷数据而言,是在别的index 里的,跟热数据index 不在相同的机器上,大家互相之间都没什么联系了。如果有人访问冷数据,可能大量数据是在磁盘上的,此时性能差点,就 10% 的人去访问冷数据,90% 的人在访问热数据,也无所谓了。

4document 模型设计

对于一些复杂的关联查询的数据。在es 里面的关联查询尽量别用,一旦用了性能一般都不太好。

最好是先在PHP 系统里就完成数据库关联查询,将关联好的数据直接写入es 中。搜索的时候,就不需要利用es 的搜索语法来完成join 之类的关联搜索了。

document 模型设计是非常重要的,很多操作,不要在搜索的时候才想去执行各种复杂的乱七八糟的操作。es 能支持的操作就是那么多,不要考虑用es 做一些它不好操作的事情。如果真的有那种操作,尽量在document 模型设计的时候,写入的时候就完成。另外对于一些太复杂的操作,比如join/nested/parent-child 搜索都要尽量避免,性能都很差的。

5、分页性能优化

es 的分页是较坑的,为啥呢?举个例子吧,假如你每页是 10 条数据,你现在要查询第 100 页,实际上是会把每个shard 上存储的前 1000 条数据都查到一个协调节

点上,如果你有个 5 个 shard,那么就有 5000 条数据,接着协调节点对这 5000 条

数据进行一些合并、处理,再获取到最终第 100 页的 10 条数据。

分布式的,你要查第 100 页的 10 条数据,不可能说从 5 个shard,每个shard 就查 2 条数据?最后到协调节点合并成 10 条数据?你必须得从每个shard 都查 1000条数据过来,然后根据你的需求进行排序、筛选等等操作,最后再次分页,拿到里面第 100 页的数据。你翻页的时候,翻的越深,每个shard 返回的数据就越多,而且协调节点处理的时间越长。所以用es 做分页的时候,你会发现越翻到后面,就越是慢。

那有什么方案有优化吗?

1)不允许深度分页/默认深度分页性能很惨

你系统不允许翻那么深的页,跟产品经理说,默认翻的越深,性能就越差。

类似于app 里的推荐商品不断下拉出来一页一页的

类似于微博中,下拉刷微博,刷出来一页一页的,你可以用scroll api,关于如何使用,

scroll 会一次性给你生成所有数据的一个快照,然后每次翻页就是通过游标移动,获取下一页下一页这样子,性能会比上面说的那种分页性能也高很多很多,基本上都是毫秒级的。

但是唯一的一点就是,这个适合于那种类似微博下拉翻页的,不能随意跳到任何一页的场景。也就是说,你不能先进入第 10 页,然后去 120 页,然后又回到 58页,不能随意乱跳页。所以现在很多产品,都是不允许你随意翻页的,app,也有一些网站,做的就是你只能往下拉,一页一页的翻。

最佳实践-PB级日志收集智能分析系统-LCA

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值