自学内容网 自学内容网

Redis1——基本命令及原理

Redis1——基本命令及原理

1. Redis原理

Redis是Remote Dictionary Service的简称,及远程字典服务。Redis是一个基于内存的存储键值对的非关系型数据库。

1.1 特点

  • 没有显式地创建和和删除数据结构地语句,当添加元素地时候自动创建,当删除元素时,如果集合为空,则自动删除数据结构。
  • 数据量少的时候,以存储效率高为主(ziplist),数据量大的时候以查询效率高为主(skiplist,dict)

1.2 数据类型及其存储方式

主要是指value指的数据结构:

1.2.1 string 字符串

存储结构:如果字符串可以表示为整数,且范围在64位二进制以内,则存储为整数,否则使用sds存储。

sds是一个能够动态扩容的内存安全的数组结构,当字符串长度不超过512M时使用它来存储。

如果字符串长度小于44字节,使用embstr编码(压缩编码),将redis对象结构与SDS分配在连续的内存中,减少内存碎片。

否则采用raw编码(普通编码),将redis对象结构与SDS分开存储,因此需要更多的内存分配和释放操作。

注意:redis的string是一个安全的二进制字符串。二进制指可以不存储为字符编码,安全是指保存了字符串的长度信息。

1.2.2 list 列表

存储结构:当节点总数小于等于512或者元素长度都不超过64字节时采用ziplist压缩列表。否则采用quicklist双向循环链表。

注意:保证插入有序。

1.2.3 hash 哈希表

存储结构:节点数量大于512(hash-max-ziplist-entries)或所有字符串长度大于64(hash-max-ziplist-value),则使用dict实现。

节点数量小于等于512且有一个字符串长度小于64,则使用ziplist实现。

注意:保存的元素为键值对,能够去重。

1.2.4 set 集合

存储结构:元素都为整数且元素数量小于等于512(set-max-intset-entries),则使用整数数组存储。否则使用dict。

注意:保存的元素为值,能够去重。

1.2.5 zset 有序集合

存储结构:节点数量大于128或者有一个字符串长度大于64,则使用跳表skiplist,否则使用压缩列表ziplist。

2. 基本命令及应用场景:

2.1 Redis应用场景

用于各种需要高效的临时存储和访问数据的场景。例如用作缓存中间件:缓存热点数据;用户标识信息等。

2.2 string——sds动态字符串

扩容策略:当长度小于1M时,加倍扩容;超过1M每次只扩容1M;字符串最大为512M。

存储内容:既可以存储字符串,也可以存储其它二进制数据,例如二进制协议数据protobuf等。

基本操作

# 赋值与查询
SET key val
SETNX key val# 如果不存在才赋值
GET key
# 增加
INCR key# 累加1
INCRBY key increment
# 减少
DECR key
DECRBY key decrement
# 删除各种类型的kv对
DEL key
# 查看值得数据类型
TYPE key

应用

作为位图使用

# 将其作为二进制数据,位图
SETBIT key offset value
BITCOUNT key start end
GETBIT key offset

对象存储

SET key '{"name":["li", "lou", "la"], "age": [21, 33, 12]}'

累加器

incr num
incrby num 100

分布式锁

# 获取锁
SET lock_key uuid NX EX 10

释放锁:lua脚本,保证原子性

if redis.call("GET", lock_key) == uuid then
    -- 成功释放
    return redis.call("DEL", KEYS[1])
else return 0
end

2.3 list——双向循环链表

列表首尾操作时间复杂度为O(1),中间元素操作时间复杂度为O(n)。

基本操作

LPUSH key e1 e2 ... en # 插入左侧
LPOP key [count] # 弹出左侧
RPUSH key e1 e2 ... en # 掺入右侧
RPOP key [count]
# 查询
LRANGE key start end
# 删除
LREM key count element
# 阻塞弹出,如果列表为空就等待
BRPOP k1 k2 ... kn timout
# 裁剪数据,只保留特定范围的数据
ltrim key start end

应用

栈(先进后出)

LPUSH + LPOP
# 或者
RPUSH + RPOP

队列(先进先出)

LPUSH + RPOP
# 或者
RPUSH + LPOP

阻塞队列

LPUSH + BRPOP
# 或者
RPUSH + BLPOP

异步消息队列

# 同队列操作,只是在不同的系统之间

获取固定窗口的数据记录

# 获取最近50条记录
LTRIM key 0 49

2.4 hash——散列表

数据类型为散列表,保存多个键值对,可以方便修改某个字段的值。

基本命令

# 赋值与查询
hset key f1 v1 f2 v2 ... fn vn
hmset key f1 v1 f2 v2 ... fn vn
hgetall key
hget key field

# 递增
hincrby key field increment
# 查看键值对个数
hlen key
# 删除
hdel key field

应用

通常将hash与其它数据结构组合,完成业务功能


2.5 set——无序集合

基本命令

# 添加元素
SADD key m1 m2 ... mn
# 查看集合所有元素
SMEMBERS key
# 查询元素个数
SCARD key

# 查询集合中是否存在某个元素
SISMEMBER key member
# 从集合中随机返回一个或多个元素,但不删除
SRANDMEMBER key [count]
# 从集合中随机删除一个或多个元素
SPOP key [count]

# 做差集
SDIFF key [key ...]
# 做交集
SINTER key [key ...]
# 做并集
SUNION key [key ...]

应用

抽奖

srandmember key 10

共同关注的人

sinter key1 key2

推荐好友

sdiff john tom # 将john的好友推荐给tom

2.6 zset——有序集合

基础命令

# 插入元素
ZADD key [NX|XX] [CH] [INCR] s1 m1 s2 m2 ... sn mn
# 删除元素
ZREM key m1 m2 ... mn
ZREMRANGEBYSCORE key min max
# 返回score
ZSCORE key member
# 修改score
ZINCRBY key increment member
# 返回元素个数
ZCARD key
# 返回排名
ZRANK key member
# 返回排名范围的member,默认时从小到大排序
ZRANGE key start stop [WITHSCORES]
# 逆序返回
ZREVRANGE key start stop [WITHSOCRES]

应用

排行榜

ZINCRBY players 13 adam
# 返回分数最大前10位player
ZREVRANGE players 0 9 withscores

延时队列

使用zset保存消息,其score为到期时间,这样可以轮询zset将到期的消息取出处理。

def delay(msg):
    msg.id = str(uuid.uuid4())
    value = json.dumps(msg)
    retry_ts = time.time() + 5
    redis.zadd("delay-queue", retry_ts, value)
    
def loop():
    while True:
        values = redis.zrangebyscore("delay-queue", 0, time.time(), start=0, num=1)
        if not values:
            time.sleep(1)
            continue
        value = values[0]
        success = redis.zrem("delay-queue", value)
        # 保证原子性
        if success:
            msg = json.loads(value)
            handle_msg(msg)

分布式定时器

image-20241126192125666

生产者将定时任务利用hash分配到不同的redis中,每个redis有一个dispather进程,不断从中获取到期的定时任务并发布到不同的消费者中。

时间窗口限流

限定用户的某个行为在指定的可动态变化的时间范围内最多发生N次

local function is_action_allowed(res, userid, action, period, max_count)
    local key = tab_concat({"hist", userid, action}, ":")
    local now = zv.time()
    
    red:init_pipeline()
    -- 记录行为
    red:zadd(key, now, now)
    -- 移除时间窗口外的行为
    red:zremrangebyscore(key, 0, now - period * 100)
    -- 获取时间窗口内的行为数量
    red:zcard(key)
    -- 设置过期时间
    red:expire(key, period + 1)
    local res = red:commit_pipeline()
    return res[3] <= max_count
end

2. 如何设计kv

2.1 如何设计key

对于单个功能的单个key,使用有意义的名字

SET name lee

对于相同功能的多个key,使用有意义的字段并用冒号分隔。

SETBIT sign:lee:202410 12 1

学习参考

学习更多相关知识请参考零声 github


原文地址:https://blog.csdn.net/leedcanDD/article/details/144067687

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!