一次线上mongodb的upset操作

线上有个业务场景,调用某个接口获取数据,由于接口的特殊性,其性能在线上也至少是百毫秒级别,这个数据本身很大,且字符串很长,起初采用了redis存储,发现对redis压力比较大,于是改为缓存到mongodb上,利用mongodb的数据自动过期策略清理过期数据。

线上mongodb缓存表定义如下:

db.createCollection("t_k_v_cache");
db.t_k_v_cache.createIndex({"key":1});
db.t_k_v_cache.createIndex({"expire_at":1},{"expireAfterSeconds":0}); 

为了保持key唯一,使用了spring的MongoTemplate进行mongodb的upset操作,代码如下:

    @Override
	public void addKVCache(KVCache cache) {
		Query query = new Query();
		Criteria criteria = new Criteria("key").is(cache.getKey());
		query.addCriteria(criteria);
		
		Update update = new Update();
		update.set("value", cache.getValue());
		update.set("expire_at", cache.getExpireAt());
		update.set("create_time", cache.getCreateTime());
		mongoTemplate.upsert(query, update, COLLECTION_T_K_V_CACHE);
	}

一切运行正常;

直到有一天发现......

任务变慢了!

经过排查,发现一个奇怪现象,任务最近从未从缓存取到过数据,也就是说所有数据走了接口,而接口数据并没有写到缓存;

那么怀疑是upset出现了问题?于是直接在mongodb客户端执行一个upset的操作:

db.t_k_v_cache.update({"key":"test"},{$set:{"key":"test","value":"test1","expire_at":"2021-04-04 03:29:19.17","create_time":"2021-03-25 11:29:19"}},true);

果不其然,报错了。。。

报错说的是这个语句没有用到分片片键,才想起来,我们最近将t_k_v_cache表进行了分片,且片键用的是主键_id;

报错信息里有个multi属性,默认就是false,表示只更新1条数据,mongo不知道你的key是唯一的,所以可能在不同的分片上都查到,那么它不知道该怎么更新,所以不允许如此操作;

要么重新构建集合,把key作为分片片键,要么直接不分片,我们最终决定不分片。

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值