学习笔记 | 分布式技术
1. MQ相关
1-1. 为啥要使用MQ?
- 解耦
比如说在这个项目中,客户通过我们这个平台下订单买车后,会发短信提示他,这个发短信的动作,如果不使用mq, 要在订单支付成功时去调用发短信的接口,然后才能返回下单成功.如果以后需求改了,不要发短信了,那这时候又要去改动订单这个模块,这个设计的就很耦合.但是如果使用了mq,在下单成功后,只需要向mq发送下单成功的消息就可以了,发送短信啥的可以直接订阅这个下单成功的消息,在获取到下单成功后,调用发送短信. 以后需求更改,也不用去修改订单这个模块. - 异步
同样,还是下单这个例子,发送短信可能耗时比较长,如果写在下单的逻辑里面的话,下单耗时就会增加,实际上,下单成功不需要关注是否发送短信通知成功. - 削峰
比方说如果在某个时间点突然有大量用户访问你这个系统,如果不使用mq,这些连接可能就直接去调用业务代码,可能就会导致系统数据量太大,服务宕机,这个时候如果使用mq,用户请求先进mq,业务系统根据自己的能力从mq中获取请求,这样就避免了系统宕机.
1-2. MQ的优点和缺点
- 优点就是上面的三个:解耦,异步和削峰
- 缺点:
- 系统可用性降低,MQ一旦故障,整个依靠mq的业务都不能使用了
- 系统复杂性提高了
- 一致性问题,A系统处理完了发送消息到MQ后就直接返回成功了,用户以为这个请求就成功了,但是问题是,如果其他系统消费该消息后,如果有一个系统出现了问题,导致数据丢失,最后就会发生数据不一致的问题.
1-3. 各种MQ的比较
- ActiveMQ
- 老牌的ActiveMQ,有概率丢失数据.
- RabbitMQ
- 管理页面做的非常详细,吞吐量万级,使用erlang开发,看源码有困难.
- RocketMQ
- 阿里开源项目,吞吐量10万级别的,topic可以几百到几千个,分布式架构,可以做到消息0丢失.
- Kafka
- 支持简单的MQ功能,在大数据领域的实时计算以及日志采集方面被大规模使用.
- 总结
中小型公司,技术实力一般,吞吐量也不高,推荐使用RabbitMQ,功能完备,管理后台好用,开源社区活跃,基本遇到问题都能在网上找到答案.
大型公司,有研究和定制源码的技术,推荐使用RocketMQ,设计的比RabbitMQ好,吞吐量也更高.
大数据领域,实时计算或者日志采集方面,使用Kafka
1-4. 如何保证MQ的高可用
- RabbitMQ的普通集群模式
- 比方说有三个MQ的实例,其中只有一个实例上保存了queue的实际数据,其他的实例上只保存了queue的元数据(也就是queue的实际位置信息等)
- 普通集群模式的缺点:
- 在集群内部产生大量数据传输
- 可用性不高,保存queue数据的节点宕机了整个系统就不能用了
- RabbitMQ的镜像集群模式
- 消息会同步到每一个节点上.
- 缺点:不是分布式的集群,如果queue中消息很多,一个节点无法容纳.
- Kafka分布式集群模式
- 一个topic可以分发到几个不同的MQ节点,也就是一个topic的全部内容由这几个节点中的内容组成.每一个节点又可以设置备份节点,主节点叫做leader节点,备份节点叫做follower节点.leader节点由这几个节点选举产生.只有leader节点向外提供服务,follower节点只是用来备份.当leader节点不可用时,会由follower 节点重新选举出leader节点来提供服务.
1-5. MQ的重复消费
- 为啥会出现重复消费
- Kafka中,消费者按顺序消费消息,并定时更新当前消费完的消息的offset到zookeeper,mq从zookeeper中读取消费者已消费消息的offset,并将之后的消息发送给消费者.如果当消费者消费完消息还没发送到zookeeper时,消费者重启了,这时mq从zookeeper中获取消息的offset是之前的数据,这样就会出现重复消费的情况
- 重复消费了怎么办
- 要设计消息消费的幂等性,可以在消息中加入唯一识别字段,每次消费时判断该消息是否已经被消费过.
1-6. 消息丢失问题
- RabbitMQ如何保证数据不丢失
- 在写入消息过程中确保数据不丢失,有两种方式,开启事务和回调.
- 开启事务方式:发送消息时开启事务,如果发送失败可以回滚或者重新发送.这种方式会降低系统的吞吐量
- 回调的方式:在生产者那里提供回调方法,在消息发送后,会自动调用回调方法,在回调方法中可以设置失败重新发送等处理办法.
- 消息的持久化,防止mq意外宕机重启后数据丢失
- 消费端关闭autoAck,只有当真正处理完消息,手动发送ack给MQ
- 在写入消息过程中确保数据不丢失,有两种方式,开启事务和回调.
- Kafka如何保证数据不丢失
- 生产者发送消息后,需要确认leader和follower都写入消息才算发送成功,否则会一直重试
- 设置每个leader下至少有一个follower在正常工作
- 消费者消费成功后才手动返回消费消息的offset
1-7. 如何保证消息的顺序性
- RabbitMQ中,一个queue可能对应多个消费者,多个消费者同时从queue中消费数据,就可能出现消息的顺序性问题.
- 解决方案:
- Kafka中,可以把相同key的消息发送到同一个partition中,保证消息在mq中的有序性,但是消费者可能会使用多个线程来并发处理消息,这样也可能会出现消息的顺序性问题.
- 解决方案:
1-8. 消息队列中积压了大量数据
怎么办
1-9. 如果让你设计一个消息队列,你会怎么做
- 保证消息队列的
可扩容性
,分布式架构,一个topic可以分发到不同的partition中, - 消息的
持久化
保存,这样mq故障恢复不会丢失数据 - 保证mq的
高可用性
,可采用多副本机制,即一个leader多个follower,leader向follower同步数据,如果leader挂了,从follower中重新选举出leader - 保证mq的
数据0丢失
,在生产者端可以设计成消息发送后必须等到所有的leader和follower都写入这条消息后才算发送成功,否则就重新发送.
2. Redis
2-1. 项目中如何使用缓存的?
2-2. 为什么要使用缓存
- 高性能,
- 高并发
2-3. redis的线程模型
- redis是单线程的
- 采用IO多路复用模式,一个线程去轮询所有连接,并将轮询到的事件压入队列,由文件事件分派器从队列中去读事件并相应处理.
2-4. redis的单线程为啥还能这么快?
- redis的操作都是基于内存的
- redis的请求是非阻塞的,采用IO多路复用器模式,轮询所有连接,并将事件压入队列,由文件事件分派器从队列中读取事件并处理.
2-5. redis有哪些数据类型,分别在哪些场景下使用
- string,用来做kv缓存
- hash,用来保存简单的对象
- list,有序列表,可以用来保存文章评论信息之类,支持分页查询
- set
- sorted set
2-6. redis的过期策略有哪些,内存满了之后怎么办.
- 过期策略:redis中,数据过期后并不是直接就被删除了,redis中采用定期删除+惰性删除策略
- 定期删除:redis每隔一段时间就会去检查数据库,删除其中过期的key,并不是删除所有的过期的key,而是随机删除一部分(因为如果数据量大,遍历数据库所有过期的key消耗过大
- 惰性删除:每次查询key的数据时,先检查该key对应的数据有没有过期,如果过期就删除掉,返回null
2-7. redis内存满了怎么办
- 增加内存
- 设置redis的内存淘汰策略
- redis配置文件中的maxmemory可以设置最大内存
- maxmemory-policy可以设置当redis达到最大内存后的策略
- volatile-lru 使用lru算法删除一个最少使用的过期的键
- allkeys-lru 使用lru算法删除一个键 (建议使用这个,因为可能没有过期时间的键太多)
- volatile-random 随机删除一个过期键
- allkeys-random 随机删除一个键
- volatile-ttl 删除一个最近即将过期的键
- noenviction 不删除,只返回错误(这个是默认的策略)
- 使用redis集群
2-8. redis的主从架构
- 概述: 一个master对应多个slave节点. master节点会将数据同步给它的所有slave节点.
- slave节点启动及同步数据过程
- 当slave节点启动时,它会发送一个psync命令给master节点,
- 如果slave是第一次连接master,就会触发master的full resynchronization.master会启动一个后台线程,生成当前数据库的RDB快照文件,然后将这个RDB发送给slave节点.slave会先将这个RDB写入本地磁盘,然后再从本地磁盘加载到内存中.
- 如果这个slave节点是重新连接master节点,那么master节点就会增量复制slave缺少的数据.
- 主从复制的断点续传
- 从redis2.8开始,就支持主从复制的断点续传.如果主从复制过程中,网络连接断掉了,那么重新连接后,可以接着上次复制的地方继续复制下去,而不是从头开始复制一份.
- master节点会在内存中存一个backlog,保存了每个slave节点已经同步的数据的 replica offset.如果网络断线重新连接后,slave会让master从上次的replica offset位置开始继续复制.如果没有找到对应的offset,那么就会执行一个full resynchronization.
- 无磁盘化复制
- master在内存中直接创建RDB,然后发送给slave,不会在本地磁盘创建.
- repl-diskless-sync
- 过期key处理
- slave不会过期key,maste过期或者通过lru淘汰了一个key时,会把slave中的这个key给删除掉.
2-9. redis如何做到高可用性?
- redis采用主从架构,一个master节点可以有多个slave节点,master节点可以提供写数据服务,master会把数据向它的slave节点同步数据,slave节点只提供读服务.当master节点出现故障,redis会自动检测,并将某个slave节点自动切换为master,这个过程叫做主备切换.这样就保证了redis的高可用性.
- master节点是否可用是通过哨兵来检测的,同时主备切换过程也是通过哨兵来完成的.(哨兵的英文 sentinal)
2-10. redis的哨兵及哨兵下数据丢失问题
- 通常会启动三个哨兵进程的集群,用来管理redis的集群.哨兵会监控master集群是否故障,如果有两个或以上哨兵检测到master不可用,这时就会选取一个slave节点,将其设置为master.
- 这样就会有个问题,如果master中有数据还未同步到slave节点就挂掉了,这时候就会造成数据丢失
- 还有一种情况,master正常工作,但是哨兵和master之间网络通信出现问题,这时候哨兵以为master挂掉了,重新选举了一个slave作为master,这时候就有两个master节点在工作了,用户数据可能还是会写入到原先的master上,假如过了一段时间,哨兵又可以和原先的master通信了,它会把原先的master作为现有master的一个slave节点,这样的话,原先master中新写入的数据就会丢失了.
- 为了降低上述两个场景的数据丢失损失,可以设置master节点的最小slave 节点同步时间,也就是说如果有N个节点的连接延时都超过了M秒,那个这个master就会停止接受外来的写请求,需要下面两个配置
min-slaves-to-write 3
min-slaves-max-lag 10
- 通过上面两个配置,就表示:假如有大于等于3个从redis的连接延迟大于10秒,那么主redis就不再接受外部的写请求
2-11. redis的持久化
- redis支持两种持久化方式:RDB和AOF
2-12. 分布式搜索引擎(elasticsearch, solr,lucene)
es基本内容:
index -> type -> mapping -> document -> field
- es分布式架构如何实现的?
- es如何写入和读取的?