1. Redis的key命名规范
1. 建议全部大写,不强制
2. key不能太长也不能太短,太短可读性太差,键名越长越占资源(毕竟内存很贵 按需申请)
3. key 单词与单词之间以分号":"分开,如{member:info:userabc}
4. redis使用的时候注意命名空间,一个项目一个命名空间,项目内业务不同命名空间也不同
一般情况下:
1) 第一段放置业务标识名或其缩写 如"member"
2) 第二段放信息标识 如, info/benefit/order:
3) 第三段放置用于区分区key的字段,如userId、priductId、activityId
eg:常见的设置登录token
key: PRO:USER:LOGINNAME:373166324
value:12kd-dsj5ce-d4445-h4sd472
2. Redis根据命名空间分组存储数据
在使用Redis进行数据缓存时,往往数据量是比较大的,若直接以普通键值对:key:value存储,就会显得比较乱,数据分类不明显,不易于查看和查找数据,就像下图一样:
这时,我们可以采取以命名空间开头的方式存储数据,使不同类型的数据统一放到一个命名空间下,一目了然;那么如何以命名空间分组呢?其实很简单,只用在存储数据时,键值对中的键命名以冒号分开即可:
在微服务模式下,存在一个项目多个微服务工程,共享redis集群的情况,因此多个工程的redis的key是相同的,这里补充一个代码技巧:我们一般将redis的key命名规范定义在公共的二方包里面,如XXcore-common,里面定义各个业务场景的redis key的生成规则,不推荐在代码中直接使用String.join(":", "member", "info": "ab123456")这样的写法,这种写法可能导致读写的redis key不一致难以维护;
代码示例:
package com.membercore.common.utils;
import com.membercore.common.constants.CacheKeyConstants;
import java.util.Date;
/**
* @Author AA
* @description 构建redisKey工具类
* @CreateDate 2020/03/13
*/
public class CacheKeyUtils {
public static final String SEPERATOR = ":";
/**
* 获取所有类型会员信息key member:info:all:#{openId}
*
* @param openid
* @return
*/
public static String getMemberAllInfoKey(String openid) {
return String.join(SEPERATOR, CacheKeyConstants.MEMBER_PREFIX, "all", openid);
}
/**
* 获取用户权益key member:benefit:#{openId}:#{bizType}:#{memberPeriod}
*
* @param openid
* @param bizType
* @param memberPeriod
* @return
*/
public static String getMemberBenefitKey(String openid, Integer bizType, Date memberPeriod) {
String memberPeriodStr = DateUtil.toStringByFormat(memberPeriod, DateUtil.DATE_FORMAT_2);
return String.join(SEPERATOR, CacheKeyConstants.MEMBER_BENEFIT_PREFIX, openid, String.valueOf(bizType), memberPeriodStr);
}
/**
* 获取权益任务key benefitTask:#{taskCode}
*
* @param taskCode
* @param bizType
* @return
*/
public static String getBenefitTaskKey(String taskCode, Integer bizType) {
return String.join(SEPERATOR, CacheKeyConstants.BENEFIT_TASK_PREFIX, taskCode, String.valueOf(bizType));
}
/**
* 获取权益模板key benefit:#{benefitId}
*
* @param benefitId
* @param benefitType
* @return
*/
public static String getBenefitKey(String benefitId, Integer benefitType) {
return String.join(SEPERATOR, CacheKeyConstants.BENEFIT_PREFIX, benefitId, String.valueOf(benefitType));
}
/**
* 获取小红点key reddot:#{openid}
*
* @param openid
* @param bizType
* @return
*/
public static String getRedDotKey(String openid, Integer bizType) {
return String.join(SEPERATOR, CacheKeyConstants.RED_DOT_PREFIX, openid, String.valueOf(bizType));
}
}
3. Redis容量预估计算(扩容、申请)
新业务场景需要使用redis时,一般会需要申请redis资源,如2G/4G/8G...申请redis容量,跟业务有关,如用户数、用户资产数、商品数量、活动数量,此外对于每一个缓存item,其缓存的key和value的长度也会影响,二者是乘积的关系;
这里给一个公式做一个快速容量预估参考:
(key的长度 + value的长度)X 数量 X 1.2
以上是一种快速计算的公式,如果想根据redis数据结构来作精确计算,可以参考下述的帖子,针对每种数据结构,结构中的变量及类型,精确算出某种结构的缓存大小,如String类型:
1个dictEntry结构,24字节,负责保存具体的键值对; 向上取整为32;
1个redisObject结构,16字节,用作val对象; 向上取整为16;
1个SDS结构,(key长度 + 9)字节,用作key字符串; 向上取整16/32/...
1个SDS结构,(val长度 + 9)字节,用作val字符串;向上取整16/32/...
当key个数逐渐增多,redis还会以rehash的方式扩展哈希表节点数组,即增大哈希表的bucket个数,每个bucket元素都是个指针(dictEntry*),占8字节,bucket个数是超过key个数向上求整的2的n次方,如2000个key,1024<2000<2048,因此bucket个数为2048;
加上向上2的n次方取值,计算公式为:
( 32 + 16 + (keyLength+9)取整 + (valLength+9)取整 )*数量 + (数量)向上取整*8(指针大小);
如:key长度为 13(13+9->32),value长度为15(15+9->32),key个数为2000(2000->2048)
根据上面总结的容量评估模型,容量预估值为2000 ×(32 + 16 + 32 + 32) + 2048× 8 = 240384