阿里云Redis开发规范

  • (1)【建议】: 可读性和可管理性

以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id

<span class="hljs-selector-tag">ugc<span class="hljs-selector-pseudo">:video<span class="hljs-selector-pseudo">:1</span></span></span>
  • (2)【建议】:简洁性

保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视,例如:

<span class="hljs-symbol">user:{uid}<span class="hljs-symbol">:friends<span class="hljs-symbol">:messages<span class="hljs-symbol">:{mid}&#x7B80;&#x5316;&#x4E3A;<span class="hljs-symbol">u:{uid}<span class="hljs-symbol">:fr<span class="hljs-symbol">:m<span class="hljs-symbol">:{mid}&#x3002;</span></span></span></span></span></span></span></span>
  • (3)【强制】:不要包含特殊字符

反例:包含空格、换行、单双引号以及其他转义字符

  • (1)【强制】:拒绝bigkey(防止网卡流量、慢查询)

string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。

反例:一个包含200万个元素的list。

非字符串的bigkey,不要使用del删除,使用hscan、sscan、zscan方式渐进式删除,同时要注意防止bigkey过期时间自动删除问题(例如一个200万的zset设置1小时过期,会触发del操作,造成阻塞,而且该操作不会不出现在慢查询中(latency可查)),查找方法删除方法

  • (2)【推荐】:选择适合的数据类型。

例如:实体类型(要合理控制和使用数据结构内存编码优化配置,例如ziplist,但也要注意节省内存和性能之间的平衡)

反例:

<span class="hljs-keyword">set <span class="hljs-keyword">user:<span class="hljs-number">1:<span class="hljs-keyword">name tom
<span class="hljs-keyword">set <span class="hljs-keyword">user:<span class="hljs-number">1:age <span class="hljs-number">19
<span class="hljs-keyword">set <span class="hljs-keyword">user:<span class="hljs-number">1:favor football</span></span></span></span></span></span></span></span></span></span></span>

正例:

<span class="hljs-selector-tag">hmset <span class="hljs-selector-tag">user<span class="hljs-selector-pseudo">:1 <span class="hljs-selector-tag">name <span class="hljs-selector-tag">tom <span class="hljs-selector-tag">age 19 <span class="hljs-selector-tag">favor <span class="hljs-selector-tag">football</span></span></span></span></span></span></span></span>

建议使用expire设置过期时间(条件允许可以打散过期时间,防止集中过期),不过期的数据重点关注idletime。

例如hgetall、lrange、smembers、zrange、sinter等并非不能使用,但是需要明确N的值。有遍历的需求可以使用hscan、sscan、zscan代替。

禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。

redis的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰。

&#x539F;&#x751F;&#x547D;&#x4EE4;&#xFF1A;&#x4F8B;&#x5982;mget&#x3001;mset&#x3002;
&#x975E;&#x539F;&#x751F;&#x547D;&#x4EE4;&#xFF1A;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;pipeline&#x63D0;&#x9AD8;&#x6548;&#x7387;&#x3002;

但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。

注意两者不同:

<span class="hljs-bullet">1. &#x539F;&#x751F;&#x662F;&#x539F;&#x5B50;&#x64CD;&#x4F5C;&#xFF0C;pipeline&#x662F;&#x975E;&#x539F;&#x5B50;&#x64CD;&#x4F5C;&#x3002;
<span class="hljs-bullet">2. pipeline&#x53EF;&#x4EE5;&#x6253;&#x5305;&#x4E0D;&#x540C;&#x7684;&#x547D;&#x4EE4;&#xFF0C;&#x539F;&#x751F;&#x505A;&#x4E0D;&#x5230;
<span class="hljs-bullet">3. pipeline&#x9700;&#x8981;&#x5BA2;&#x6237;&#x7AEF;&#x548C;&#x670D;&#x52A1;&#x7AEF;&#x540C;&#x65F6;&#x652F;&#x6301;&#x3002;</span></span></span>

Redis的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot上(可以使用hashtag功能解决)

  • 1.所有key都应该由 KEYS 数组来传递,redis.call/pcall 里面调用的redis命令,key的位置,必须是KEYS array, 否则直接返回error,”-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array”
  • 2.所有key,必须在1个slot上,否则直接返回error, “-ERR eval/evalsha command keys must in same slot”

避免多个应用使用一个Redis实例

正例:不相干的业务拆分,公共数据做服务化。

使用带有连接池的数据库,可以有效控制连接,同时提高效率,标准使用方式:

&#x6267;&#x884C;&#x547D;&#x4EE4;&#x5982;&#x4E0B;&#xFF1A;
Jedis jedis = <span class="hljs-keyword">null;
<span class="hljs-keyword">try {
    jedis = jedisPool.getResource();
    </span></span>

下面是JedisPool优化方法的文章:

高并发下建议客户端添加熔断功能(例如netflix hystrix)

设置合理的密码,如有必要可以使用SSL加密访问(阿里云Redis支持)

根据自身业务类型,选好maxmemory-policy(最大内存淘汰策略),设置好过期时间。

默认策略是volatile-lru,即超过最大内存后,在过期键中使用lru算法进行key的剔除,保证不过期数据不被删除,但是可能会出现OOM问题。

  • allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。
  • allkeys-random:随机删除所有键,直到腾出足够空间为止。
  • volatile-random:随机删除过期键,直到腾出足够空间为止。
  • volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略。
  • noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息”(error) OOM command not allowed when used memory”,此时Redis只响应读操作。

redis间数据同步可以使用:redis-port

&#x963F;&#x91CC;&#x4E91;Redis&#x5DF2;&#x7ECF;&#x5728;&#x5185;&#x6838;&#x5C42;&#x9762;&#x89E3;&#x51B3;&#x70ED;&#x70B9;key&#x95EE;&#x9898;&#xFF0C;&#x6B22;&#x8FCE;&#x4F7F;&#x7528;&#x3002;

五 附录:删除bigkey

<span class="hljs-bullet">1. &#x4E0B;&#x9762;&#x64CD;&#x4F5C;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;pipeline&#x52A0;&#x901F;&#x3002;
<span class="hljs-bullet">2. redis 4.0&#x5DF2;&#x7ECF;&#x652F;&#x6301;key&#x7684;&#x5F02;&#x6B65;&#x5220;&#x9664;&#xFF0C;&#x6B22;&#x8FCE;&#x4F7F;&#x7528;&#x3002;</span></span>
public <span class="hljs-keyword">void delBigHash(<span class="hljs-built_in">String host, int port, <span class="hljs-built_in">String password, <span class="hljs-built_in">String bigHashKey) {
    Jedis jedis = <span class="hljs-keyword">new Jedis(host, port);
    <span class="hljs-keyword">if (password != <span class="hljs-literal">null && !<span class="hljs-string">"".equals(password)) {
        jedis.auth(password);
    }
    ScanParams scanParams = <span class="hljs-keyword">new ScanParams().count(<span class="hljs-number">100);
    <span class="hljs-built_in">String cursor = <span class="hljs-string">"0";
    <span class="hljs-keyword">do {
        ScanResult<entry<<span class="hljs-built_in">String, <span class="hljs-built_in">String>> scanResult = jedis.hscan(bigHashKey, cursor, scanParams);
        List<entry<<span class="hljs-built_in">String, <span class="hljs-built_in">String>> entryList = scanResult.getResult();
        <span class="hljs-keyword">if (entryList != <span class="hljs-literal">null && !entryList.isEmpty()) {
            <span class="hljs-keyword">for (Entry<<span class="hljs-built_in">String, <span class="hljs-built_in">String> entry : entryList) {
                jedis.hdel(bigHashKey, entry.getKey());
            }
        }
        cursor = scanResult.getStringCursor();
    } <span class="hljs-keyword">while (!<span class="hljs-string">"0".equals(cursor));

    </span></span></span></span></span></span></span></span></entry<<span></span></entry<<span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">delBigList(<span class="hljs-params">String host, <span class="hljs-keyword">int port, String password, String bigListKey) {
    Jedis jedis = <span class="hljs-keyword">new Jedis(host, port);
    <span class="hljs-keyword">if (password != <span class="hljs-literal">null && !<span class="hljs-string">"".equals(password)) {
        jedis.auth(password);
    }
    <span class="hljs-keyword">long llen = jedis.llen(bigListKey);
    <span class="hljs-keyword">int counter = <span class="hljs-number">0;
    <span class="hljs-keyword">int left = <span class="hljs-number">100;
    <span class="hljs-keyword">while (counter < llen) {
        </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
public <span class="hljs-keyword">void delBigSet(<span class="hljs-built_in">String host, int port, <span class="hljs-built_in">String password, <span class="hljs-built_in">String bigSetKey) {
    Jedis jedis = <span class="hljs-keyword">new Jedis(host, port);
    <span class="hljs-keyword">if (password != <span class="hljs-literal">null && !<span class="hljs-string">"".equals(password)) {
        jedis.auth(password);
    }
    ScanParams scanParams = <span class="hljs-keyword">new ScanParams().count(<span class="hljs-number">100);
    <span class="hljs-built_in">String cursor = <span class="hljs-string">"0";
    <span class="hljs-keyword">do {
        ScanResult<<span class="hljs-built_in">String> scanResult = jedis.sscan(bigSetKey, cursor, scanParams);
        List<<span class="hljs-built_in">String> memberList = scanResult.getResult();
        <span class="hljs-keyword">if (memberList != <span class="hljs-literal">null && !memberList.isEmpty()) {
            <span class="hljs-keyword">for (<span class="hljs-built_in">String member : memberList) {
                jedis.srem(bigSetKey, member);
            }
        }
        cursor = scanResult.getStringCursor();
    } <span class="hljs-keyword">while (!<span class="hljs-string">"0".equals(cursor));

    </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
public <span class="hljs-keyword">void delBigZset(<span class="hljs-built_in">String host, int port, <span class="hljs-built_in">String password, <span class="hljs-built_in">String bigZsetKey) {
    Jedis jedis = <span class="hljs-keyword">new Jedis(host, port);
    <span class="hljs-keyword">if (password != <span class="hljs-literal">null && !<span class="hljs-string">"".equals(password)) {
        jedis.auth(password);
    }
    ScanParams scanParams = <span class="hljs-keyword">new ScanParams().count(<span class="hljs-number">100);
    <span class="hljs-built_in">String cursor = <span class="hljs-string">"0";
    <span class="hljs-keyword">do {
        ScanResult<tuple> scanResult = jedis.zscan(bigZsetKey, cursor, scanParams);
        List<tuple> tupleList = scanResult.getResult();
        <span class="hljs-keyword">if (tupleList != <span class="hljs-literal">null && !tupleList.isEmpty()) {
            <span class="hljs-keyword">for (Tuple tuple : tupleList) {
                jedis.zrem(bigZsetKey, tuple.getElement());
            }
        }
        cursor = scanResult.getStringCursor();
    } <span class="hljs-keyword">while (!<span class="hljs-string">"0".equals(cursor));

    </span></span></span></span></span></tuple></tuple></span></span></span></span></span></span></span></span></span></span></span></span></span>

Original: https://www.cnblogs.com/Alight/p/9596982.html
Author: 一束光
Title: 阿里云Redis开发规范

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/529038/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 聊聊消息中心的设计与实现逻辑

    厌烦被消息打扰,又怕突然间的安静; 一、业务背景 微服务的架构体系中,会存在很多基础服务,提供一些大部分服务都可能需要的能力,比如文件管理、MQ队列、缓存机制、消息中心等等,这些服…

    Linux 2023年6月14日
    086
  • 笔记:linux 总结

    1.开始 Linux,全称GNU/Linux,是一种免费使用和自由传播的类UNIX操作系统,其内核由林纳斯·本纳第克特·托瓦兹于1991年10月5日首次发布,它主要受到Minix和…

    Linux 2023年5月27日
    0141
  • 手把手教你搭建一个SpringBoot工程

    手把手教你搭建一个SpringBoot工程 首先进入Spring官网,下载Demo工程 像这样设置好 点击下载 将工程导入Idea并打开 在 application.propert…

    Linux 2023年6月14日
    0113
  • QT官方社区及版本说明

    Qt版本说明 版本分类 Qt商业版:提供给商业软件开发。它们提供传统商业软件发行版并且提供在协议有效期内的免费升级和技术支持服务。 Qt开源版:提供了和商业版本同样的功能。它是免费…

    Linux 2023年6月13日
    0153
  • VMware Workstation 与 Device/Credential Guard 不兼容

    问题: 在确定已经禁用 Hyper-V 功能的前提下,启动虚拟机还是报错 ” VMware Workstation 与 Device/Credential Guard …

    Linux 2023年6月7日
    082
  • Docker部署

    部署Docker 1.部署docker相关 此章描述在新的服务器上安装docker容器。 1.1 概述 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apach…

    Linux 2023年6月7日
    0125
  • 安装 CentOS 7

    1、VMware虚拟机安装 2、CentOS操作系统安装 3、CentOS操作系统配置 3.1、选择语言 3.2、网络和主机名 3.3、日期和时间 3.4、安装位置 3.5、开始安…

    Linux 2023年6月8日
    0100
  • redis 学习指南

    2、 redis.windows.conf各项配置参数介绍 默认情况下,redis不是在后台模式运行的,如果需要在后台进程运行,把该项的值更改为yes,默认为no daemoniz…

    Linux 2023年5月28日
    078
  • 位图实现

    位图就是用每个字节中的bit位代表一组资源的映射。 例如:一个字节有8位,在操作系统中可以用一个bit位代表一个4K的页,那一个字节就可以代表8页32K内存。 可以利用位图进行资源…

    Linux 2023年6月7日
    071
  • C语言—>指针

    当两个指针 p1, p2相减时, p2-p1就是从 p1到 p2,不包含 p2的元素个数,结果的类型是 ptrdiff_t #include int main() { int a[…

    Linux 2023年6月8日
    079
  • SQL45 将titles_test表名修改为titles_2017

    本题链接本题省略表结构。需要用到RENAME TABLE子句,该子句可实现一或多个表名称的修改。子句语法为: RENAME TABLE tbl_name TO new_tbl_na…

    Linux 2023年6月13日
    072
  • make

    make 背景 gcc 在编译一个包含多个源文件的工程时, gcc需要将每一个源文件都编译一遍,任何再链接起来形成一个可执行文件。实际上,用户很少对所有源文件都进行修改,这就会造成…

    Linux 2023年6月7日
    091
  • Linux Netlink学习笔记

    Netlink是用户程序与内核通信的socket方法,通过Netlink可以获得修改内核的配置,常见的有获得接口的IP地址列表、更改路由表或邻居表。旧版本的内核提供很多从内核获取信…

    Linux 2023年6月6日
    0101
  • 4.8 Linux解压.bz2格式的文件(bunzip2命令)

    要解压”.bz2″格式的压缩包文件,除了使用”bzip2 -d 压缩包名”命令外,还可以使用 bunzip2 命令。 bunzip2…

    Linux 2023年6月7日
    071
  • Java的jinfo命令使用详解

    jinfo命令简介 jinfo(Java Virtual Machine Configuration Information)是JDK提供的一个可以实时查看Java虚拟机各种配置参…

    Linux 2023年5月27日
    093
  • 备用链接

    win10 stick note 地址 https://www.partitionwizard.com/partitionmanager/where-are-sticky-note…

    Linux 2023年6月7日
    079
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球