当前位置: 首页 > 后端技术 > Java

Redis开发注意事项

时间:2023-04-01 19:17:45 Java

一、键值设计1、键名设计(一)【建议】:可读性和可管理性以业务名(或数据库名)为前缀(防止键冲突),以冒号分隔,如业务名:表名:idugc:video:1(2)【建议】:在保证简洁和语义的前提下,控制key的长度。当key很多的时候,内存的占用是不容忽视的。例如:user:{uid}:friends:messages:{mid}简化为u:{uid}:fr:m:{mid}(3)【强制】:不包含特殊字符反例:包含空格,换行符、单双引号等转义字符2.取值设计(1)【强制】:拒绝bigkey(防止网卡流量和慢查询)string类型控制在10KB以内,hash、list、set、zset元素不能超过5000个。反例:200万个元素的列表。对于非字符串bigkey,不要使用del删除,使用hscan、sscan、zscan逐步删除,同时注意防止bigkey过期时间自动删除(比如设置了200万的zset1小时后过期,会触发del操作,造成Blocking,慢查询中不会出现此操作(latency可查)。(2)【推荐】:选择合适的数据类型。例如:实体类型(合理控制和使用数据结构内存编码优化配置,比如ziplist,还要注意节省内存和性能的平衡)反例:setuser:1:nametomsetuser:1:age19setuser:1:favorfootball正例:hmsetuser:1nametomage19favourfootball2.命令用法1.【推荐】O(N)条命令注意N个数,比如hgetall,lrange,smembers,zrange、sinter等也不是不能用。但需要指定N的值。如果需要遍历,可以使用hscan、sscan、zscan代替。2、【建议】:禁用keys、flushall、flushdb等禁止在线使用的命令,通过redis的rename机制禁用命令,或者使用scan方式逐步处理。3.【建议】合理使用selectredis的多数据库弱,用数字区分,很多客户端支持不好。同时,多服务的多数据库实际上是单线程处理的,会产生干扰。4、【建议】使用批处理提高效率原生命令:如mget、mset。非本机命令:可以使用管道来提高效率。但是要注意控制一次批量操作的元素个数(比如500以内,其实和元素字节数有关)。注意两者不同:native是原子操作,pipeline是非原子操作。管道可以打包不同的命令,这是原生无法完成的。管道需要客户端和服务器都支持。[建议]Redis事务功能较弱,不建议过多使用。5、【建议】Redis事务功能较弱,不建议使用太多operationmustbeonaslot(可以使用hashtag功能解决)6.【建议】Redis集群版本对使用Lua有特殊要求:所有的key都要通过KEYS数组传递,在redis中调用redis命令.call/pcall,key的位置必须是KEYS数组,否则直接返回error,"-ERRbadluascriptforrediscluster,allthekeysthatthescriptusesshouldbepassedusingtheKEYSarray"Allkeysmustbeononeslot,否则直接返回error,“-ERReval/evalshacommandkeysmustinsameslot”7.【建议】必要时使用monitor命令,注意不要长时间使用。三、客户端使用1、删除策略根据自身业务类型,选择maxmemory-policy(最大内存删除策略),并设置过期时间。默认策略是volatile-lru,即超过最大内存后,使用lru算法对过期key进行移除,保证非过期数据不会被删除,但可能会出现OOM问题。其他策略如下:allkeys-lru:根据LRU算法删除keys,不管数据是否有超时属性,直到有足够的空间可用。allkeys-random:随机删除所有键,直到有足够的空间。volatile-random:随机删除过期的键,直到有足够的空间。volatile-ttl:根据key-value对象的ttl属性,删除最近即将过期的数据。如果不是,则退回到noeviction策略。noeviction:不会删除任何数据,拒绝所有写操作,并返回客户端错误信息“(error)OOMcommandnotallowedwhenusedmemory”。此时Redis只响应读操作。4.删除bigkey1。使用管道可以加速以下操作。2.redis4.0已支持key的异常删除1.哈希删除:hscan+hdelpublicvoiddelBigHash(Stringhost,intport,Stringpassword,StringbigHashKey){Jedisjedis=newJedis(host,port);if(password!=null&&!"".equals(password)){jedis.auth(password);}ScanParamsscanParams=newScanParams().count(100);字符串游标="0";做{ScanResult>scanResult=jedis.hscan(bigHashKey,cursor,scanParams);List>entryList=scanResult.getResult();if(entryList!=null&&!entryList.isEmpty()){for(Entryentry:entryList){jedis.hdel(bigHashKey,entry.getKey());}}}cursor=scanResult.getStringCursor();}while(!"0".equals(cursor));//删除bigkeyjedis.del(bigHashKey);}2.列表删除:ltrimpublicvoiddelBigList(Stringhost,intport,Stringpassword,StringbigListKey){Jedisjedis=newJedis(host,port);if(password!=null&&!"".equals(password)){jedis.auth(password);}longllen=jedis.llen(bigListKey);整数计数器=0;int左=100;while(counterscanResult=jedis.sscan(bigSetKey,cursor,scanParams);ListmemberList=scanResult.getResult();如果(成员列表!=null&&放大器;!memberList.isEmpty()){for(Stringmember:memberList){jedis.srem(bigSetKey,member);}}cursor=scanResult.getStringCursor();}while(!"0".equals(cursor));//删除bigkeyjedis.del(bigSetKey);}4.SortedSet删除:zscan+zrempublicvoiddelBigZset(Stringhost,intport,Stringpassword,StringbigZsetKey){Jedisjedis=newJedis(host,port);if(password!=null&&!"".equals(password)){jedis.auth(password);}ScanParamsscanParams=newScanParams().count(100);字符串游标="0";做{ScanResultscanResult=jedis.zscan(bigZsetKey,cursor,scanParams);列表<元组>tupleList=scanResult.getResult();if(tupleList!=null&&!tupleList.isEmpty()){for(Tupletuple:tupleList){jedis.zrem(bigZsetKey,tuple.getElement());}}}cursor=scanResult.getStringCursor();}while(!"0".equals(cursor));//删除bigkeyjedis.del(bigZsetKey);}本文编译自:https://mp.weixin.qq.com/s/XI...