• golang工程中间件——redis常用结构及应用(string, hash, list)


    Redis

    命令中心

    【golang工程中间件——redisxxxxx】这些篇文章专门以应用为主,原理性的后续博主复习到的时候再详细阐述

    string结构以及应用

    字符数组,redis字符串是二进制安全字符串,可以存储图片等二进制数据,同时也可以存储经过 messagepack 或者 protobuffer 等工具压缩后的二进制数据; 内部实际存储根据 string 的数据特征可采用 int 、 embstr 、 raw 存储;(长度,是否能化为整数等条件,主要是长度)

    基础命令

    # 设置 key 的 value 值
    SET key val
    # 获取 key 的 value
    GET key
    # 执行原子加一的操作
    INCR key
    # 执行原子加一个整数的操作
    INCRBY key increment
    # 执行原子减一的操作
    DECR key
    # 执行原子减一个整数的操作
    DECRBY key decrement
    # 如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做
    SETNX key value
    # 删除 key val 键值对
    DEL key
    # 设置或者清空key的value(字符串)在offset处的bit值。
    SETBIT key offset value
    # 返回key对应的string在offset处的bit值
    GETBIT key offset
    # 统计字符串被设置为1的bit数.
    BITCOUNT key
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    应用

    对象存储

    常用存储json字符串,或者protobuffer序列化二进制。

    SET role:10001 '{["name"]:"mark",["sex"]:"male",["age"]:30}'
    GET role:10001
    # 固定不变或者几乎不会修改它采用
    
    • 1
    • 2
    • 3

    程序读取后反序列化为对象即可

    累加器
    # 统计访问数 累计加1
    incr accessCount
    # 累计加100
    incrby accessCount 100
    
    • 1
    • 2
    • 3
    • 4
    分布式锁

    在这里插入图片描述

    • 排他性
    • 定义获取锁行为
    • 定义释放锁行为
    # 加锁
    setnx lock 1
    # 释放锁
    del lock
    
    • 1
    • 2
    • 3
    • 4
    位运算
    # 月签到功能 10001 用户id 202107 2021年7月份的签到 7月份的第1天
    setbit sign:10001:202107 1 1
    # 计算 2021年7月份 的签到情况
    bitcount sign:10001:202107
    # 获取 2021年7月份 第二天的签到情况 1 已签到 0 没有签到
    getbit sign:10001:202107 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    list结构以及应用

    首尾相接的双向链表,链表首尾操作时间复杂度为O(1) ;查找中间元素时间复杂度为O(n) ;

    列表中数据可能会被压缩:

    • 元素长度小于 48,不压缩;
    • 元素压缩前后长度差不超过 8,不压缩;

    基础命令

    # 从队列的左侧入队一个或多个元素
    LPUSH key value [value ...]
    # 从队列的左侧弹出一个元素
    LPOP key
    # 从队列的右侧入队一个或多个元素
    RPUSH key value [value ...]
    # 从队列的右侧弹出一个元素
    RPOP key
    # 返回从队列的 start 和 end 之间的元素 0, 1 2
    LRANGE key start end
    # 从存于 key 的列表里移除前 count 次出现的值为 value 的元素
    LREM key count value
    # 它是 RPOP 的阻塞版本,因为这个命令会在给定list无法弹出任何元素的时候阻塞连接
    # block right pop
    BRPOP key timeout #
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    应用

    LPUSH + LPOP
    # 或者
    RPUSH + RPOP
    
    
    • 1
    • 2
    • 3
    • 4
    队列
    LPUSH + RPOP
    # 或者
    RPUSH + LPOP
    
    • 1
    • 2
    • 3
    异步队列

    在这里插入图片描述

    redis队列存储应用日志,再落盘到ES索引中

    类似异步队列,一些后台服务往redis队列里写日志,专门起日志落盘程序,读取redis队列中的日志json字符串(对象),格式化落盘到ES索引中。

    阻塞队列(blocking queue)
    LPUSH + BRPOP
    # 或者
    RPUSH + BLPOP
    
    • 1
    • 2
    • 3

    实际应用过程中,需要保证命令的原子性,所以需要使用 lua 脚本或者使用 pipeline 命令 + 事 务;

    # 在某些业务场景下,需要获取固定数量的记录;比如获取最近50条战绩;这些记录需要按照插入的先
    后顺序返回;
    lpush says '{["name"]:"狐金道长", ["text"]:"镇山河!",
    ["picture"]:["url://image-20230601232741434.jpg", "url://image202306asxx741435.jpg"], timestamp = 1699241288}'
    lpush says '{["name"]:"六红军爷", ["text"]:"任驰骋!",
    ["picture"]:["url://image-20230601134742434.jpg", "url://image20230asff72741436.jpg"], timestamp = 1699241288}'
    lpush says '{["name"]:"蹩脚毒萝", ["text"]:"化蝶!",
    ["picture"]:["url://image-20230601172543434.jpg", "url://image2021060123a41437.jpg"], timestamp = 1699241288}'
    lpush says '{["name"]:"sb弓", ["text"]:"我是傻狗",
    ["picture"]:["url://image-20230601172744678.jpg", "url://image20230601146272741438.jpg"], timestamp = 1699241288}'
    # 裁剪最近5条记录 例如聊天记录 
    ltrim says 0 4
    # 获取队列所有内容
    lrange says 0 -1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    问题

    可能会有很多连接去对list进行操作。但是redis是单线程的,只会处理一个命令。但是在这两条命令之间,可能会有别的命令对list进行操作。所以需要保证这两个命令一起执行。

    # 裁剪最近5条记录 例如聊天记录 
    ltrim says 0 4
    # 获取队列所有内容
    lrange says 0 -1
    
    • 1
    • 2
    • 3
    • 4

    实际应用过程中,需要保证命令的原子性,所以需要使用 lua 脚本或者使用 pipeline 命令 + 事 务

    hash结构以及应用

    字典结构,通过 hash 函数来确定节点的位置,很多高级语言包含 这个数据结构,例如 c++ 中 unordered_map,go 语言当中的 map 结构;

    基础命令

    # 获取 key 对应 hash 中的 field 对应的值
    HGET key field
    # 设置 key 对应 hash 中的 field 对应的值
    HSET key field value
    # 设置多个hash键值对
    HMSET key field1 value1 field2 value2 ... fieldn valuen
    # 获取多个field的值
    HMGET key field1 field2 ... fieldn
    # 给 key 对应 hash 中的 field 对应的值加一个整数值
    HINCRBY key field increment
    # 获取 key 对应的 hash 有多少个键值对
    HLEN key
    # 删除 key 对应的 hash 的键值对,该键为field
    HDEL key field
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    存储结构

    当节点数量少的时候且字符串长度小的时候,内部采用压缩列表存储,否则采用字典实现;

    10.62.122.23:7002> object encoding MyCart:10001
    "ziplist"
    
    • 1
    • 2

    应用

    存储对象
    hmset hash:10001 name qudaodao age 18 sex male
    # 与 string 比较
    set hash:10001 '{["name"]:"qudaodao",["sex"]:"male",["age"]:18,
    ["money"]:1000000}'
    # 假设现在修改qudaodao的年龄为19岁
    # hash:
    hset hash:10001 age 19
    # string:
    get role:10001
    # 将得到的字符串调用json.decode解密,取出字段,修改 age 值
    # 再调用json加密
    set role:10001 '{["name"]:"qudaodao",["sex"]:"male",["age"]:19}'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    购物车
    # 将用户id作为 key
    # 商品id作为 field
    # 商品数量作为 value
    # 注意:这些物品是按照我们添加顺序来显示的;
    # 添加商品:
    hset MyCart:10001 40001 1
    lpush MyItem:10001 40001
    # 增加数量:
    hincrby MyCart:10001 40001 1
    hincrby MyCart:10001 40001 -1 // 减少数量1
    # 显示所有物品数量:
    hlen MyCart:10001
    # 删除商品:
    hdel MyCart:10001 40001
    lrem MyItem:10001 1 40001
    # 获取所有物品:
    lrange MyItem:10001
    # 40001 40002 40003
    hget MyCart:10001 40001
    hget MyCart:10001 40002
    hget MyCart:10001 40003
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    xxl-job-架构及原理
    分布式IT监控系统
    3.3 log | 474.一和零,518.零钱兑换II,377. 组合总和 Ⅳ,322. 零钱兑换
    再看tomcat的体会
    基于 xml 配置文件的入门级 SSM 框架整合
    Excel 函数教程之如何提取字符串部分内容特殊字符,六套完整解决方案 (教程含源码)
    剑指offer-数据结构二
    浏览器上写代码,4核8G微软服务器免费用,Codespaces真香
    【软件设计师-下午题总结】
    Lab 1 实验 MapReduce
  • 原文地址:https://blog.csdn.net/qq_43058348/article/details/134251292