<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    阿里官方 Redis 開發(fā)規(guī)范

    共 8716字,需瀏覽 18分鐘

     ·

    2022-08-03 20:27

    本文主要介紹在使用阿里云 Redis 的開發(fā)規(guī)范,從下面幾個(gè)方面進(jìn)行說(shuō)明。

    • 鍵值設(shè)計(jì)
    • 命令使用
    • 客戶端使用
    • 相關(guān)工具

    通過(guò)本文的介紹可以減少使用 Redis 過(guò)程帶來(lái)的問(wèn)題。

     

    1

    鍵值設(shè)計(jì)

    1、key 名設(shè)計(jì)

    可讀性和可管理性

    以業(yè)務(wù)名 (或數(shù)據(jù)庫(kù)名) 為前綴(防止 key 沖突),用冒號(hào)分隔,比如業(yè)務(wù)名: 表名: id

    ugc:video:1


    簡(jiǎn)潔性


    保證語(yǔ)義的前提下,控制 key 的長(zhǎng)度,當(dāng) key 較多時(shí),內(nèi)存占用也不容忽視,例如:

    user:{uid}:friends:messages:{mid}簡(jiǎn)化為u:{uid}:fr:m:{mid}

    不要包含特殊字符

    反例:包含空格、換行、單雙引號(hào)以及其他轉(zhuǎn)義字符

    2、value 設(shè)計(jì)

    拒絕 bigkey

    防止網(wǎng)卡流量、慢查詢,string 類型控制在 10KB 以內(nèi),hash、list、set、zset 元素個(gè)數(shù)不要超過(guò) 5000。

    反例:一個(gè)包含 200 萬(wàn)個(gè)元素的 list。

    非字符串的 bigkey,不要使用 del 刪除,使用 hscan、sscan、zscan 方式漸進(jìn)式刪除,同時(shí)要注意防止 bigkey 過(guò)期時(shí)間自動(dòng)刪除問(wèn)題 (例如一個(gè) 200 萬(wàn)的 zset 設(shè)置 1 小時(shí)過(guò)期,會(huì)觸發(fā) del 操作,造成阻塞,而且該操作不會(huì)不出現(xiàn)在慢查詢中 (latency 可查)),查找方法和刪除方法

    選擇適合的數(shù)據(jù)類型

    例如:實(shí)體類型 (要合理控制和使用數(shù)據(jù)結(jié)構(gòu)內(nèi)存編碼優(yōu)化配置, 例如 ziplist,但也要注意節(jié)省內(nèi)存和性能之間的平衡)

    反例:

    set user:1:name tom
    set user:1:age 19
    set user:1:favor football
    正例:

    hmset user:1 name tom age 19 favor football

    控制 key 的生命周期

    redis 不是垃圾桶,建議使用 expire 設(shè)置過(guò)期時(shí)間 (條件允許可以打散過(guò)期時(shí)間,防止集中過(guò)期),不過(guò)期的數(shù)據(jù)重點(diǎn)關(guān)注 idletime。

     

    2

    命令使用


    1、O(N) 命令關(guān)注 N 的數(shù)量

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

    2、禁用命令

    禁止線上使用 keys、flushall、flushdb 等,通過(guò) redis 的 rename 機(jī)制禁掉命令,或者使用 scan 的方式漸進(jìn)式處理。

    3、合理使用 select

    redis 的多數(shù)據(jù)庫(kù)較弱,使用數(shù)字進(jìn)行區(qū)分,很多客戶端支持較差,同時(shí)多業(yè)務(wù)用多數(shù)據(jù)庫(kù)實(shí)際還是單線程處理,會(huì)有干擾。

    4、使用批量操作提高效率

    • 原生命令:例如 mget、mset。
    • 非原生命令:可以使用 pipeline 提高效率。

    但要注意控制一次批量操作的元素個(gè)數(shù) (例如 500 以內(nèi),實(shí)際也和元素字節(jié)數(shù)有關(guān))。
    注意兩者不同:

    • 原生是原子操作,pipeline 是非原子操作。
    • pipeline 可以打包不同的命令,原生做不到
    • pipeline 需要客戶端和服務(wù)端同時(shí)支持。

    5、不建議過(guò)多使用 Redis 事務(wù)功能

    Redis 的事務(wù)功能較弱 (不支持回滾),而且集群版本(自研和官方) 要求一次事務(wù)操作的 key 必須在一個(gè) slot 上(可以使用 hashtag 功能解決)

    6、Redis 集群版本在使用 Lua 上有特殊要求

    1、所有 key 都應(yīng)該由 KEYS 數(shù)組來(lái)傳遞,redis.call/pcall 里面調(diào)用的 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 arrayrn"
    2、所有 key,必須在 1 個(gè) slot 上,否則直接返回 error, "-ERR eval/evalsha command keys must in same slotrn"

    7、monitor 命令

    必要情況下使用 monitor 命令時(shí),要注意不要長(zhǎng)時(shí)間使用。


    3

    客戶端使用


    1、避免多個(gè)應(yīng)用使用一個(gè) Redis 實(shí)例

    不相干的業(yè)務(wù)拆分,公共數(shù)據(jù)做服務(wù)化。

    2、使用連接池

    可以有效控制連接,同時(shí)提高效率,標(biāo)準(zhǔn)使用方式:

    執(zhí)行命令如下:
    Jedis jedis = null;
    try {
        jedis = jedisPool.getResource();
        //具體的命令
        jedis.executeCommand()
    catch (Exception e) {
        logger.error("op key {} error: " + e.getMessage(), key, e);
    finally {
        //注意這里不是關(guān)閉連接,在JedisPool模式下,Jedis會(huì)被歸還給資源池。
        if (jedis != null)
            jedis.close();
    }


    3、熔斷功能

    高并發(fā)下建議客戶端添加熔斷功能 (例如 netflix hystrix)

    4、合理的加密

    設(shè)置合理的密碼,如有必要可以使用 SSL 加密訪問(wèn)(阿里云 Redis 支持)

    5、淘汰策略

    根據(jù)自身業(yè)務(wù)類型,選好 maxmemory-policy(最大內(nèi)存淘汰策略),設(shè)置好過(guò)期時(shí)間。

    默認(rèn)策略是 volatile-lru,即超過(guò)最大內(nèi)存后,在過(guò)期鍵中使用 lru 算法進(jìn)行 key 的剔除,保證不過(guò)期數(shù)據(jù)不被刪除,但是可能會(huì)出現(xiàn) OOM 問(wèn)題。

    其他策略如下:

    • allkeys-lru:根據(jù) LRU 算法刪除鍵,不管數(shù)據(jù)有沒(méi)有設(shè)置超時(shí)屬性,直到騰出足夠空間為止。
    • allkeys-random:隨機(jī)刪除所有鍵,直到騰出足夠空間為止。
    • volatile-random: 隨機(jī)刪除過(guò)期鍵,直到騰出足夠空間為止。
    • volatile-ttl:根據(jù)鍵值對(duì)象的 ttl 屬性,刪除最近將要過(guò)期數(shù)據(jù)。如果沒(méi)有,回退到 noeviction 策略。
    • noeviction:不會(huì)剔除任何數(shù)據(jù),拒絕所有寫入操作并返回客戶端錯(cuò)誤信息 "(error) OOM command not allowed when used memory",此時(shí) Redis 只響應(yīng)讀操作。

     

    4

    相關(guān)工具


    1、數(shù)據(jù)同步

    redis 間數(shù)據(jù)同步可以使用:redis-port

    2、big key 搜索

    redis 大 key 搜索工具

    3、熱點(diǎn) key 尋找

    內(nèi)部實(shí)現(xiàn)使用 monitor,所以建議短時(shí)間使用 facebook 的 redis-faina 阿里云 Redis 已經(jīng)在內(nèi)核層面解決熱點(diǎn) key 問(wèn)題


    5

    刪除 bigkey


    • 下面操作可以使用 pipeline 加速。
    • redis 4.0 已經(jīng)支持 key 的異步刪除,歡迎使用。

    1、Hash 刪除: hscan + hdel

    public void delBigHash(String host, int port, String password, String bigHashKey) {
        Jedis jedis = new Jedis(host, port);
        if (password != null && !"".equals(password)) {
            jedis.auth(password);
        }
        ScanParams scanParams = new ScanParams().count(100);
        String cursor = "0";
        do {
            ScanResult<Entry<StringString>> scanResult = jedis.hscan(bigHashKey, cursor, scanParams);
            List<Entry<StringString>> entryList = scanResult.getResult();
            if (entryList != null && !entryList.isEmpty()) {
                for (Entry<StringString> entry : entryList) {
                    jedis.hdel(bigHashKey, entry.getKey());
                }
            }
            cursor = scanResult.getStringCursor();
        } while (!"0".equals(cursor));
        //刪除bigkey
        jedis.del(bigHashKey);
    }

    2、List 刪除: ltrim

    public void delBigList(String host, int port, String password, String bigListKey{
        Jedis jedis = new Jedis(host, port);
        if (password != null && !"".equals(password)) {
            jedis.auth(password);
        }
        long llen = jedis.llen(bigListKey);
        int counter = 0;
        int left = 100;
        while (counter < llen) {
            //每次從左側(cè)截掉100個(gè)
            jedis.ltrim(bigListKey, left, llen);
            counter += left;
        }
        //最終刪除key
        jedis.del(bigListKey);
    }

    3、Set 刪除: sscan + srem

    public void delBigSet(String host, int port, String password, String bigSetKey) {
        Jedis jedis = new Jedis(host, port);
        if (password != null && !"".equals(password)) {
            jedis.auth(password);
        }
        ScanParams scanParams = new ScanParams().count(100);
        String cursor = "0";
        do {
            ScanResult<String> scanResult = jedis.sscan(bigSetKey, cursor, scanParams);
            List<String> memberList = scanResult.getResult();
            if (memberList != null && !memberList.isEmpty()) {
                for (String member : memberList) {
                    jedis.srem(bigSetKey, member);
                }
            }
            cursor = scanResult.getStringCursor();
        } while (!"0".equals(cursor));
        //刪除bigkey
        jedis.del(bigSetKey);
    }

    4、SortedSet 刪除: zscan + zrem

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

    來(lái)源:yq.aliyun.com/articles/531067
    瀏覽 27
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    97资源人妻 | 一级射视屏 | 黄频AV| www国产在线 | 国产又大又黄无遮挡 |