功能需求分析

实现一个消息中心,支持消息推送,并在有新消息时更新用户的小红点数

  1. 功能需求
  • 支持实时推送
  • 支持小红点数量递增
  • 支持多用户,多维度展示小红点
  • 小红点状态的持久化(防止服务重启丢失)
  • 支持高并发与海量用户场景
  1. 非功能需求
  • 高性能:保证推送消息的低延迟
  • 高可用性:消息推送的小红点数据更新不能丢失
  • 可扩展性:支持用户增长和未来功能扩展

设计思路

  1. 核心流程
  • 消息的生

    • 消息中心接收系统的业务事件(新消息的产生)
  • 更新小红点的数量:

    • 更新小红点数据,记录用户有未读消息
  • 推送消息:

    • 将消息实时推送给用户
  • 用户读取操作:

    • 用户查看消息后,小红点数重置为0或者其他特殊状态
  1. 系统架构

核心组件和模块

模块描述实现框架或组件
消息API提供消息查询,消息发送等接口Java API
消息队列用于异步解耦消息的生成,推送和存储Kafka、RocketMQ
缓存用户快速存储用户小红点计数Redis
推送服务将新消息实时推送到用户设备WebSocket、MQTT、APNs/FCM|
数据库持久化消息内容和小红点数据MySQL、MongDB
  1. 逻辑设计
  • 消息的接收与处理

    • 消息中心接收新消息(通过Rest API、事件流等)
    • 数据消息写入数据库,使用消息队列异步处理
  • 小红点计数更新

    • 小红点计数存储在Redis中,按照用户纬度维护

        Key: unread_count:user_id
        Value: { message_type: count }
      
    • 每次新消息产生时,Redis的计数加1

        redis.hincrBy("unread_count:" + userId, messageType, 1);
      
  • 实时推送

    • 通过WebSocket或者消息队列通客户端有消息
    • 推送内容包括小红点更新和消息预览内容
  • 用户读取消息

    • 用户点击点击消息以后,标记消息为已读
    • 小红点计数清零以后,更新Redis和数据库

        redis.hset("unread_count:" + userId, messageType, 0);
      
  1. 选型和框架

    消息队列

    • Kafka:

        高吞吐量,适合日志型消息推送
        消息分区支持高并发
    • RabbitMQ:

        支持丰富的路由规则,适合复杂的推送需求
    • RocketMQ:

        天然支持事务消息和延迟消息,适合高可靠推送
      

    缓存

    • Redis:

        使用哈希表存储小红点计数,支持高效读写
        提供过期策略,可以清理长期未读数据
      

    推送技术

    • WebSocket:

        实时双向通信,适合网页和移动端
    • MQTT:

        轻量级协议,适合物联网和高并发场景
    • APNs/FCM:

        苹果和谷歌的推送服务,适合移动设备通知

      数据库

    • MySQL:

        
        存储消息内容,适合结构化查询。
      
    • MongoDB

        
        存储消息内容,支持灵活的文档型存储和查询
      

    服务框架

    • SpringBoot

        快速构建 REST API和服务逻辑
      
    • Netty

        实现高性能 WebSocket服务
      
    • Spring WebFlux

        支持非阻塞式的异步推送
      

示例代码

  1. 消息生产与小红点更新
@RestController
@RequestMapping("/message")
public Class MessageController {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @PostMapping("/send")
    public ResponseEntity<String> sendMessage(@RequestBody Message message) {
        // 1. 存储消息到数据库
        message.saveMessage(message);
        
        // 2. 更新 Redis 中的小红点计数
        String key = “unread_count:” + message.getUserId();
        redisTemplate.opsForHash().increment(key, message.getType(), 1);

        // 1和2追求接口性能的话可以做成异步
        // 3.推送消息
        notificationService.pushMessage(message);
        // 4.异步接收推送消息返回的数据
        return ReponseEntity.ok(“messgae ok”);
    }

}
  1. 小红点查询
@RestController
@RequestMapping("/notification")
public class NotificationController {
    
    @GetMapping("/unread")
    public Map<Object, Object> getUnreadCount(@RequestParam String userId) {
        String key = "unread_count:" + userId;
        return redisTemplate.opsForHash().entries(key);
    }
}
  1. 用户读取消息
@RestController
@RequestMapping("/message") 
public class ReadMessageController {
    
    @Autowired
    private RedisTemplate<Object,String> redisTemplate;

    @PostMapping("/read")
    public ResponseEntity<String> readMessage(@RequestParam String userId, @RequestParam String type) {
        // 1. 标记消息为已读(更新数据库)
        messageService.markMessagesAsRead(userId, type);
        // 2. 清零小红点计数
        String key = “unread_count:” + userId;
        redisTemplate.opsForHash().put(key, type, 0);
        return ResponseEntity.ok("Messages marked as read");
    }
}

扩展功能

  1. 消息类型区分:

    • 例如分为系统消息、订单消息、私信等,每种类型独立计数。
  2. 延迟推送:

    • 使用消息队列支持消息的延迟发送。
  3. 分组推送:

    • 支持按用户群体(如订阅相同主题)推送。
  4. 过期清理:

    • 定期清理 Redis 中长期未读的小红点计数。

未完待续。。。。。。

思路补充

  1. IM系统和消息中心解耦逻辑

    • IM和消息中心解体,IM只是消息中心的使用者
  2. 消息实体内容

    • 消息体
    • 消息未读数
    • 消息调用者
    • 消息通知方式
    • 消息发送连接方式(短链接/长链接)
  3. 消息推送客户端的感知

    • APP外推送
    • APP内推送
    • 短信
    • 站内通知
    • 私信
  4. 特殊业务推送

    • 1设备n用户推送(APP双启)
    • n设备单用户推送 -> 该用户最近最新使用设备

爱跑步的猕猴桃
1 声望0 粉丝