项目功能-消息推送 (重点)
- RPC和消息队列的对比
- 如果需要服务端立即返回结果, 最好使用RPC(效率高, 不需要中转)
- 如果不需要服务端返回结果 或者 需要减轻生产者压力, 可以使用消息队列(消费者可以执行异步任务, 减轻同一时间服务器的并发压力)
将推送消息放入消息队列中
获取用户身份
IM服务器从消息队列中获取数据
IM
- 当用户连接IM时, 取出user_id, 并进入其user_id对应的房间
- 从消息队列中取出关注通知
# 需求: 让用户id 和 sid进行绑定
# 1.获取用户id: 传递jwt
# 2.绑定用户身份
from server import sio, JWT_SECRET
from flask import Request
def _get_user_id(token): # 取出用户id
# 取出jwt中的数据
from jwt_util import verify_jwt
payload = verify_jwt(token, secret=JWT_SECRET)
if payload:
return payload.get('user_id')
else:
return None
@sio.on('connect')
def on_connect(sid, envrion):
request = Request(envrion)
token = request.args.get('token')
user_id = _get_user_id(token)
# 用户一连接im服务器, 就让其进入自己的用户id对应的房间 room="2"
print("进入房间: %s" % user_id)
sio.enter_room(sid, str(user_id))
@sio.on('disconnect')
def on_disconnect(sid):
rooms = sio.rooms(sid)
for room in rooms: # 断开连接, 离开所有的房间
sio.leave_room(sid, room)
web服务器
- 将关注通知放入消息队列, 消息发送给作者的user_id对应的房间
- 细节
- 测试 web应用必须使用生产模式,否则消息队列管理器会报错
- RabbitMQ
amqp://guest:guest@192.168.105.128:5672
上线收到通知的逻辑
1. 用户一旦连接IM,
1> 需要让user_id和sid建立关系
2> 一旦离线就删除关系
3> 关系可以存在redis中
2.web应用
1> 从redis中取user_id对应的sid
2> 如果能取出, 说明在线, 直接往消息队列中添加消息
3> 如果不能取出, 说明离线, 将消息保存到redis中
3. im应用
1> 一旦建立连接, 先从redis中查询是否有消息被保存
2> 如果有,取出并发给客户端, 取出后从redis中删除数据
3> 同时还需要从消息队列中实时取出消息数据