利用Redis发布订阅模式、SSE实现分布式实时站内信系统

文章目录

  • 前言
  • 一、SSE是什么?
  • 二、单机与集群的站内信实现方式有何区别?
  • 三、Redis 发布、订阅模式有何特点?
  • 四、代码演示
    • 1.数据模型
        • 小结
    • 2.引入依赖
    • 3.配置RedissonClient
    • 4.编写RestController用于测试
    • 5.编写用户消息订阅逻辑
    • 6.实现消息的发布
    • 7.实现广播消息的订阅
    • 8.个人与团队消息的订阅
    • 8.效果演示
  • 总结


前言

站内信功能在各大系统中被广泛应用,本文结合工作的实际场景,使用java springboot框架、Redis,探讨一种轻量化的实现分布式实时站内信系统方案。


一、SSE是什么?

 SSE (Server-sent Events )是 WebSocket 的一种轻量代替方案,可实现服务端主动向客户端推送消息,例如在扫码支付结果反馈、邮箱服务的新邮件提醒,微博的新消息推送,SSE 都是不错的选择

在Springboot框架中已经集成,无需像websocket方式一样需要单独引入依赖,相对轻量。
浏览器断线自动重连,减少了前端业务逻辑。

二、单机与集群的站内信实现方式有何区别?

单机场景下逻辑较为简单,消息的发送端和用户登录在同一个节点,程序只需要在内存中找到所需的SseEmitter对象并发送即可。但生产环境往往不会只部署一个节点,那此时用户订阅的SseEmitter对象和消息的发送端很可能不在同一个节点,假设用户订阅产生的SseEmitter对象在A节点,但是消息发送在B节点,如何让A节点感知到有实时消息并调用SseEmitter.send()发送数据,需要一套中心化的消息推送机制才能实现。

三、Redis 发布、订阅模式有何特点?

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

下图展示了客户端与频道之间的订阅关系

利用Redis发布订阅模式、SSE实现分布式实时站内信系统_第1张图片

下图展示了消息推送数据流向

利用Redis发布订阅模式、SSE实现分布式实时站内信系统_第2张图片

相对于市面上其他的主流的消息中间件产品,如Kafka、RabbitMQ、ActiveMQ, RocketMQ,Redis的订阅发布功能相对轻量,但由于其数据只在内存中分发,不持久化的特点,当客户端程序重启时可能会发生丢失在重启期间的数据的问题,所以Redis的发布订阅功能,只针对业务体量小、追求轻量化、对数据完整性要求不高的场景下比较适合使用。

四、代码演示

1.数据模型

消息发布的范围分为全体广播、工作室广播、个人私信
全体广播:所有用户都能收到消息
工作室广播:仅指定工作室内的成员能够接收到消息
个人私信:仅个人能收到消息

用户表:

利用Redis发布订阅模式、SSE实现分布式实时站内信系统_第3张图片

用户与工作室关系表:

利用Redis发布订阅模式、SSE实现分布式实时站内信系统_第4张图片
具体数据可以下载源码启动后访问:http://127.0.0.1:9090/h2

小结

用户zhangsan、lisi同属团队1,wangwu属于团队2

2.引入依赖

Redission:

 <dependency>
     <groupId>org.redisson</groupId>
     <artifactId>redisson</artifactId>
     <version>3.17.3</version>
</dependency>

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.配置RedissonClient

	@Bean
    public RedissonClient redissonClient() {
   
        Config config = new Config();
        // 单节点
        SingleServerConfig singleServerConfig = config.useSingleServer();
        singleServerConfig.setAddress("redis://127.0.0.1:6379");
        // 使用json序列化方式
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        config.setCodec(new JsonJacksonCodec(objectMapper));
        return Redisson.create(config);
    }

4.编写RestController用于测试


@Slf4j
@RequiredArgsConstructor
@RestController
public class InboxController {
   

    private final SseEmitterServer sseEmitterServer;
    private final IMsgSendService msgSendService;

    /**
     * 模拟用户上线,订阅自己的站内信,服务端返回SseEmitter对象
     *
     * @return SseEmitter对象
     */
    @GetMapping("/online/{userId}")
    public S

你可能感兴趣的:(Java,redis,redis,分布式,java)