最近做了一个需求,需要实现一个竞价大厅,经办人开启竞价大厅后,其他人都可以进入竞价大厅进行报价,要求经办人及所有报价人都可以实时看到别人的报价。
要实现实时看到别人的报价,那就需要用长连接来实现服务端和客户端的通信,以在有新的报价时给所有连接的客户端发送通知,通知客户端刷新数据,那么服务端就需要保存客户端的会话信息,服务端是分布式应用,怎么来保存会话信息呢?首先想到的就是使用分布式缓存,但是连接信息是无法被序列化的,只能保存连接的关键信息,然后在使用时再利用这些关键信息来创建新的连接,这种办法成本比较高不推荐。 如果想避免序列化,直接缓存会话信息就得使用服务器的本地内存来保存会话信息,这就要求如果有新的报价,那么该应用的所有实例都得知道并处理,才能给所有的长连接发送更新数据的消息,这就需要用消息的发布订阅机制来实现。发布订阅模式,该主题下的所有队列都能接收并处理这个消息,为了让所有的实例都能接收并处理这个消息,那么就应该给每个实例建一个单独的队列,这样每个实例都能接收到这个消息,然后查找自己缓存的会话信息,并给客户端发送更新报价信息的通知,如果没有找到缓存的绘画信息,那么就直接忽略。这里遇到了一个坑,设计的是给每个实例的队列名称的末尾都加上machine ID来标识,以便让每个实例都有不同的队列名称,但由于服务端使用了docker进行部署,docker容器默认的machine ID是没有值的,这就导致了服务端的所有实例的队列名称都一样,进而导致只有一个实例能够收到并处理报价更新的消息,从而导致不能实现报价大厅中的所有人实时刷新报价的要求。修改起来也很简单,直接给队列名字加上了一个随机数,这样就确保了每个实例都能有唯一的队列名称,进而保证每个实例都能收到并处理报价更新的消息。