差点导致系统挂掉,可用率啊可用率!

早上我们线的架构找到我,由于一张表被频繁查询,险些导致系统挂掉(还好现在只有每天几千的查询量,数据量不大,不过过段时间,当一个新业务上线时,会有每天1000w--5000w的量,就是说每天查询1000w次),现在打字时还有些腿软,可用率啊可用率!

 

上下文是这样的:

原因:系统中有些配置数据会被频繁查询,所以我们将之纳入缓存,用于提升系统的性能,缓解数据库的压力。

措施:因此每次系统启动时会把这些配置信息放入缓存,并且在每次请求访问配置数据时,加了一个容错,根据缓存Map的size==0来防止启动时数据库问题而加载不到配置信息,恰恰是由于这个容错,可能导致更加频繁的数据库查询。

问题:在什么情况下会出现这种情况呢?数据库的配置信息没有数据的时候!这个时候每次查询,缓存Map的size总是0,每次执行业务程序的时候,会以为是数据库加载不到数据而重新加载数据。也许大家会问为什么这个配置会是0呢?因为这是一个缓冲配置表,为了防止热点账户反复请求而设置的配置信息,所以它是动态增加的,系统刚上线时,自然是为0的。

总结:还是要多点责任心,事先也许由于经验不足,没有考虑到;事后没有监控好日志,确实是自己的责任了。 下面看看有问题的程序:

 

public class ProductCacheConfigManagerImpl extends TimerTask implements ProductCacheConfigManager,
                                                            InitializingBean {

    /** 定时任务logger */
    private static final Logger       timeTaskLogger = LoggerFactory
                                                         .getLogger(LoggerName.CONFIG_TIMETASK);

    /** logger */
    private static final Logger       logger         = LoggerFactory
                                                         .getLogger(ProductCacheConfigManagerImpl.class);

    /** 缓冲配置DAO */
    private ProdCacheConfigDAO        prodCacheConfigDAO;

    /** 缓冲配置信息缓存 */
    private Map<String, List<String>> configMap      = new HashMap<String, List<String>>();

    /**
     * 是否需要缓冲记账
   * 
     * @param principalId 主体id
     * @param subProductCode 子产品码
   * @return boolean 是否需要缓冲配置
     */
    public boolean isCached(String principalId, String subProductCode) {
       // 可能由于网络或者数据库原因没有加载到数据,需要重新加载。
        if (configMap.size() == 0) {
            reloadCacheConfig();
        }
       return needCache(principalId,subProductCode);
    }



    @Override
    public void run() {
        timeTaskLogger.warn("系统定时任务加载缓冲配置CacheConfig信息。");

        reloadCacheConfig();
    }

    private void reloadCacheConfig() {
        timeTaskLogger.warn("系统加载缓冲配置CacheConfig信息到map,开始执行。");

        Map<String, List<String>> map = new HashMap<String, List<String>>();

        List<ProdCacheConfigDO> cacheConfigDOs = this.prodCacheConfigDAO.findAll();

        for (ProdCacheConfigDO configDO : cacheConfigDOs) {
            String principalId = configDO.getPrincipalId();
            String subProductCode = configDO.getSubProductCode();

            if (map.containsKey(principalId)) {
                List<String> subProductCodes = map.get(principalId);
                subProductCodes.add(subProductCode);
            } else {
                List<String> subProductCodes = new ArrayList<String>();
                subProductCodes.add(subProductCode);
                map.put(principalId, subProductCodes);
            }

            timeTaskLogger.warn("系统加载缓冲配置CacheConfig信息到map,principalId=" + principalId
                                + ",subProductCode=" + subProductCode);
        }

        configMap = map;

        timeTaskLogger.warn("系统加载缓冲配置CacheConfig信息到map,结束。");

    }

    public void afterPropertiesSet() throws Exception {
        try {
            reloadCacheConfig();
        } catch (Exception ex) {
            timeTaskLogger.warn("系统加载缓冲配置CacheConfig信息失败。", ex);
        }
    }

    public void setProdCacheConfigDAO(ProdCacheConfigDAO prodCacheConfigDAO) {
        this.prodCacheConfigDAO = prodCacheConfigDAO;
    }
}

 

 

 

 

恰恰由于没有考虑数据库配置为空的情况,可能会导致数据库上千万次的查询。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值