|
ElasticSearch进阶篇集群+原理 1.相关概念解释
1 Y0 E- J6 z9 v) Y4 b6 O" e0 {0 s(1)Near Realtime(NRT):近实时,两个意思,从写入数据到数据可以被搜索到有一个小延迟(大概1秒);基于es执行搜索和分析可以达到秒级 (2)Cluster:集群,包含多个节点,每个节点属于哪个集群是通过一个配置(集群名称,默认是elasticsearch)来决定的,对于中小型应用来说,刚开始一个集群就一个节点很正常 (3)Node:节点(简单理解为集群中的一个服务器),集群中的一个节点,节点也有一个名称(默认是随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为“elasticsearch”的集群,如果直接启动一堆节点,那么它们会自动组成一个elasticsearch集群,当然一个节点也可以组成一个elasticsearch集群 (4)Index:索引(简单理解就是一个数据库),包含一堆有相似结构的文档数据,比如可以有一个客户索引,商品分类索引,订单索引,索引有一个名称。一个index包含很多document,一个index就代表了一类类似的或者相同的document。比如说建立一个product index,商品索引,里面可能就存放了所有的商品数据,所有的商品document。 (5)Type:类型(简单理解就是一张表),每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field,比如博客系统,有一个索引,可以定义用户数据type,博客数据type,评论数据type。 (6)Document&field:文档(就是一行数据),es中的最小数据单元,一个document可以是一条客户数据,一条商品分类数据,一条订单数据,通常用JSON数据结构表示,每个index下的type中,都可以去存储多个document。一个document里面有多个field,每个field就是一个数据字段。 (7)shard:单台机器无法存储大量数据,es可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个shard都是一个lucene index。 (8)replica:任何一个服务器随时可能故障或宕机,此时shard可能就会丢失,因此可以为每个shard创建多个replica副本。replica可以在shard故障时提供备用服务,保证数据不丢失,多个replica还可以提升搜索操作的吞吐量和性能。primary shard(建立索引时一次设置,不能修改,默认5个),replica shard(随时修改数量,默认1个),默认每个索引10个shard,5个primary shard,5个replica shard,最小的高可用配置,是2台服务器。 2ElasticSearch分布式架构原理
9 z# _6 U5 X1 }, y ~3 r- O2.1shad与replica机制" {) \' y! y. Y
(1)一个index包含多个shard,也就是一个index存在多个服务器上 (2)每个shard都是一个最小工作单元,承载部分数据,比如有三台服务器,现在有三条数据,这三条数据在三台服务器上各方一条. (3)增减节点时,shard会自动在nodes中负载均衡 (4)primary shard和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard (5)replica shard是primary shard的副本,负责容错,以及承担读请求负载 (6)primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改 (7)primary shard的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard (8)primary shard不能和自己的replica shard放在同一个节点上(否则节点宕机,primary shard和副本都丢失,起不到容错的作用),但是可以和其他primary shard的replica shard放在同一个节点上 2.2分布式架构图 - a4 Z' J J' ?/ |# h4 e
2.3容错机制. Q5 U9 f" T1 D2 E: @- A" @; R
在集群中会有一个master负责当leader进行协调,比如上图的Node2为master, 那么当它挂了的时候会重现选举一个新的master,比如新选举的是Node3,这个时候replica 2这时候会变成primary. 当Node2恢复了的时候,这个时候node2的prinary会变成replica 2.4ES写入数据的过程
& e% j1 P: v1 f% r8 }' D2.4.1简单流程:
O6 |' O4 X$ G. Q' k$ I2 g客户端选择一个node发送请求过去,这个node就是coordinating node (协调节点)
, J, F' \# m: b3 J5 W) q P+ A- ?- icoordinating node,对document进行路由,将请求转发给对应的node; \9 ]3 \0 y/ x9 V: y7 S
实际上的node上的primary shard处理请求,然后将数据同步到replica node
5 d% z# O2 s! N- \coordinating node,如果发现primary node和所有的replica node都搞定之后,就会返回请求到客户端
F6 w, J. `; u1 ]( ^ d0 K$ @1 l" O 这个路由简单的说就是取模算法,比如说现在有3太服务器,这个时候传过来的id是5,那么5%3=2,就放在第2太服务器 2.4.2写入数据底层原理:. M& b- c1 v* z, r* H
数据先写入到buffer里面,在buffer里面的数据时搜索不到的,同时将数据写入到translog日志文件之中- a8 W& G7 U S* |% a. |( H
如果buffer快满了,或是一段时间之后(定时),就会将buffer数据refresh到一个新的OS cache之中,然后每隔1秒,就会将OS cache的数据写入到segment file之中,但是如果每一秒钟没有新的数据到buffer之中,就会创建一个新的空的segment file,只要buffer中的数据被refresh到OS cache之中,就代表这个数据可以被搜索到了。当然可以通过restful api 和Java api,手动的执行一次refresh操作,就是手动的将buffer中的数据刷入到OS cache之中,让数据立马搜索到,只要数据被输入到OS cache之中,buffer的内容就会被清空了。同时进行的是,数据到shard之后,就会将数据写入到translog之中,每隔5秒将translog之中的数据持久化到磁盘之中& v0 _1 ^$ c1 V0 L( Y4 G3 ]) o
重复以上的操作,每次一条数据写入buffer,同时会写入一条日志到translog日志文件之中去,这个translog文件会不断的变大,当达到一定的程度之后,就会触发commit操作。
4 ?) m& u+ u% E7 a% L5 C将一个commit point写入到磁盘文件,里面标识着这个commit point 对应的所有segment file
2 K% ]4 I# b. j& T& d强行将OS cache 之中的数据都fsync到磁盘文件中去。
+ \* p3 A+ M+ q4 A: v解释:translog的作用:在执行commit之前,所有的而数据都是停留在buffer或OS cache之中,无论buffer或OS cache都是内存,一旦这台机器死了,内存的数据就会丢失,所以需要将数据对应的操作写入一个专门的日志问价之中,一旦机器出现宕机,再次重启的时候,es会主动的读取translog之中的日志文件的数据,恢复到内存buffer和OS cache之中。
& f% u6 u* k) N. y5 J将现有的translog文件进行清空,然后在重新启动一个translog,此时commit就算是成功了,默认的是每隔30分钟进行一次commit,但是如果translog的文件过大,也会触发commit,整个commit过程就叫做一个flush操作,我们也可以通过ES API,手动执行flush操作,手动将OS cache 的数据fsync到磁盘上面去,记录一个commit point,清空translog文件$ L3 d: Q$ N2 p* {
补充:其实translog的数据也是先写入到OS cache之中的,默认每隔5秒之中将数据刷新到硬盘中去,也就是说,可能有5秒的数据仅仅停留在buffer或者translog文件的OS cache中,如果此时机器挂了,会丢失5秒的数据,但是这样的性能比较好,我们也可以将每次的操作都必须是直接fsync到磁盘,但是性能会比较差。
, Z, ^& N/ E, S8 \/ D6 b如果时删除操作,commit的时候会产生一个.del文件,里面讲某个doc标记为delete状态,那么搜索的时候,会根据.del文件的状态,就知道那个文件被删除了。
& {: q4 `# w% {' [ A如果时更新操作,就是讲原来的doc标识为delete状态,然后重新写入一条数据即可。
% f4 r7 w7 b( A6 }* f6 K) ebuffer每次更新一次,就会产生一个segment file 文件,所以在默认情况之下,就会产生很多的segment file 文件,将会定期执行merge操作- {% a7 u3 X% K- m9 T
每次merge的时候,就会将多个segment file 文件进行合并为一个,同时将标记为delete的文件进行删除,然后将新的segment file 文件写入到磁盘,这里会写一个commit point,标识所有的新的segment file,然后打开新的segment file供搜索使用。9 s) E& R& Y+ m0 F( ]
2.5ES查询过程
) R6 e$ q: F6 I. R. w) ?9 E. f" u2.5.1倒排序算法
& U4 F* `/ g7 J4 f- e' J9 \查询有个算法叫倒排序:简单的说就是:通过分词把词语出现的id进行记录下来,再查询的时候先去查到哪些id包含这个数据,然后再根据id把数据查出来. 要是不理解的可以先去查下什么是倒排序 2.5.2查询过程
- ]* o2 |6 y0 I客户端发送一个请求给coordinate node
7 a* @5 |) b; R# N- K, k协调节点将搜索的请求转发给所有的shard对应的primary shard 或replica shard
4 d5 p1 ] T3 D& [' }+ Squery phase:每一个shard 将自己搜索的结果(其实也就是一些唯一标识),返回给协调节点,有协调节点进行数据的合并,排序,分页等操作,产出最后的结果
0 q! w: r# e) @1 [7 F7 yfetch phase ,接着由协调节点,根据唯一标识去各个节点进行拉去数据,最总返回给客户端
; | w4 V2 E3 @' H; c' {, X2.5.3查询原理
; q z9 ?% y' |7 V) U% _查询过程大体上分为查询和取回这两个阶段,广播查询请求到所有相关分片,并将它们的响应整合成全局排序后的结果集合,这个结果集合会返回给客户端。 查询阶段 当一个节点接收到一个搜索请求,这这个节点就会变成协调节点,第一步就是将广播请求到搜索的每一个节点的分片拷贝,查询请求可以被某一个主分片或某一个副分片处理,协调节点将在之后的请求中轮训所有的分片拷贝来分摊负载。
" t: @' E( L9 I/ [每一个分片将会在本地构建一个优先级队列,如果客户端要求返回结果排序中从from 名开始的数量为size的结果集,每一个节点都会产生一个from+size大小的结果集,因此优先级队列的大小也就是from+size,分片仅仅是返回一个轻量级的结果给协调节点,包括结果级中的每一个文档的ID和进行排序所需要的信息。& N! P% Y" {6 u7 @& E
协调节点将会将所有的结果进行汇总,并进行全局排序,最总得到排序结果。' m" }# Z# }, a; a' q* d
取值阶段 查询过程得到的排序结果,标记处哪些文档是符合要求的,此时仍然需要获取这些文档返回给客户端: D, S3 ?" h: |' P
协调节点会确定实际需要的返回的文档,并向含有该文档的分片发送get请求,分片获取的文档返回给协调节点,协调节点将结果返回给客户端* u1 c# w, O. i* l4 ~
2.6更新过程
7 y- N' ^; V0 I! o3 y2 W6 z2.6.1document的全量替换
7 e, O! J, _, q这个就是用新的数据全部覆盖以前的数据
9 n# I+ ]# l( F* o! S" W- j重新创建一个document并把原来的标记为delete) P( T. z' b/ s1 |
partial update, 就是制定需要更新的字段. 全量是把数据找出来,然后再java代码中进行修改,再放回去. partial是直接提交需要修改的字段然后直接修改,在一个shard中进行,内部也是全量替换. 8 [/ ]% f3 E- R
2.6.2强制创建' [7 S* q! k7 \* {: R" b
就是不管原来的数据,直接强制创建一个新的 2.7删除过程0 G; l0 h( W: L! \
当要进行删除document的时候,只是把它标记为delete,当数据到达一定的时候再进行删除, 有点像JVM中标记清除法 3.Es并发解决方案( ~ y4 ]: u9 P$ P8 c' e
为什么会出现并发问题,简单的说就是多个线程去操作同一个数据. 假如现在下单系统下2单,都要去减库存(100件),第一个线程进去减1件100-1=99,这时候还没更像到ES中,第二线程进去了,也要减一个库存100-1=99.现在系统卖出去2个,可是库存却还有99个,应该是98个 3.1解决方案-悲观锁
+ P8 P8 k; b9 W* ^/ I3.2解决方案-乐观锁2 y. L# q- e9 g# `
温馨提示,乐观锁会出现ABA情况 下面是2种解决方案,在网上找的图片:
4 d* ~8 A, Z9 K' b, S" T
+ C8 Q' x; {5 }6 _ |