今天有幸和一位Java老兵交流了下,受益良多。
记录下一些感悟,重新考虑两个问题 1 心跳机制 2 Redis实现分布式公平锁
平时工作中,只注重组合现有的组件去实现业务,没有深入思考这些组件在常见的场景的实现细节。今日引以为戒。
一、关于心跳机制
在广义上,心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制。
由于在长连接的场景下,客户端和服务端并不是一直处于通信状态,如果双方长期没有通讯,双方都不清楚对方目前的状态,所以需要发送一段很小的报文告诉对方 "I am alive",同时也能告诉对方当前服务依旧能正常处理检测存活逻辑。
此外,如果该长连接双方一直没有进行通讯。客户端和服务端策略
(1)服务端回收资源
服务端检测到某个客户端迟迟没有心跳过来可以主动关闭通道,让它下线;
(2)客户端重置连接
客户端检测到某个服务端迟迟没有响应心跳也能重连获取一个新的连接。
此前,参与的一个项目中,在后端使用Netty+Mina实现了一套长连接的通讯系统,服务端的心跳检测机制如下:
1 客户端向服务端建立长连接,Mina在创建长连接时会把该连接包装成一个IoSession,同时把需要空闲检测的session加入到(空闲状态检测)IdleStatusChecker的sessions集合中。
2 客户端会定时向服务端发送心跳信息 MSG_HEART_BEATING
3 服务端收到的MSG_HEART_BEATING 后回复客户端一个ACK
4 IdleStatusChecker 每隔1s中,会遍历sessions中所有的连接,通过系统当前时间来计算该连接空闲时间。
public void run() {
thread = Thread.currentThread(); try {
while (!cancelled) {
// Check idleness with fixed delay (1 second). long currentTime = System.currentTimeMillis(); notifySessions(currentTime); try {
Thread.sleep(1000); } catch (InterruptedException e) {
// will exit the loop if interrupted from interrupt() } } } finally {
thread = null; }}
5 IdleStatusChecker 计算空闲时间是否达到超时时间,超时则主动断开连接,
private static void notifyWriteTimeout(IoSession session, long currentTime) {
long writeTimeout = session.getConfig().getWriteTimeoutInMillis(); if ((writeTimeout > 0) && (currentTime - session.getLastWriteTime() >= writeTimeout) && !session.getWriteRequestQueue().isEmpty(session)) {
WriteRequest request = session.getCurrentWriteRequest(); if (req