
2.ES分布式搜索,传统数据库遍历式搜索
3.ES采用倒排索引,传统数据库采用B+树索引
4.ES没有用户验证和权限控制
5.ES没有事务的概念,不支持回滚,误删不能恢复
6.ES免费,完全开源;传统数据库部分免费
有关更详细的比较内容,可以到黑马程序员官网找到社区技术文章,找不到可以对话框问一下。里面还有结合工作的举例。
1 增大内存: es性能优化的杀手锏: filesystem cache(OS cache): 也就是说 尽量让内存可以容纳所有的索引数据文件,那么搜索的时候就基本都是走内存的,性能会非常高。磁盘和OS cache扫描速度相差近一个数量级,可能一个是1到几百毫秒,另一个是秒。最佳的情况下,就是单机机器的内存,至少可以容纳单机数据量的一半。另一个方面就是写数据的时候,仅仅写入要用来检索的少数几个字段就可以了,其余的数据放到hbase或者mysql上
2 数据预热
假设机器内存达到上面的要求,比如 内存是100G,数据是200G。那么有一半的数据存放在磁盘上,那么这个时候可以设计一个 数据预热子系统, 就是对热数据每隔一段时间,就提前访问一下,让热数据进入 filesystem cache 里面去。这样下次别人访问的时候,性能一定会好很多。
3 document 模型设计
document 模型设计是非常重要的,很多 *** 作,不要在搜索的时候才想去执行各种复杂的乱七八糟的 *** 作,尽量存放单纯的数据放到ES上去,不要考虑用 es 做一些它不好 *** 作的事情,比如 join/nested/parent-child 搜索都要尽量避免,性能都很差的。
4 分页性能优化
分页性能差的原因: https://www.jianshu.com/p/e4da06b55e63
解决方案1:跟产品经理说,你系统不允许翻那么深的页,默认翻的越深,性能就越差。
解决方案2:类似于 app 里的推荐商品不断下拉出来一页一页的
就像淘宝商品一样,一页一页往下刷,不能从第一页跳到100页,从100页跳到50页,不能这样 *** 作。
可以使用 scroll api 来实现,scroll 会一次性给你生成所有数据的一个快照,然后每次滑动向后翻页就是通过游标 scroll_id 移动,获取下一页下一页这样子,性能会比上面说的那种分页性能要高很多很多,基本上都是毫秒级的。
初始化时必须指定 scroll 参数,告诉 es 要保存此次搜索的上下文多长时间。你需要确保用户不会持续不断翻页翻几个小时,否则可能因为超时而失败。
除了用 scroll api,你也可以用 search_after 来做,search_after 的思想是使用前一页的结果来帮助检索下一页的数据,显然,这种方式也不允许你随意翻页,你只能一页页往后翻。初始化时,需要使用一个唯一值的字段作为 sort 字段。参考: https://www.cnblogs.com/hello-shf/p/11543453.html#4527510
见 https://www.jianshu.com/p/a5c1ec91c92e
先写入内存 buffer,在 buffer 里的时候数据是搜索不到的;同时将数据写入 translog 日志文件。
如果 buffer 快满了,或者到一定时间,就会将内存 buffer 数据 refresh 到一个新的 segment file 中,但是此时数据不是直接进入 segment file 磁盘文件,而是先进入 os cache 。这个过程就是 refresh。只要数据进入了OS cache那么就可以被访问到了。
每隔 1 秒钟,es 将 buffer 中的数据写入一个新的 segment file (如果 buffer 里面此时没有数据,那当然不会执行 refresh *** 作) ,每秒钟会产生一个新的磁盘文件 segment file,这个 segment file 中就存储最近 1 秒内 buffer 中写入的数据。
这里就解释了为什么叫 es 是 准实时 的? NRT,全称 near real-time。默认是每隔 1 秒 refresh 一次的,所以 es 是准实时的,因为写入的数据 1 秒之后才能被看到。可以通过 es 的 restful api 或者 java api,手动执行一次 refresh *** 作,就是手动将 buffer 中的数据刷入 os cache中(但是这样会影响ES批量插入数据的效率),让数据立马就可以被搜索到。只要数据被输入 os cache 中,buffer 就会被清空了,因为不需要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。
重复上面的步骤,新的数据不断进入 buffer 和 translog,不断将 buffer 数据写入一个又一个新的 segment file 中去,每次 refresh 完 buffer 清空,translog 保留。随着这个过程推进,translog 会变得越来越大。当 translog 达到一定长度的时候,就会触发 commit *** 作。
commit *** 作发生第一步,就是将 buffer 中现有数据 refresh 到 os cache 中去,清空 buffer。然后,将一个 commit point 写入磁盘文件,里面标识着这个 commit point 对应的所有 segment file,同时强行将 os cache 中目前所有的数据都 fsync 到磁盘文件中去。最后清空 现有 translog 日志文件,重启一个 translog,此时 commit *** 作完成。
这个 commit *** 作叫做 flush。默认 30 分钟自动执行一次 flush,但如果 translog 过大,也会触发 flush。flush *** 作就对应着 commit 的全过程,我们可以通过 es api,手动执行 flush *** 作,手动将 os cache 中的数据 fsync 强刷到磁盘上去。
translog 日志文件的作用是什么?你执行 commit *** 作之前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,无论是 buffer 还是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。所以需要将数据对应的 *** 作写入一个专门的日志文件 translog 中,一旦此时机器宕机,再次重启的时候,es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去 这里和Redis持久化机制是类似的 。
translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会丢失 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写 *** 作必须是直接 fsync 到磁盘,但是性能会差很多。
总结一下,数据先写入内存 buffer,然后每隔 1s,将数据 refresh 到 os cache,到了 os cache 数据就能被搜索到(所以我们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s,将数据写入 translog 文件(磁盘里面)(这样如果机器宕机,内存数据全没,最多会有 5s 的数据丢失),translog 大到一定程度,或者默认每隔 30mins,会触发 commit *** 作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。
可以通过 doc id 来查询,会根据 doc id 进行 hash,判断出来当时把 doc id 分配到了哪个 shard 上面去,从那个 shard 去查询。
客户端发送请求到任意一个 node,成为 coordinate node。
coordinate node 对 doc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin 随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。
接收请求的 node 返回 document 给 coordinate node。
coordinate node 返回 document 给客户端。
搜索
es 最强大的是做全文检索,就是比如你有三条数据:
java真好玩儿啊
java好难学啊
j2ee特别牛
你根据 java 关键词来搜索,将包含 java的 document 给搜索出来。es 就会给你返回:java真好玩儿啊,java好难学啊。
1 客户端发送请求到一个 coordinate node。
2 协调节点将搜索请求转发到所有的 shard 对应的 primary shard 或 replica shard,都可以。
3 query phase:每个 shard 将自己的搜索结果(其实就是一些 doc id)返回给协调节点,由协调节点进行数据的合并、排序、分页等 *** 作,产出最终结果。
4 fetch phase:接着由协调节点根据 doc id 去各个节点上拉取实际的 document 数据,最终返回给客户端。
如果是更新 *** 作,就是将原来的 doc 标识为 deleted 状态,然后新写入一条数据。
buffer 每 refresh 一次,就会产生一个 segment file,所以默认情况下是 1 秒钟一个 segment file,这样下来 segment file 会越来越多,此时会定期执行 merge。每次 merge 的时候,会将多个 segment file 合并成一个 (这里类似于Redis的RDB文件重写) ,同时这里会将标识为 deleted 的 doc 给 物理删除掉 ,然后将新的 segment file 写入磁盘,这里会写一个 commit point,标识所有新的 segment file,然后打开 segment file 供搜索使用,同时删除旧的 segment file。
ES是一个基于RESTful web接口并且构建在Apache Lucene之上的开源分布式搜索引擎。同时ES还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,能够横向扩展至数以百计的服务器存储以及处理PB级的数据。
可以在极短的时间内存储、搜索和分析大量的数据。通常作为具有复杂搜索场景情况下的核心发动机。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)