yudao 多租户通过tenantFrameworkService获取子租户缓存异常

一、问题描述

在yudao的多租户系统中,有个 tenantFrameworkService 可以可以缓存租户id,系统中由于是多级租户,所以有根据租户id获所有子租户的需求,我们就在这个 tenantFrameworkService 下加了 getTenantChildren(Long tenantId) 方法来获取所有的子租户。

   private final LoadingCache<Long, List<Long>> getAllTenantIdsForChildCache = CacheUtils.buildAsyncReloadingCache(
           Duration.ofMinutes(1L), // 过期时间 1 分钟
           new CacheLoader<Long, List<Long>>() {
               @Override
               public List<Long> load(Long tenantId) throws Exception {
                   CommonResult<List<Long>> result = tenantApi.getALLTenantIdsForChild(tenantId);
                   if (result.isSuccess()) {
                       log.info("[getALLTenantIdsForChild] 缓存命中,tenantId={},{}", tenantId, result.getCheckedData());
                       return result.getCheckedData();
                   } else {
                       throw new Exception(result.getMsg());
                   }
               }
           });

   @Override
   @SneakyThrows
   public List<Long> getTenantChildren(Long tenantId) {
       return getAllTenantIdsForChildCache.get(tenantId);
   }

但是问题是这边查询了两个租户的所有子租户,然后使用
tenantIds.addAll(yhbzTenantIds);
把两个list合在一起了,奇怪的问题出现了,由于缓存有效期是1分钟 ,在执行一次定时任务,一分钟内再次执行的话,获取到的子租户id就会异常,会多出 yhbzTenantIds 对应的租户id。如果一分钟内执行三次的话,就会多两次 yhbzTenantIds 。

image.png
image.png

image.png

二、问题分析

由于缓存存在一分钟,且只在一分钟之内执行会出现此问题,那么基本可以判断出来是在 tenantIds.addAll(yhbzTenantIds); 这个 方法执行后,将执行后的 tenantIds 又保存进缓存里了,那么问题是什么时候存进缓存的呢?或者说是怎么更新缓存的?

查看 代码,具体的保存缓存是在 CacheUtils.buildAsyncReloadingCache 这个方法,存到 getAllTenantIdsForChildCache 这个 LoadingCache 里,LoadingCache 是以 K,V 形式保存的,经过下面的测试发现,第一次和第二次从 LoadingCache 获取到的同一个key对应的 value 是一样的,也就是保存在 堆内存的指针是没变的,所以获取到的 List 变化后,一分钟内再获取还是变化后的。

image.png
image.png

三、处理方法

其实这种处理很简单,新建个list将两个list添加进来即可

 List<Long> tenantIds = new ArrayList<>();
        List<Long> hgTenantIds = tenantFrameworkService.getTenantChildren(constantsTenant.HG_TENANTID);
        List<Long> yhbzTenantIds = tenantFrameworkService.getTenantChildren(constantsTenant.YHBZ_TENANTID);
        tenantIds.addAll(hgTenantIds);
        tenantIds.addAll(yhbzTenantIds);
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容