公司年会有个环节是现场线上线下互动,现场会通过二维码及其他方式迅速建起一个超过5000人的群。员工会在群里分享一年来的感人故事,业绩以及对公司的祝愿,老板们可能在群里发红包,表示对员工的感谢。群里的信息会实时投影到现场的大屏幕上,同时也会推送到个人手机上。
这样一个群,短时间的消息并发量非常大,消息的延迟很难完全避免。普通消息延迟一点大家也就忍了,但是红包怎么办呢?
首先看看延迟发生在哪些环节
1、运营商基站
一些大型的聚会活动(如演唱会),我们往往能看到运营商架设的临时基站,架设基站的原因是解决固定基站容量和带宽不足的问题。现场5、6千人短时间大量使用网络的情况下,基站是可能存在一些压力的(尤其是群里大量发送照片的时候)。
2、IM系统推送
群里某人发1条消息,服务端需要向超过5000人推送。如果高峰期每秒发送20条消息(保守估计,峰值可能远不止这个数),服务器每秒需要推送10w条消息,以我们现有的资源,很难不出现延迟(采用客户端定时拉取的方式,可以极大减轻服务端压力,但是现有的软件不支持这个功能,另外定时拉取的时效性要差一些,员工互动感会下降)。即使1个红包消息,也需要进行5000次推送,这个点上也是有先有后的。
延迟很难避免,我们在推送顺序上做一些策略来尽量保证红包的公平性。
这个群里每次推送消息,推送成员的顺序都随机打乱,就不会造成某些人因为在群里位置靠前而具有优先推送的优势。
问题就转变为了寻找一种时间复杂度和空间复杂度都要很优秀的随机打乱一个数组的方法。因为并发消息量很多,时间复杂度太高速度慢;空间复杂度太大,内存开销会比较多。
Java语言里Collections类中正好提供了shuffle这个方法。下图是这个方法的核心代码
可以看到这个方法只需要遍历一次数组,进行数据位置交换。时间复杂度是O(n),空间复杂度是O(1)。
尽管对于单个红包,某些成员的推送顺序有优势(优势也是随机的),但对于多个红包,能保证不会总是某些人有优势。
消息从服务端推送出去后,到底先到达谁的手机就不好说了(网络因素太复杂)。因此,能不能抢到红包,主要还是看运气!