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

【参考】:

Redis相关数据结构的容量评估(这个帖子讲了一个结论解释了为什么计算出来的值是24字节,实际上计算时用的是32)

​​​​​​Redis容量评估

怎么计算字符串内存空间的占用

更快的方式,已经有在线的估算工具:Redis容量预估-极数云舟

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐