订阅发布模式应用
1. spring application publish event ContextRefreshedEvent , CustomEvent , ContextReadyEvent
2. redis 中的 订阅 channel ,当channel有变化时通知 channel的订阅者.
3. zookeeper中的watcher机制监听 某个节点的 创建 ,修改, 删除事件 , 客户端有个event listener线程不断轮询有没有服务端推送过来事件,如果收到事件就回调事件对应的回调方法
Redisson
Redisson提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期,也就是说,如果一个拿到锁的线程一直没有完成逻辑,那么看门狗会帮助线程不断的延长锁超时时间,锁不会因为超时而被释放。
默认情况下,看门狗的续期时间是30s,也可以通过修改Config.lockWatchdogTimeout来另行指定。
另外Redisson 还提供了可以指定leaseTime参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了,不会延长锁的有效期。
watch dog 在当前节点存活时每10s给分布式锁的key续期 30s;
watch dog 机制启动,且代码中没有释放锁操作时,watch dog 会不断的给锁续期;
从可2得出,如果程序释放锁操作时因为异常没有被执行,那么锁无法被释放,所以释放锁操作一定要放到 finally {} 中
如果释放锁操作本身异常了,watch dog 还会不停的续期吗?
不会,因为无论释放锁操作是否成功,EXPIRATION_RENEWAL_MAP中的目标 ExpirationEntry 对象已经被移除了,watch dog 通过判断后就不会继续给锁续期了。
Rabbitmq 消费不均衡
prefetch Count
什么是prefetch Count,先举个栗子:
假定 RabbitMQ 队列有 N 个消费队列,RabbitMQ 队列中的消息将以轮询的方式发送给消费者。
消息的数量是 M,那么每个消费者得到的数据就是 M%N。如果某一台的机器中的消费者,因为自身的原因,或者消息本身处理所需要的时间很久,消费的很慢,但是其他消费者分配的消息很快就消费完了,然后处于闲置状态,这就造成资源的浪费,消息队列的吞吐量也降低了。
这时候prefetch Count就登场了,通过引入prefetch Count来避免消费能力有限的消息队列分配过多的消息,而消息处理能力较好的消费者没有消息处理的情况。
RabbitM 会保存一个消费者的列表,每发送一条消息都会为对应的消费者计数,如果达到了所设定的上限,那么 RabbitMQ 就不会向这个消费者再发送任何消息。直到消费者确认了某条消息之后 RabbitMQ 将相应的计数减1,之后消费者可以继续接收消息,直到再次到达计数上限。这种机制可以类比于 TCP/IP 中的"滑动窗口"。
所以消息不会被处理速度很慢的消费者过多霸占,能够很好的分配到其它处理速度较好的消费者中。通俗的说就是消费者最多从 RabbitMQ 中获取的未消费消息的数量。
prefetch Count数量设置为多少合适呢?大概就是30吧
RocketMq
对延时消息机制的思考
优点:
设计简单,把所有相同延迟时间的消息都先放到一个队列中,做定时扫描,可以保证消息消费的有序性;
延时队列中的消息时按消息到期时间进行递增排序,也就是说队列中消息越靠前的到期时间越早;
缺点:
延时消息机制所有的定时任务都在一个定时器中,定时器采用的java.util.Timer,而Timer是单线程运行的;如果延迟消息的数量很大大的话,可能单线程处理不过来,也就会造成消息到期后没有及时发送出去的现象,甚至会造成消息拥堵;
可能的改进点:
- 为每个延迟队列上分别采用一个Timer;
- 或者说仅使用Timer开始定时任务做扫描,而消息处理的核心逻辑使用线程池处理,进而提高消息处理的效率;
timer 设计
基于大顶堆 小顶堆 堆排序实现任务队列 , 任务执行时间没到时 需要sleep() 或者 wait( 剩余时间)