Five data types and usage scenarios of Redis

1. Five data types of Redis

1. String type

a. Purpose

  • Store string type data, including text, numbers, etc.

b. Common commands

  • SET key value: set key-value pair
  • GET key: Get the value of the specified key
  • INCR key: Add 1 to the value corresponding to the key
  • DECR key: decrement the value corresponding to the key by 1

Sample code:

import redis

# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)

# 设置键值对
r.set('name', 'Lucy')

# 获取键对应的值
print(r.get('name'))

# 值加1
r.incr('age')

# 值减1
r.decr('age')

2. Hash type

a. Purpose

  • Store some data with corresponding relationship, such as user information.

b. Common commands

  • HSET key field value: set the value of a field in hash type data
  • HGET key field: Get the value of a field in hash type data
  • HGETALL key: Get all fields and values ​​in hash type data

Sample code:

import redis

# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)

# 设置哈希类型数据
r.hset('user', 'name', 'Lucy')
r.hset('user', 'age', 18)

# 获取哈希类型数据中某个域的值
print(r.hget('user', 'name'))

# 获取哈希类型数据中所有域和值
print(r.hgetall('user'))

3. List type

a. Purpose

  • Stores a set of ordered string type data, which can be used to implement scenarios such as message queues and task lists.

b. Common commands

  • LPUSH key value: Insert a value from the left side of the list
  • RPUSH key value: Insert a value from the right side of the list
  • LPOP key: Pop a value from the left of the list
  • RPOP key: Pop a value from the right side of the list

Sample code:

import redis

# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)

# 向列表左侧插入两个值
r.lpush('task', 'task1')
r.lpush('task', 'task2')

# 向列表右侧插入一个值
r.rpush('task', 'task3')

# 从列表左侧弹出一个值
print(r.lpop('task'))

# 从列表右侧弹出一个值
print(r.rpop('task'))

4. Collection type

a. Purpose

  • Store a set of unordered string type data, which is often used to deduplicate and quickly determine whether an element exists in the set.

b. Common commands

  • SADD key member: Add an element to the collection
  • SMEMBERS key: Get all elements in the collection
  • SISMEMBER key member: Determine whether an element exists in the collection

Sample code:

import redis

# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)

# 向集合中添加两个元素
r.sadd('students', 'Lucy', 'Jack')

# 获取集合中所有元素
print(r.smembers('students'))

# 判断某元素是否存在集合中
print(r.sismember('students', 'Lucy'))

5. Ordered collection type

a. Purpose

  • Store a set of ordered string data, each element has a corresponding score, which can be used in scenarios such as leaderboards.

b. Common commands

  • ZADD key score member: Add an element and score to the ordered set
  • ZRANGEBYSCORE key min max: returns all elements in the sorted set whose scores are within the given interval
  • ZREVRANGE key start stop [WITHSCORES]: Return a part of elements in the sorted set sorted by scores from large to small, and you can choose to return scores at the same time

Sample code:

import redis

# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)

# 向有序集合中添加三个元素和分数
r.zadd('score', {
    
    'Lucy': 90, 'Jack': 85, 'Mike': 92})

# 返回有序集合中分数在给定区间内的所有元素
print(r.zrangebyscore('score', min=85, max=92))

# 返回有序集合中按照分数从大到小排序的一部分元素,并返回分数
print(r.zrevrange('score', start=0, stop=1, withscores=True))

2. Redis usage scenarios

Redis is an efficient key-value pair database, which is widely used in the following five scenarios because of its fast speed, support for rich data types and flexible configuration:

1. Cache system

Redis can store commonly used data in memory, and set the expiration time to realize the caching function. When the application needs the data, it can be obtained directly from Redis, avoiding the IO operation of reading data from the disk, thereby improving the response time and throughput of the system.

# 以字符串类型为例,在 Python 中使用 Redis 实现缓存功能的示例代码
import redis

# 创建 Redis 客户端
redis_client = redis.Redis(host='localhost', port=6379, db=0)

def get_data_from_cache(key):
    """
    从 Redis 的缓存中获取数据
    """
    data = redis_client.get(key)
    if data is not None:
        # 如果缓存中存在对应 key 的数据,则直接返回
        return data
        
    # 如果缓存中不存在对应 key 的数据,则去数据库中查询并写入缓存
    data = fetch_data_from_database(key)
    redis_client.set(key, data, ex=3600)  # 设置过期时间为 1 小时
    return data

2. Counter

The incr/decr command of Redis can perform atomic increment/decrement operations on a key, so it is often used as a counter. For example, counting the number of website visits, sales of products, number of likes for comments, etc.

# 在 Python 中使用 Redis 的 incr/decr 实现计数器功能的示例代码
def increase_counter(key):
    """
    自增一个计数器,返回自增后的值
    """
    return redis_client.incr(key)

def decrease_counter(key):
    """
    自减一个计数器,返回自减后的值
    """
    return redis_client.decr(key)

3. Message queue

Redis provides a message queue function, which can be used as a lightweight message middleware and supports multiple producers and consumers. Producers can use lpush or rpush to insert messages into a list, while consumers use blpop or brpop to pop messages from the list and process them.

# 在 Python 中使用 Redis 实现消息队列功能的示例代码

import threading
import time

def produce_message(queue_name: str):
    """
    生产者向队列中插入消息
    """
    for i in range(10):
        message = f"Message {i}"
        redis_client.lpush(queue_name, message)  # 左边插入消息
        print(f"Produce Message: {message}")
        time.sleep(0.5)

def consume_message(queue_name: str):
    """
    消费者从队列中弹出消息并进行处理
    """
    while True:
        message = redis_client.brpop(queue_name, timeout=3)  # 从右边弹出消息
        if message is not None:
            print(f"Consume Message: {message[1].decode()}")

# 创建生产者和消费者线程
t1 = threading.Thread(target=produce_message, args=('my_queue',))
t2 = threading.Thread(target=consume_message, args=('my_queue',))

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

4. Leaderboard system

Redis provides an ordered set (SortedSet) structure, which supports sorting members according to a certain field, so it can be used to implement a leaderboard system. For example, count the number of times music is played, the amount of news read, and the ranking of users.

# 在 Python 中使用 Redis 实现排行榜系统的示例代码

def update_ranking(username: str, score: float):
    """
    更新排行榜,以 username 为成员、score 为排序指标
    """
    redis_client.zadd('ranking', {
    
    username: score})

def get_top_n(n: int):
    """
    获取排行榜前 n 名
    """
    return redis_client.zrevrangebyscore('ranking', '+inf', '-inf', start=0, num=n, withscores=True)

5. Distributed lock

The setnx command of Redis can set the value of the key when the key does not exist, so distributed locks can be implemented based on this. When a process performs a locking operation, it first tries to use setnx to occupy the key of the lock. If the return value is 1, it means that the lock has been obtained; otherwise, it means that the lock has been occupied by other processes. Wait for a while and try again. Locking and unlocking operations need to use the same key and value to succeed.

# 在 Python 中使用 Redis 实现分布式锁的示例代码

def acquire_lock_with_timeout(lockname: str, acquire_timeout: int=10):
    """
    获取分布式锁,等待 acquire_timeout 秒后仍未获得锁则放弃
    """
    identifier = str(uuid.uuid4())
    end = time.time() + acquire_timeout
    
    while time.time() < end:
        if redis_client.setnx(lockname, identifier):
            # 成功获取到锁
            return identifier
        elif not redis_client.ttl(lockname):
            # 如果锁没有设置过期时间,则设置一个过期时间,避免死锁
            redis_client.expire(lockname, 10)
            
        # 等待一段时间后进行重试
        time.sleep(0.1)
        
    return False

def release_lock(lockname: str, identifier: str):
    """
    释放分布式锁,需要传入获取锁时返回的 identifier
    """
    pipline = redis_client.pipeline(True)
    while True:
        try:
            # 监视锁,保证在执行事务期间锁没有被其他进程修改
            pipline.watch(lockname)

            if pipline.get(lockname).decode() == identifier:
                # 删除锁
                pipline.multi()
                pipline.delete(lockname)
                pipline.execute()
                return True

            # 锁已被其他进程修改,放弃执行事务
            pipline.unwatch()
        except redis.exceptions.WatchError:
            # 如果在执行pipline.watch()和pipline.multi()之间,锁的值被其他进程改变,会抛出 WatchError 异常
            continue
        finally:
            pipline.reset()
    return False

Guess you like

Origin blog.csdn.net/u010349629/article/details/130895567