1 为什么使用分布式系统?
单体式架构风险高,每次需要完全更新,容易引来大规模问题,不够稳定;而分布式系统易于扩展,根据业务场景进拆分,发布的可以是单个服务,对已有功能影响较小;即使有业务出现问题,也易于排查,而且有些模块访问量高,有些访问量低,可以针对性的进行扩展,访问量高的部署在多个机器上。同样系统会越来越复杂,迭代成本高,版本维护复杂,还有cap问题,数据一致性问题等,所有需要辩证看待。
2 rpc怎么理解?
rpc顾名思义,就是调用其他机器上的接口如同调用本地接口一样,那么需要知道接口的ip地址,端口,服务名,这些东西被统一管理在注册中心,调用方去注册中心查要是用服务,然后去调用
3 注册中心挂了,服务之间是否还能互相调用?
这个要分情况看待,首先注册中心可以集群部署,有相应的备份,其次如果数据库挂了,注册中心有缓存,如果注册中心服务挂了,那么对应的服务也都有服务缓存,只要相应的服务没有下线就可以继续使用。
4 CAP
提升可用性A 一般通过增加缓存,增加服务器,引入消息队列
提升容错性P 增加集群部署,都有备份,容灾备份
提高数据一致性C
分布式数据库就是牺牲一致性,满足高可用性和容错性,尤其是要求高可用性,解决高可用性主要就是备胎要多
5 负载均衡策略
应用及负载均衡:
轮询策略,随机策略 加权策略
多个方式配合使用 轮询加权等
相应时间+权重策略
网关级负载策略:
gateway
nginx 反向代理 请求先转发到nginx上面然后nginx再进行转发
6 服务熔断
熔断器根据服务调用失败率来判断,如果一个服务短时间内失败率很高就被判定为不可用,就会断开服务,防止发生更严重的问题(雪崩);熔断器有重试机制,5秒内,如果失败率降低就会关掉熔断机制,恢复服务;熔断往往和降级一起使用,一旦发生熔断,就会使用一些降级方法比如getfallback(提示用户稍后重试等),比如redis服务挂了, 可以使用备胎用其他资源代替服务(ES elasticsearch,或者本地缓存 guava)开源熔断器 hystrix sentinel等
7 高并发问题:
线程隔离:主要原理是不通的方法使用不同的线程池进行隔开,防止所有的方法相互影响,没有可调用线程,防止访问量大的方法占用所有线程
信号量隔离: 线程池隔离比较重,适用于查询量比较大,计算比较复杂的情况;信号量隔离比较轻量化,适合计算量小的业务,轻量化查询等,;也适用于网关层使用,在网关层直接用信号量对流量进行控制
8 消息队列
原理: 消费者生产者模式;
用处:可以用来异步处理 流量削峰 应用解耦
问题:双刃剑 带来的复杂度翻一倍 ,会带来三个方面的问题:可用性问题,一致性问题,复杂性问题
如何处理重复消息?
什么情况会产生重复消息:1 比如生产者发给broker的过程中,broker写入之后,如果broker的响应慢了,触发了了生产者的消息补偿那么就会导致消息重复;2在消费者消费阶段,如果消费者正确处理完消息,需要更新consumeroffset,但是还没来得及更新,消费者挂了, 那么新来一个消费者会重复消费一次同一消息
解决办法就是对接口做幂等设计
如何保证消息没有重复消费?
在发送方为了防止消息丢失,会做消息补偿,消费方响应超时,网络抖动,mq挂了等,导致发送方长时间拿不到消息的回复,就会尝试重发一遍消息:解决办法是做好接口的幂等设计;
幂等设计方案:1进行约束控制,在数据库层面做unique索引,在redis层面做sennx约束控制,来进行唯一性控制;2设置前置条件,处理之前加一个查询,查看是否操作成功,另外这个查询需要加分布式锁,防止有并发问题,或者利用数据库版本号进行对比查询;3 消息设置全局id(比较复杂),可以多个方案配合使用
怎么处理消息丢失的情况?
通过三个阶段保证,分别是消息--->
生产阶段:消息确认机制,保证消息发送到broker 阶段,会用到一些消息补偿机制
存储阶段:使用持久化存储机制(除非是网络故障等,暴力性问题)
消费阶段:通过消息确认机制,会用到消息补偿机制
消息丢失的兜底方案:1 使用拦截器(用到aop原理)记录版本号,消息消费时查看是否版本号连续来做一次double check 2 使用状态码,定时(cron)检测订单或者事件有没有正常变化,从而使用一些处理手段,也是一种double check方案
如何保证消息不丢失?
三个方面:1生产者处理好各类异常问题,比如callback中的trycatch处理,做好上报; 2存储阶段需要注意先落盘再给生产者响应; 3 消费阶段,在消费者执行完业务逻辑,在给broker相应
怎么保证消息传递的顺序性?
全局有序以及局部有序,绝大多数场景只需要局部有序
将有关联关系的消息放到同一个队列中去,保证消息消费的顺序性,要注意多线程问题
消息队列,消费积压如何解决?
如果是生产者的问题,那么利用限流熔断策略,减少源头产生的消息数量,比如令牌通算法
如果是消费端的问题,那么加快消费速度,优化代码逻辑解决bug,如果瓶颈在数据库,那就先存redis,等到不忙再做持久化存储,可以做批处理增加速度,最后可以考虑扩容;
死信队列:指消息队列中无法消费的消息,比如过期的消息会被放到死信队列中;死信队列的另一个用处是可以用来处理延迟消息
消息队列中的事务性问题?
相当于有一个协调者保证所有消息全部成功或者全部失败
协调者可以采用tcc机制 try confirm commit
用来解决一致性问题;比如用户下单的场景下:先发送一个隐藏的消息(也叫半消息,在broker 中只是一个日志记录,还没有完全存储下来,rocktmq中叫commitlog),如果用户下单成功(生产端业务执行成功之后),再从commitlog中捞出来,该消息转为普通消息,再由broker将消息转到消费端进行消费 否则,回滚所有操作,删除该隐藏消息。
消息队列挂了,事务如何处理?
利用数据库的事务机制,使用本地数据表,把本地事务操作和本地消息插入做成同一个事务;同时后台起一个线程关注本地数据表每条数据的状态,进行相应的回滚或者重试操作
刚性事务和柔性事务?
刚性是指强一致性,任何时间点所有节点都是一致性的,比如xa;问题是会有性能的影响,因为需要锁住所有的资源,高并发场景使用不多
柔性是指不要求强一致性,要求最终一致性,不追求所有节点在所有时间都保持一致,但是最终要保持一致。
消息队列选型? kafka rocketmq rabbitmq
互联网,电商平台 低时延可以选择rocketmq java实现,每秒几十万级处理量
处理大批量数据同步 离线计算 对延迟有一定包容性 兼容性好 选择kafka
如何设计一个消息队列?
需要考虑消费者,生产者,存储,路由,分发,消息类型,保障机制
如何理解消息队列的推push pull拉模式
一般生产者与broker之间都是推模式;
消费者与broker之间可以使用推模式也可以使用拉模式;
rabbitmq默认是推模式,优点是实时性比较好,也可能带来消费堆积的问题
kafka rocketmq默认采用拉模式,优点是可以控制消费的消息数量,不易产生消息堆积,问题是实时性不够高,解决办法是长轮训方式,如果有消息就返回,如果没有没有就等到超时,超时之后断开连接,之后再重新连接
9 分布式数据库——数据库分库分表
为什么要分库分表?
sql查询变慢,单表数据达到1000w条以上,需要考虑分库分表
水平拆分,就是分表之后,可以减少写操作的范围,建立索引以及查询的速度都会变快
分库 就是一主多从读写分离
分库分表可能带来的问题?
1) 不能join 一般使用数据冗余的策略解决,多加一行重复的数剧
2)id自增不能使用数据库自增序列了,需要使用uuid snowflake leaf redis的incre等
3)需要重新分表,需要重新刷盘
4)同步带来的分布式事务的问题 主要使用tcc机制解决 也可以使用xa 开源框架seata bytetcc等
5)分页查询 需要根据分表策略以及查询逻辑具体情况具体分析 提前复杂查询逻辑,提前查询好,做好缓存逻辑
6) 查询优化,将数据提前存储到redis es等内存数据库中,提升查询速度;
自增id序列如何处理?
1)分表之后间隔递增
2)使用redis的incre,有可能redis服务会挂,挂了之后可以使用aof继续递增
3)snowflake 雪花算法,公认方案,核心由三部分组成时间戳+机器+序号,可能存在的问题是时间回拨;
数据库分库之后的问题
分库可以带来数据库的读写分离,一主多从,主库可读可写,从库只能读,数据来源于主库的同步
mysql 使用binlog进行主从同步,从库有多个可以设置负载均衡策略
为什么禁止使用select *?
1)无法使用索引,会导致查询性能很差;
2)select * 比较耗时,会拖垮整个数据库的查询效率,阻塞所有的查询线程;
10 分布式事务
分布式主流的实现方案有两种---->
1)xa协议,原理是两阶段提交,依赖数据库本身的事务,事务开启前,分布式事务管理器先询问所有的数据库是否准备好,如果所有的都回复ok,那么就执行事务,如果有一个没有回复ok那么就会滚事务;缺点是效率不是很高
2)tcc 不依赖数据库本身的事务,分为三个阶段try confirm cancle,try阶段做检测和资源预留;confirm阶段做具体业务操作,如果遇到错误就直接回滚,通过补偿机制实现回滚操作;使用较广泛
11 如何设计秒杀系统?
1)静态资源 + 做好多级缓存(本地缓存+redis缓存)
2)前端页面级限流,后端网关层做限流算法令牌桶,漏桶等,规定周期放一定流量进来,其他消息直接返回网络繁忙等,开启熔断机制兜底
3)使用分布式锁(redis zookper)做好库存的原子扣减,或者使用数据库的触发器
12 分布式系统下的鉴权认证方案
基于token方案,第一次认证登录生成token客户端和服务端都存下来,客户端每次请求都带上,服务端存在redis里面
13 nginx如何实现高可用
nginx理论山支持5w并发链接
1)一般使用nginx+keep alive ,一主一从,如果主节点挂了,把备用的nginx节点顶上来,缺点是,从服务器可能一直闲置,解决办法是互为主备
2)集群部署,可以使用LVS,理论上可以支持几十万的并发请求 阿里的SLB负载均衡策略,云服务器不支持虚拟ip,硬件负载F5
14 分布式锁
通过redis实现
如何解决死锁问题
原因:加锁之后各种原因导致没有正常释放锁
解决:保证锁正常释放 1删除锁的key,需要注意是否是当前线程加的锁,判断锁是否被占用 使用lua脚本保证操作的原子性 2 设置过期时间 需要保证操作原子性
分布式锁超过过期时间,需要增加守护线程(watch dog)轮询业务是否处理完,没有处理完给锁续命
15 分布式场景在的调度框架
1)阿里云 schedulex
2)quarts
3)大众点评徐雪里 xxl-job
4)当当 elasticjob
5
5
网友评论