Redis相关命令详解及其原理

思维导图

认识redis

  • redis中的string类型是binary safe的,因为它不会对任何字符(包括'\0')进行特殊解释

redis测试

启动redis-server

启动redis-cli去连接redis-server

存储的value类型为string类型的

存储的value类型为hash结构

存储的value类型为set结构

存储的value类型为有序的集合

存储的value类型为链表结构

这种链表结构的数据存储类型适用于大部分的业务场景,因为大部分的业务场景都是仅仅要求插入有序。

redis存储结构KV

  • 存储的时候需要对两方面进行均衡:
    • 存储空间上进行均衡
    • 存储效率上进行均衡
  • redis是内存数据库,需要在时间和空间上进行均衡,而且redis会根据某个数据结构的节点数来进行均衡;换句话说就是底层的数据存储结构不是一成不变的,是会不断变化的

redis中value的编码:对象类型

string类型

从上面的实验可以看出来,string类型在redis中的存储可以是int类型,也可以是embstr类型,或者也可以是raw类型。

源码解析:string类型在redis内部的存储

注意这个sdshdrxx的结构体成员中都有个柔性数组(char buf[])。柔性数组的用法及特点是:

  1. 必须放在结构体中使用
  2. 必须放在结构体的最后面
  3. 结构体中还至少要包含一个其他的成员
  4. sizeof这个结构体返回的结构体的大小并不包含柔性数组的大小的
  5. 使用malloc这个接口来给结构体分配空间(注意这里malloc只需要调用一次)
//32为想要给结构体中的柔性数组分配的大小空间
struct sdshdr16* p = malloc(sizeof(struct sdshdr16) + 32);
  1. 使用free这个接口来给结构体释放空间(注意这里free也是只需要调用一次)
free(p);//这样就可以把结构体中的所有元素(包括柔性数组)全部都释放掉
  1. 柔性数组其实就是给编译器的一个标识,标识柔性数组代表的内存是动态的

应用方式

基本命令

位运算

key的设计
单个功能一个key

相同功能多个key

总结

  1. 如果不使用柔性数组,而是使用char* buffer的话,那么就需要malloc两次(一次是申请struct结构体的内存,还有一次是申请char* buffer的内存);同理释放也需要释放两次

  1. 柔性数组的优点
    1. 方便内存的分配及释放(只需要调用一次malloc)
    2. 减少内存碎片(只需要调用一次malloc)
  1. 分清楚几个概念:
    1. 对象类型:抽象的数据结构
    2. 数据结构、内存存储的结构:落盘的时候写到磁盘的结构
    3. 内存中的结构:字符串使用的是sds的数据结构来进行存储的

list类型

基础命令

清空数据库

存储list数据类型的基本操作

brpop的操作

存储结构定义

/* Node, quicklist, and Iterator are the only data structures used currently. */

/* quicklistNode is a 32 byte struct describing a listpack for a quicklist.
 * We use bit fields keep the quicklistNode at 32 bytes.
 * count: 16 bits, max 65536 (max lp bytes is 65k, so max count actually < 32k).
 * encoding: 2 bits, RAW=1, LZF=2.
 * container: 2 bits, PLAIN=1, PACKED=2.
 * recompress: 1 bit, bool, true if node is temporary decompressed for usage.
 * attempted_compress: 1 bit, boolean, used for verifying during testing.
 * extra: 10 bits, free for future use; pads out the remainder of 32 bits */
typedef struct quicklistNode {
    struct quicklistNode *prev;
    struct quicklistNode *next;
    unsigned char *entry;
    size_t sz;             /* entry size in bytes */
    unsigned int count : 16;     /* count of items in listpack */
    unsigned int encoding : 2;   /* RAW==1 or LZF==2 */
    unsigned int container : 2;  /* PLAIN==1 or PACKED==2 */
    unsigned int recompress : 1; /* was this node previous compressed? */
    unsigned int attempted_compress : 1; /* node can't compress; too small */
    unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;

/* quicklist is a 40 byte struct (on 64-bit systems) describing a quicklist.
 * 'count' is the number of total entries.
 * 'len' is the number of quicklist nodes.
 * 'compress' is: 0 if compression disabled, otherwise it's the number
 *                of quicklistNodes to leave uncompressed at ends of quicklist.
 * 'fill' is the user-requested (or default) fill factor.
 * 'bookmarks are an optional feature that is used by realloc this struct,
 *      so that they don't consume memory when not used. */
typedef struct quicklist {
    quicklistNode *head;
    quicklistNode *tail;
    unsigned long count;        /* total count of all entries in all listpacks */
    unsigned long len;          /* number of quicklistNodes */
    signed int fill : QL_FILL_BITS;       /* fill factor for individual nodes */
    unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
    unsigned int bookmark_count: QL_BM_BITS;
    quicklistBookmark bookmarks[];
} quicklist;

应用

队列

阻塞队列

异步消息队列

获取固定窗口记录

hash类型

基础命令

修改hash数组中某个field的value(比如说修改age->30)

存储结构

应用

存储对象

购物车

set类型

基础命令

存储结构

应用

抽奖

共同关注

推荐好友

zset类型

基础命令

存储结构

应用

百度热榜

延时队列

分布式定时器

时间窗口限流

测试

package.cpath = package.cpath..";./luaclib/?.so;"
package.path = package.path .. ";./lualib/?.lua;"

local zv = require "zv"
local socket = require "socket"
local evloop = require "evloop"

local redis = require "db.redis"
require "util"
evloop.start()

local tab_concat = table.concat

local function is_action_allowed(red, userid, action, period, max_count)
  local key = tab_concat({"hist", userid, action}, ":")
  local now = zv.time()
  red:init_pipeline()
  red:multi()
  -- 记录行为
  red:zadd(key, now, now)
  -- 移除时间窗口之前的行为记录,剩下的都是时间窗口内的记录
  red:zremrangebyscore(key, 0, now - period *100)
  -- 获取时间窗口内的行为数量
  red:zcard(key)
  -- 设置过期时间,避免冷用户持续占用内存 时间窗口的长度+1秒
  red:expire(key, period + 1)
  red:exec()
  local res = red:commit_pipeline()
  print(table.dump(res[6][3]))
  return (tonumber(res[6][3]) or 0) <= max_count
end

local function console_loop(_)
  local rds, err = redis.new("127.0.0.1", 6379)
  if not rds then
    print("failed to connect redis:", err)
    return
  end
  local ok
  ok, err = rds:set("name", "zero voice")
  if not ok then
    print("failed to set name: ", err)
    return
  end
  local res
  res, err = rds:get("name")
  if not res then
    print("failed to get name: ", err)
    return
  end
  if res == null then
    print("name not found.")
    return
  end
  print("name:", res)

  for i = 1, 10 do
    local can_reply = is_action_allowed(rds, 10001, "replay", 5, 7)
    if can_reply then
      print("can reply")
    else
      print("cant replay")
    end
    zv.sleep(10)
  end
end

socket.bind(0, console_loop)

evloop.run()

学习链接

https://xxetb.xetslk.com/s/12PH1r

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值