加权随机:假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上就可以了。
最小活跃数:每个服务提供者对应一个活跃数 active,初始情况下,所有服务提供者活跃数均为0。每收到一个请求,活跃数加1,完成请求后则将活跃数减1。在服务运行一段时间后,性能好的服务提供者处理请求的速度更快,因此活跃数下降的也越快,此时这样的服务提供者能够优先获取到新的服务请求。
一致性hash:通过hash算法,把provider的invoke和随机节点生成hash,并将这个 hash 投射到 [0, 2^32 - 1] 的圆环上,查询的时候根据key进行md5然后进行hash,得到第一个节点的值大于等于当前hash的invoker。
图片来自dubbo官方加权轮询:比如服务器 A、B、C 权重比为 5:2:1,那么在8次请求中,服务器 A 将收到其中的5次请求,服务器 B 会收到其中的2次请求,服务器 C 则收到其中的1次请求。
集群容错
Failover Cluster失败自动切换:dubbo的默认容错方案,当调用失败时自动切换到其他可用的节点,具体的重试次数和间隔时间可用通过引用服务的时候配置,默认重试次数为1也就是只调用一次。
Failback Cluster快速失败:在调用失败,记录日志和调用信息,然后返回空结果给consumer,并且通过定时任务每隔5秒对失败的调用进行重试
Failfast Cluster失败自动恢复:只会调用一次,失败后立刻抛出异常
Failsafe Cluster失败安全:调用出现异常,记录日志不抛出,返回空结果
Forking Cluster并行调用多个服务提供者:通过线程池创建多个线程,并发调用多个provider,结果保存到阻塞队列,只要有一个provider成功返回了结果,就会立刻返回结果
Broadcast Cluster广播模式:逐个调用每个provider,如果其中一台报错,在循环调用结束后,抛出异常。
消息队列对于MQ的作用大家都应该很了解了,削峰填谷、解耦。依赖消息队列,同步转异步的方式,可以降低微服务之间的耦合。
对于一些不需要同步执行的接口,可以通过引入消息队列的方式异步执行以提高接口响应时间。在交易完成之后需要扣库存,然后可能需要给会员发放积分,本质上,发积分的动作应该属于履约服务,对实时性的要求也不高,我们只要保证最终一致性也就是能履约成功就行了。对于这种同类性质的请求就可以走MQ异步,也就提高了系统抗压能力了。
对于消息队列而言,怎么在使用的时候保证消息的可靠性、不丢失?
消息可靠性消息丢失可能发生在生产者发送消息、MQ本身丢失消息、消费者丢失消息3个方面。
生产者丢失
生产者丢失消息的可能点在于程序发送失败抛异常了没有重试处理,或者发送的过程成功但是过程中网络闪断MQ没收到,消息就丢失了。
由于同步发送的一般不会出现这样使用方式,所以我们就不考虑同步发送的问题,我们基于异步发送的场景来说。
异步发送分为两个方式:异步有回调和异步无回调,无回调的方式,生产者发送完后不管结果可能就会造成消息丢失,而通过异步发送+回调通知+本地消息表的形式我们就可以做出一个解决方案。以下单的场景举例。
下单后先保存本地数据和MQ消息表,这时候消息的状态是发送中,如果本地事务失败,那么下单失败,事务回滚。
下单成功,直接返回客户端成功,异步发送MQ消息
MQ回调通知消息发送结果,对应更新数据库MQ发送状态
JOB轮询超过一定时间(时间根据业务配置)还未发送成功的消息去重试