docs(es/mq): update doc description

更新文档知识点描述
This commit is contained in:
yanglbme 2018-12-05 20:52:54 +08:00
parent 929342d26b
commit 7b8ce84104
6 changed files with 22 additions and 20 deletions

View File

@ -13,7 +13,7 @@ es 的分布式架构原理能说一下么es 是如何实现分布式的啊
## 面试题剖析
ElasticSearch 设计的理念就是分布式搜索引擎,底层其实还是基于 lucene 的。核心思想就是在多台机器上启动多个 es 进程实例,组成了一个 es 集群。
es 中存储数据的**基本单位是索引**,比如说你现在要在 es 中存储一些订单数据,你就应该在 es 中创建一个索引order_idx,所有的订单数据就都写到这个索引里面去,一个索引差不多就是相当于是 mysql 里的一张表。
es 中存储数据的**基本单位是索引**,比如说你现在要在 es 中存储一些订单数据,你就应该在 es 中创建一个索引 `order_idx`,所有的订单数据就都写到这个索引里面去,一个索引差不多就是相当于是 mysql 里的一张表。
```
index -> type -> mapping -> document -> field。
@ -25,14 +25,14 @@ index 相当于 mysql 里的一张表。而 type 没法跟 mysql 里去对比,
所以就会在订单 index 里,建两个 type一个是实物商品订单 type一个是虚拟商品订单 type这两个 type 大部分字段是一样的,少部分字段是不一样的。
很多情况下,一个 index 里可能就一个 type但是确实如果说是一个 index 里有多个 type 的情况,你可以认为 index 是一个类别的表具体的每个type 代表了具体的一个 mysql 中的表。每个 type 有一个 mapping如果你认为一个 type 是一个具体的一个表index 代表多个 type 的同属于的一个类型mapping 就是这个 type 的**表结构定义**,你在 mysql 中创建一个表,肯定是要定义表结构的,里面有哪些字段,每个字段是什么类型。实际上你往 index 里的一个 type 里面写的一条数据,叫做一条 document一条 document 就代表了 mysql 中某个表里的一行,每个 document 有多个 field每个 field 就代表了这个 document 中的一个字段的值。
很多情况下,一个 index 里可能就一个 type但是确实如果说是一个 index 里有多个 type 的情况,你可以认为 index 是一个类别的表,具体的每个 type 代表了具体的一个 mysql 中的表。每个 type 有一个 mapping如果你认为一个 type 是一个具体的一个表index 代表多个 type 的同属于的一个类型mapping 就是这个 type 的**表结构定义**,你在 mysql 中创建一个表,肯定是要定义表结构的,里面有哪些字段,每个字段是什么类型。实际上你往 index 里的一个 type 里面写的一条数据,叫做一条 document一条 document 就代表了 mysql 中某个表里的一行,每个 document 有多个 field每个 field 就代表了这个 document 中的一个字段的值。
![es-index-type-mapping-document-field](/img/es-index-type-mapping-document-field.png)
接着你搞一个索引,这个索引可以拆分成多个 `shard`,每个 shard 存储部分数据。
你搞一个索引,这个索引可以拆分成多个 `shard`,每个 shard 存储部分数据。
接着就是这个 shard 的数据实际是有多个备份,就是说每个 shard 都有一个 `primary shard`,负责写入数据,但是还有几个 `replica shard`。primary shard 写入数据之后,会将数据同步到其他几个 replica shard 上去。
接着就是这个 shard 的数据实际是有多个备份,就是说每个 shard 都有一个 `primary shard`,负责写入数据,但是还有几个 `replica shard``primary shard` 写入数据之后,会将数据同步到其他几个 `replica shard` 上去。
![es-cluster](/img/es-cluster.png)
@ -42,4 +42,6 @@ es 集群多个节点,会自动选举一个节点为 master 节点,这个 ma
如果是非 master节点宕机了那么会由 master 节点,让那个宕机节点上的 primary shard 的身份转移到其他机器上的 replica shard。接着你要是修复了那个宕机机器重启了之后master 节点会控制将缺失的 replica shard 分配过去,同步后续修改的数据之类的,让集群恢复正常。
说得更简单一点,就是说如果某个非 master 节点宕机了。那么此节点上的 primary shard 不就没了。那好master 会让 primary shard 对应的 replica shard在其他机器上切换为 primary shard。如果宕机的机器修复了修复后的节点也不再是 primary shard而是 replica shard。
其实上述就是 ElasticSearch 作为一个分布式搜索引擎最基本的一个架构设计。

View File

@ -1,7 +1,7 @@
## lucene 和 es 的前世今生
lucene 是最先进、功能最强大的搜索库。如果直接基于 lucene 开发,非常复杂,即便写一些简单的功能,也要写大量的 Java 代码,需要深入理解原理。
elasticsearch 基于lucene隐藏了 lucene 的复杂性,提供了简单易用的 restful api / Java api接口另外还有其他语言的 api接口
elasticsearch 基于 lucene隐藏了 lucene 的复杂性,提供了简单易用的 restful api / Java api 接口(另外还有其他语言的 api 接口)。
- 分布式的文档存储引擎
- 分布式的搜索引擎和分析引擎
@ -40,7 +40,7 @@ Node 是集群中的一个节点,节点也有一个名称,默认是随机分
类型,每个索引里可以有一个或者多个 typetype 是 index 的一个逻辑分类,比如商品 index 下有多个 type日化商品 type、电器商品 type、生鲜商品 type。每个 type 下的 document 的 field 可能不太一样。
### shard
单台机器无法存储大量数据es 可以将一个索引中的数据切分为多个 shard分布在多台服务器上存储。有了 shard 就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个 shard 都是一个lucene index。
单台机器无法存储大量数据es 可以将一个索引中的数据切分为多个 shard分布在多台服务器上存储。有了 shard 就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个 shard 都是一个 lucene index。
### replica
任何一个服务器随时可能故障或宕机,此时 shard 可能就会丢失,因此可以为每个 shard 创建多个 replica 副本。replica 可以在 shard 故障时提供备用服务,保证数据不丢失,多个 replica 还可以提升搜索操作的吞吐量和性能。primary shard建立索引时一次设置不能修改默认 5 个replica shard随时修改数量默认 1 个),默认每个索引 10 个 shard5 个 primary shard5个 replica shard最小的高可用配置是 2 台服务器。

View File

@ -19,7 +19,7 @@ es 写入数据的工作原理是什么啊es 查询数据的工作原理是
可以通过 `doc id` 来查询,会根据 `doc id` 进行 hash判断出来当时把 `doc id` 分配到了哪个 shard 上面去,从那个 shard 去查询。
- 客户端发送请求到**任意**一个 node成为 `coordinate node`
- `coordinate node``doc id` 进行哈希路由,将请求转发到对应的 node此时会使用 `round-robin` **随机轮询算法**,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。
- `coordinate node``doc id` 进行哈希路由,将请求转发到对应的 node此时会使用 `round-robin` **随机轮询算法**,在 `primary shard` 以及其所有 replica 中随机选择一个,让读请求负载均衡。
- 接收请求的 node 返回 document 给 `coordinate node`
- `coordinate node` 返回 document 给客户端。
@ -34,7 +34,7 @@ j2ee特别牛
你根据 `java` 关键词来搜索,将包含 `java``document` 给搜索出来。es 就会给你返回java真好玩儿啊java好难学啊。
- 客户端发送请求到一个 `coordinate node`
- 协调节点将搜索请求转发到**所有**的 shard 对应的 primary shard 或 replica shard都可以。
- 协调节点将搜索请求转发到**所有**的 shard 对应的 `primary shard``replica shard`,都可以。
- query phase每个 shard 将自己的搜索结果(其实就是一些 `doc id`)返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。
- fetch phase接着由协调节点根据 `doc id` 去各个节点上**拉取实际**的 `document` 数据,最终返回给客户端。

View File

@ -5,9 +5,9 @@
其实这个也是用 MQ 的时候必问的话题,第一看看你了不了解顺序这个事儿?第二看看你有没有办法保证消息是有顺序的?这是生产系统中常见的问题。
## 面试题剖析
我举个例子,我们以前做过一个 mysql binlog 同步的系统压力还是非常大的日同步数据要达到上亿。mysql -> mysql常见的一点在于说大数据 team就需要同步一个 mysql 库过来,对公司的业务系统的数据做各种复杂的操作。
我举个例子,我们以前做过一个 mysql `binlog` 同步的系统压力还是非常大的日同步数据要达到上亿。mysql -> mysql常见的一点在于说大数据 team就需要同步一个 mysql 库过来,对公司的业务系统的数据做各种复杂的操作。
你在 mysql 里增删改一条数据,对应出来了增删改 3 条`binlog`,接着这三条`binlog`发送到 MQ 里面,到消费出来依次执行,起码得保证人家是按照顺序来的吧?不然本来是:增加、修改、删除;你楞是换了顺序给执行成删除、修改、增加,不全错了么。
你在 mysql 里增删改一条数据,对应出来了增删改 3 条 `binlog`,接着这三条 `binlog` 发送到 MQ 里面,到消费出来依次执行,起码得保证人家是按照顺序来的吧?不然本来是:增加、修改、删除;你楞是换了顺序给执行成删除、修改、增加,不全错了么。
本来这个数据同步过来,应该最后这个数据被删除了;结果你搞错了这个顺序,最后这个数据保留下来了,数据同步就出错了。
@ -26,5 +26,5 @@
![rabbitmq-order-2](/img/rabbitmq-order-2.png)
#### kafka
一个 topic一个 partition一个 consumer内部单线程消费写 N 个内存 queue然后 N 个线程分别消费一个内存 queue 即可。
![kafka-order-2](/img/kafka-order-2.png)
一个 topic一个 partition一个 consumer内部单线程消费写 N 个内存 queue然后对于 N 个线程,每个线程分别消费一个内存 queue 即可。
![kafka-order-2](/img/kafka-order-2.png)

View File

@ -14,7 +14,7 @@
#### 生产者弄丢了数据
生产者将数据发送到 RabbitMQ 的时候,可能数据就在半路给搞丢了,因为网络啥的问题,都有可能。
生产者将数据发送到 RabbitMQ 的时候,可能数据就在半路给搞丢了,因为网络问题啥的,都有可能。
此时可以选择用 RabbitMQ 提供的事务功能,就是生产者**发送数据之前**开启 RabbitMQ 事务`channel.txSelect`,然后发送消息,如果消息没有成功被 RabbitMQ 接收到,那么生产者会收到异常报错,此时就可以回滚事务`channel.txRollback`,然后重试发送消息;如果收到了消息,那么可以提交事务`channel.txCommit`。
```java
@ -47,7 +47,7 @@ channel.txCommit
- 创建 queue 的时候将其设置为持久化<br>
这样就可以保证 RabbitMQ 持久化 queue 的元数据,但是不会持久化 queue 里的数据。
- 第二个是发送消息的时候将消息的`deliveryMode`设置为 2<br>
- 第二个是发送消息的时候将消息的 `deliveryMode` 设置为 2<br>
就是将消息设置为持久化的,此时 RabbitMQ 就会将消息持久化到磁盘上去。
必须要同时设置这两个持久化才行RabbitMQ 哪怕是挂了,再次重启,也会从磁盘上重启恢复 queue恢复这个 queue 里的数据。
@ -80,12 +80,12 @@ RabbitMQ 如果丢失了数据,主要是因为你消费的时候,**刚消费
所以此时一般是要求起码设置如下 4 个参数:
- 给 topic 设置 replication.factor 参数:这个值必须大于 1要求每个 partition 必须有至少2个副本。
- 在 Kafka 服务端设置 min.insync.replicas 参数:这个值必须大于 1这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower 吧。
- 在 producer 端设置 acks=all这个是要求每条数据必须是**写入所有 replica 之后,才能认为是写成功了**。
- 在 producer 端设置 retries=MAX很大很大很大的一个值无限次重试的意思这个是**要求一旦写入失败,就无限重试**,卡在这里了。
- 给 topic 设置 `replication.factor` 参数:这个值必须大于 1要求每个 partition 必须有至少2个副本。
- 在 Kafka 服务端设置 `min.insync.replicas` 参数:这个值必须大于 1这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower 吧。
- 在 producer 端设置 `acks=all`:这个是要求每条数据,必须是**写入所有 replica 之后,才能认为是写成功了**。
- 在 producer 端设置 `retries=MAX`(很大很大很大的一个值,无限次重试的意思):这个是**要求一旦写入失败,就无限重试**,卡在这里了。
我们生产环境就是按照上述要求配置的,这样配置之后,至少在 Kafka broker 端就可以保证在 leader 所在 broker 发生故障,进行 leader 切换时,数据不会丢失。
#### 生产者会不会弄丢数据?
如果按照上述的思路设置了 ack=all一定不会丢要求是你的 leader 接收到消息,所有的 follower 都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试,重试无限次。
如果按照上述的思路设置了 `ack=all`,一定不会丢,要求是,你的 leader 接收到消息,所有的 follower 都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试,重试无限次。

View File

@ -10,7 +10,7 @@
关于这个事儿,我们一个一个来梳理吧,先假设一个场景,我们现在消费端出故障了,然后大量消息在 mq 里积压,现在出事故了,慌了。
### 大量消息在 mq 里积压了几个小时了还没解决
几千万条数据在MQ里积压了七八个小时从下午 4 点多,积压到了晚上 11 点多。这个是我们真实遇到过的一个场景,确实是线上故障了,这个时候要不然就是修复 consumer 的问题,让它恢复消费速度,然后傻傻的等待几个小时消费完毕。这个肯定不能在面试的时候说吧。
几千万条数据在 MQ 里积压了七八个小时,从下午 4 点多,积压到了晚上 11 点多。这个是我们真实遇到过的一个场景,确实是线上故障了,这个时候要不然就是修复 consumer 的问题,让它恢复消费速度,然后傻傻的等待几个小时消费完毕。这个肯定不能在面试的时候说吧。
一个消费者一秒是 1000 条,一秒 3个 消费者是 3000 条,一分钟就是是 18 万条。所以如果你积压了几百万到上千万的数据,即使消费者恢复了,也需要大概 1 小时的时间才能恢复过来。