基于Redis实现Spring Cloud Gateway的动态管理( 三 )

  • 如果数据量比较大, 不建议使用keys进行模糊查询, 应该使用scan方式
  • 数据缓存
    我们提供了内部缓存,它处于使用者与持久存储之间,缓存数据以提升性能 。缓存的实现主要有如下几点:
    1. 实现了 InitializingBean 以实现在网关启动时, 自动加载数据
    2. 内部使用了ConcurrentHashMap, 保证写时的线程同步, 又保证了get时的高效(get整个过程不需要加锁)
    3. 从缓存中取数据时, 如果需要懒加载, 当从持久存储中加载不到数据时, 建议使用空数据, 或空集合占位, 避免每次都去持久存储中查询
    代码示例如下:
    /** * 根据 appCode 获取流量策略 ** @param appCode * @return */public Set<ApplicationTrafficPolicy> getAppTrafficPolicies(String appCode) { // 从缓存加载 Map<String, ApplicationTrafficPolicy> map = policyMap.get(appCode); // 缓存中没有 if (map == null) { // 尝试从持久存储中加载所有此网关的流量策略 Set<ApplicationTrafficPolicy> policies = trafficPolicyRepository.fuzzyQuery(); // 持久存储中没有任何流量策略,占个位置,防止缓存重复去加载 if (policies == null || policies.size() == 0) { map = new ConcurrentHashMap<>(); policyMap.put(appCode, map); } else { // 持久存储中有流量策略,放入缓存 for (ApplicationTrafficPolicy policy : policies) { setTrafficPolicy(policy); } // 重新从缓存中加载一次 map = policyMap.get(appCode); // 如果还是没有,使用空 map 占位子 if (map == null) { map = new ConcurrentHashMap<>(); policyMap.put(appCode, map); } } } return map.values().stream().collect(Collectors.toSet());}事件通知
    事件通知,这里我们使用的是redis的发布与订阅能力 。Redis默认是不发送事件的,要让它发布事件,需要先修改它的配置文件redis.conf,添加一个配置:
    notify-keyspace-events "K$g"上面的配置将使得Redis中发生数据的添加,修改或删除时,发送set或del事件 。
    然后,我们需要配置一个RedisMessageListenerContainer,用来订阅我们感兴趣的事件 。
    @BeanRedisMessageListenerContainer container(MessageListenerAdapter listenerAdapter) { String gtwReidsPattern = "__keyspace@*__:" + GTW + keyGenerator.getGatewayCode() + "]*"; String cofRedisPattern = "__keyspace@*__:" + COF + cacheKey.getKeyNameSpace() + USER_NAME + "*"; log.info("Add gateway redis message listener, patternTopic is {}", gtwReidsPattern); log.info("Add coframe redis message listener, patternTopic is {}", cofRedisPattern); RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(redisTemplate.getConnectionFactory()); // PatternTopic 参考:http://redisdoc.com/topic/notification.html container.addMessageListener(listenerAdapter, Arrays.asList(new PatternTopic(PatternUtil.fmt(gtwReidsPattern)), new PatternTopic(PatternUtil.fmt(cofRedisPattern)))); return container;}当redis事件订阅好了之后, 每次其中我们关心的数据有变更, 都会发送set或del事件.我们需要定义一个 MessageListener, 来接收事件:@Service(value = https://www.isolves.com/it/wlyx/fwq/2019-08-22/RedisMessageListener.REDIS_LISTENER_NAME)public class RedisMessageListener implements MessageListener { @Override public void onMessage(Message message, byte[] pattern) { String ops = new String(message.getBody()); String channel = new String(message.getChannel()); String key = channel.split(":")[1];? if ("set".equals(ops)) { String value = redisTemplate.opsForValue().get(key); handleSet(key, value); } else if ("del".equals(ops)) { handleDel(key); } } ...}接收到事件后,会调用相应的内部缓存,更新内部缓存中的数据,以实现治理数据变更的及时生效 。
    基于Redis实现Spring Cloud Gateway的动态管理

    文章插图
     
    关于作者:将晓渔,现任普元云计算架构师 。曾在PDM,云计算,数据备份,移动互联相关领域公司工作,十年以上IT工作经验 。曾为科企桌面虚拟化产品的核心工程师,爱数容灾备份云柜系统设计师,万达信息的食安管理与追溯平台开发经理 。国内IAAS云计算的早期实践者,容器技术专家 。
    关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享 。




    推荐阅读