如果你使用Redis 4.0+,一条异步删除unlink就解决,就可以忽略下面内容 。
1.字符串:
一般来说,对于string类型使用del命令不会产生阻塞 。
del bigkey2.hash
使用hscan命令,每次获取部分(例如100个)field-value,在利用hdel删除每个field(为了快速可以使用pipeline) 。public void delBigHash(String bigKey) { Jedis jedis = new Jedis("127.0.0.1", 6379); // 游标 String cursor = "0"; while(true) {ScanResult<Map.Entry<String, String>> scanResult = jedis.hscan(bigKey, cursor, new ScanParams().count(100));// 每次扫描后获取新的游标cursor = scanResult.getStringCursor();// 获取扫描结果List<Entry<String, String>> list = scanResult.getResult();if(list == null || list.size() == 0) {continue;}String[] fields = getFieldsFrom(list);// 删除多个fieldjedis.hdel(bigKey, fields);// 游标为0时停止if(cursor.equals("0")) {break;} } // 最终删除key jedis.del(bigKey);}/** * 获取field数组 */private String[] getFieldsFrom(List<Entry<String, String>> list) { List<String> fields = new ArrayList<String>(); for (Entry<String, String> entry : list) {fields.add(entry.getKey()); } return fields.toArray(new String[fields.size()]);}3.list
Redis并没有提供lscan这样的API来遍历列表类型,但是提供了ltrim这样的命令可以渐进式的删除列表元素,直到把列表删除 。
public void delBigList(String bigKey) { Jedis jedis = new Jedis("127.0.0.1", 6379); long llen = jedis.llen(bigKey); int counter = 0; int left = 100; while(counter < llen) {// 每次从左侧截掉100个jedis.ltrim(bigKey, left, llen);counter += left; } // 最终删除key jedis.del(bigKey);}4.set
使用sscan命令,每次获取部分(例如100个)元素,在利用srem删除每个元素 。
ublic void delBigSet(String bigKey) { Jedis jedis = new Jedis("127.0.0.1", 6379); // 游标 String cursor = "0"; while(true) {ScanResult<String> scanResult = jedis.sscan(bigKey, cursor, new ScanParams().count(100));// 每次扫描后获取新的游标cursor = scanResult.getStringCursor();// 获取扫描结果List<String> list = scanResult.getResult();if(list == null || list.size() == 0) {continue;}jedis.srem(bigKey, list.toArray(new String[list.size()]));// 游标为0时停止if(cursor.equals("0")) {break;} } // 最终删除key jedis.del(bigKey);}5.sorted set
使用zscan命令,每次获取部分(例如100个)元素,在利用zremrangebyrank删除元素 。public void delBigSortedSet(String bigKey) { long startTime = System.currentTimeMillis(); Jedis jedis = new Jedis(HOST, PORT); // 游标 String cursor = "0"; while(true) {ScanResult<Tuple> scanResult = jedis.zscan(bigKey, cursor, new ScanParams().count(100));// 每次扫描后获取新的游标cursor = scanResult.getStringCursor();// 获取扫描结果List<Tuple> list = scanResult.getResult();if(list == null || list.size() == 0) {continue;}String[] members = getMembers(list);jedis.zrem(bigKey, members);// 游标为0时停止if(cursor.equals("0")) {break;} } // 最终删除key jedis.del(bigKey);}public void delBigSortedSet2(String bigKey) { Jedis jedis = new Jedis(HOST, PORT); long zcard = jedis.zcard(bigKey); int counter = 0; int incr = 100; while(counter < zcard) {jedis.zremrangeByRank(bigKey, 0, 100);// 每次从左侧截掉100个counter += incr; } // 最终删除key jedis.del(bigKey);}六、如何优化
1.拆
big list: list1、list2、...listN
big hash:可以做二次的hash,例如hash%100
日期类:key20190320、key20190321、key_20190322 。
2.本地缓存
减少访问redis次数,降低危害,但是要注意这里有可能因此本地的一些开销(例如使用堆外内存会涉及序列化,bigkey对序列化的开销也不小)
7、总结:
由于开发人员对Redis的理解程度不同,在实际开发中出现bigkey在所难免,重要的能通过合理的检测机制及时找到它们,进行处理 。作为开发人员应该在业务开发时不能将Redis简单暴力的使用,应该在数据结构的选择和设计上更加合理,例如出现了bigkey,要思考一下可不可以做一些优化(例如二级索引)尽量的让这些bigkey消失在业务中,如果bigkey不可避免,也要思考一下要不要每次把所有元素都取出来(例如有时候仅仅需要hmget,而不是hgetall),删除也是一样,尽量使用优雅的方式来处理 。
【阿里云的redis规范】
推荐阅读
- 阿里巴巴怎么开店注册流程 如何阿里巴巴开店步骤
- Redis原理分享,从使用到会用
- Redis布隆过滤器
- 火烧云的形状像什么 什么是火烧云,火烧云是怎么形成的
- 双十一阿里巴巴市值 双11阿里巴巴股票下降
- 阿里山珠炉茶介绍
- 普洱茶口感中影响唐云的因素
- Redis哈希类型
- 网站引入阿里云滑块验证码实现人机交互教程
- 阿里旺旺怎么用 阿里旺旺主要功能