利用redis广播在多实例间做事件通知

有些小量数据其实也并非放在redis这样的缓存里的,因为数据量百万千万时,若是要比对数据,岂不是要让这个小数据和大数据进行百万千万次的交互比对。那就不如把小数据提前加载到本地内存或者缓存,如果小数据需要更新,则可以定时job更新或者手动用接口更新,或者数据发生变化时调用更新。可是如果你的服务部署在两台,三台,四台···服务器上呢,客户端请求过来时,被nginx反向代理等等负载均衡到其中某一台服务器,那么你的本地缓存刷新只会在这一台更新。如果场景等不及每台服务器上的缓存数据被定时任务刷新,那么就需要借助一些广播

其实逃不掉某些东西。不用全局的,就还得用能够全局的东西来告诉各个本地。无论你是用kafka生产者发到topic上,然后每台服务器上监听消费这个topic信息,从而知道某台服务器的内存/缓存刷新了,我们也刷新。或者用redis广播推送,然后各个地方订阅了解到有刷新动向,那就也同步刷新。具体的还要看项目


这里我举例一下redis的情况吧:

引入 Redis 依赖: 在 pom.xml 文件中添加 Redis 依赖:

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

配置 Redis: 在 application.yml 中添加 Redis 配置:

spring:
  redis:
    host: localhost
    port: 6379

创建 Redis 发布者:

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class RedisPublisherService {
    private final StringRedisTemplate redisTemplate;

    public RedisPublisherService(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public void publishRefreshMessage() {
        redisTemplate.convertAndSend("refreshChannel", "refresh");
    }
}

Redis 订阅者:

import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Service;

@Service
public class RedisSubscriberService implements MessageListener {
    private final ShieldDidAndModelCache shieldDidAndModelCache;

    public RedisSubscriberService(ShieldDidAndModelCache shieldDidAndModelCache) {
        this.shieldDidAndModelCache = shieldDidAndModelCache;
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String msg = new String(message.getBody());
        if ("refresh".equals(msg)) {
            shieldDidAndModelCache.loadShieldDidCache();
            shieldDidAndModelCache.loadShieldModelCache();
        }
    }
}

配置 Redis 消息监听器: 在配置类中配置 Redis 消息监听器。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

@Configuration
public class RedisConfig {

    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                                   MessageListenerAdapter listenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(listenerAdapter, new ChannelTopic("refreshChannel"));
        return container;
    }

    @Bean
    public MessageListenerAdapter listenerAdapter(RedisSubscriberService subscriberService) {
        return new MessageListenerAdapter(subscriberService);
    }
}

在需要刷新时发送消息: 在需要主动刷新时调用 RedisPublisherService 的 publishRefreshMessage 方法。

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;

@RestController
public class RefreshController {
    private final RedisPublisherService redisPublisherService;

    public RefreshController(RedisPublisherService redisPublisherService) {
        this.redisPublisherService = redisPublisherService;
    }

    @PostMapping("/refresh")
    public ResponseEntity<String> refresh() {
        redisPublisherService.publishRefreshMessage();
        return ResponseEntity.ok("Refresh message sent");
    }
}

通过以上配置,当你在任意一台服务器上发送刷新请求时,Redis 会将消息广播到所有订阅的服务器,确保每台服务器都执行刷新操作。

posted @ 2024-12-24 09:52  J九木  阅读(182)  评论(0)    收藏  举报