1,采用的是mongdB存储,普通的mysql难以支撑
2,mongdB搞冷热分离,但是考虑到大型web项目也难以支撑一条公告发送百万数据,采用消息队列细睡长流慢慢的写入mongdb
3,使用异步线程的方式往消息队列发送消息
4,系统的消息存储的消息队里上,只是用他过渡,消息最终还是存储到数据上,这样就可以用户登录的时候异步从队列取出消息,然后存储到数据库,最后在把队列删除。
业务:
系统登录:
用户登录的时候可以异步从队列收取消息
轮询接受消息:
系统5分钟轮询查询一次消息,异步从队列中获取消息,把lastFlag设置为true代表新接受的消息,当查询数据库中有多少条消息的把lastFlag改成false,修改了多少就代表新接受了多少消息。
修改用户资料:
修改过后,修改通知消息从队列取出,首页轮询查询出系统提示
什么时候使用异步和同步?
只要跟前端没关系的消息收发,用异步的都可以,比如系统之间的消息收发,用异步就很恰当。但是跟前端有关,因为HTTP协议是短连接,所以这次刷新页面就应该明确知道接收了多少条消息。如果用异步,HTTP连接都断开了,后端才刷到消息,怎么能推送给前端页面?所以必须要用同步的。消息没收完,就别切断HTTP连接。
总结:因为http是短链接,如果使用异步的话,还等等待接受消息,消息没有收取完成就会切断。
项目中使用的异步线程,同步mq
这里有两种异步方式:MQ的异步和线程执行的异步。MQ的异步更像是挂载后台阻塞运行,没收到消息也不退出,一直在后端运行。这种方式肯定不妥,所以我们选择的是MQ同步执行,收完消息就退出。线程池方面,我们选择的是异步线程执行MQ的同步接收消息。如果用MQ的异步方式,一直阻塞下去,线程池的线程永远不放回到线程池,线程池很快就被耗光
总结:
这里简单的总结就是使用异步线程池,去执行mq同步接受的消息,这样执行完之后就会放回去,不会导致线程池的线程耗光。
RabbitMQ的API分成阻塞和非阻塞
Message集合uuid设计
比如5分钟来了一堆消息。其中一个消息没有在这5分钟消费者还有没有消费,但是又来了一个轮询会接受两个一样的消息所以使用uuid来辨别重复。
业务实现:
分页查询查询显示,这个使用连表查询,显示到页面。这里主要Aggregation
构建集合连接。调用mongoTemplate.aggregate()
,查询出连接的所有消息,之后遍历每一个消息,拼接map中显示页面。
根据id查询:
mongoTemplate.findById()
根据id查询,在修改:
mongoTemplate.updateFirst()
根据id删除:
mongoTemplate.remove
保存
mongoTemplate.save
刷新用户的消息: 比如用户登录的时候发送了一条系统通知,保存到了mongdb对象中,调用mq收取消息保存到mongdb中,发送消息主体,附属message集合主键,发送消息。
轮询的时候异步线程线程,同步mq收取mq队列中的消息,获取队列中的消息的时候,收取的时候保存到message_ref集合中,并把收取消息改为true,此时也在同时进行查询数量就是把true改为false,最后返回查询的数量。
总结:
-
发送通知到mq队列
-
定时轮询接受消息,并查询新接受消息的数量(根据lastFlag属性标记来查询数量)
-
其他都是一些增删改查