服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Redis - 如何优化 Redis 扫描性能

如何优化 Redis 扫描性能

2024-03-12 15:25小技术君 Redis

Redis 的逻辑数据库为在单个 Redis 实例中组织和管理数据提供了强大的机制。在本文中,我将展示如何利用逻辑数据库来提升 Redis 查询性能。

Redis 是一款强大而多才多艺的内存数据存储,被广泛用于缓存、会话管理、实时分析等场景。Redis 的一个关键特性是其对逻辑数据库的支持,使用户能够在单个 Redis 实例中对数据进行分区。这些逻辑数据库提供了隔离和在键方面的不同命名空间,从而实现更有效的数据管理和组织。在本文中,我将展示如何利用逻辑数据库来提升 Redis 查询性能。

如何优化 Redis 扫描性能

逻辑数据库

Redis 支持多个逻辑数据库,通常称为“数据库编号”或“DB”。每个逻辑数据库都是相互隔离的,一个数据库中存储的数据无法直接从另一个数据库中访问。这种隔离提供了一种对数据进行逻辑分区的方式。在 Redis 中,键在数据库内是唯一的。因此,不同的数据库为键提供了独立的命名空间,允许在不发生冲突的情况下在不同的数据库中使用相同的键。

如何优化 Redis 扫描性能

带有逻辑数据库和共享资源(CPU 和内存)的 Redis 实例

虽然逻辑数据库提供了隔离,但它们仍然在单个 Redis 实例内共享相同的底层物理资源(内存、CPU 等)。因此,对一个数据库的大量使用可能潜在地影响其他数据库的性能。

扫描性能

尽管 Redis 不是专为像传统关系型数据库那样的复杂查询而设计的,但在某些情况下,您可能需要获取具有相同前缀的一组键。这是一个常见的需求,特别是在键按层次结构组织或按公共标识符分组的场景中。

让我们深入探讨一个性能查询取决于数据库大小的场景。假设您正在使用 Redis 缓存最近访问您网站的用户的值,TTL(生存时间)为 24 小时。这些缓存的值存储在前缀为 user_id 下。此外,您还有一个用于当前正在使用您服务的用户的 Active Users 缓存,前缀为 active_user_id,TTL 为 2 小时。现在,您有一个定期检查有多少活跃用户并使用 Active Users 缓存的过程。以下是性能如何受数据库大小影响的一个示例。

随着越来越多的用户访问您的网站并将其数据缓存在 Redis 中,前缀为 user_id 的数据库大小将增长。令人惊讶的是,即使活跃用户数量稳定,扫描活跃用户的速度也可能变慢。这是因为 SCAN 命令遍历数据库中的所有键,并之后应用前缀模式。请参阅以下实现。我们有一个简单的函数,用于使用给定前缀向 Redis 数据库填充随机记录。

import random
import redis
import string

def populate_db(host, port, db_number, key_prefix, n):
    r = redis.Redis(host=host, port=port, db=db_number)

    # 生成并将随机数据加载到 Redis
    for i in range(n):
        suffix = ''.join(random.choices(string.ascii_letters, k=5))
        key = f"{key_prefix}{suffix}"
        value = ''.join(
            random.choices(string.ascii_letters + string.digits, k=5),
        )
        r.set(key, value)

    print("数据加载到 Redis。")

在 Redis 中,SCAN 命令用于安全而高效地遍历数据库中的键。使用基于游标的迭代方法与 SCAN 而不是一次性获取所有键(KEYS <prefix>)的主要原因是确保该操作不会阻塞 Redis 服务器或在数据库较大的情况下对其性能产生负面影响。

import redis
import time

def scan_redis_by_pattern(host, port, db_number, pattern):
    r = redis.Redis(host=host, port=port, db=db_number)
    num_keys = r.dbsize()
    print(f"DB={db_number} 的键数量: {num_keys}")

    cursor = 0
    keys = []
    while True:
        cursor, partial_keys = r.scan(cursor, match=pattern)
        keys.extend(partial_keys)
        if cursor == 0:
            break
    return keys

现在我们根据数据库中的 user_id 记录数量检查 active_user_id 查询性能。

host = 'localhost'
port = 6379
pattern = 'active_user_id:*'
db_number = 0

# populate_db(host, port, db_number, "active_user_id:", 1)
for n in [10, 1000, 10000]:
    populate_db(host, port, db_number, "user_id:", n)
    start = time.time()
    keys = scan_redis_by_pattern(host, port, db_number, pattern)
    print(
        f"Keys: {keys}, Duration: {time.time() - start}s",
    )

我们得到以下结果:

数据加载到 Redis。
DB=0 的键数量: 11
Keys: [b'active_user_id:aTtsr'], Duration: 0.004511117935180664s

数据加载到 Redis。
DB=0 的键数量: 1011
Keys: [b'active_user_id:aTtsr'], Duration: 0.051651954650878906s

数据加载到 Redis。
DB=0 的键数量: 100999
Keys: [b'active_user_id:aTtsr

'], Duration: 4.748287916183472s

随着数据库中 user_id 键的数量增加,执行 active_user_id 查询所需的时间也会成比例增加(从几毫秒到几秒)。这突显了在设计和管理 Redis 数据库时考虑数据库大小和性能影响的重要性。

如果将 active_user_id 和 user_id 记录保持在不同的逻辑数据库中,那么 user_id 键的数量增加将不会影响 active_user_id 扫描。

数据加载到 Redis。
DB=0 的键数量: 1000990
DB=1 的键数量: 1
Keys: [b'active_user_id:DsHfN'], Duration: 0.003325939178466797s

正如您所见,将数据分隔到逻辑数据库中是一种简单而有效的设计策略,可用于提升 Redis 性能。

结论

Redis 的逻辑数据库为在单个 Redis 实例中组织和管理数据提供了强大的机制。通过将数据划分到独立的逻辑数据库中,用户可以实现更好的隔离和更高效的数据访问。然而,必须注意共享内存和 CPU 利用率的潜在性能影响。

原文地址:https://mp.weixin.qq.com/s?__biz=MzU0NDMzMjY5Ng==&mid=2247489408&idx=1&sn=6f7110c7c6c7c5c2d4cf2d6e8cee2233

延伸 · 阅读

精彩推荐
  • Redis浅谈为什么单线程的redis那么快

    浅谈为什么单线程的redis那么快

    本文主要介绍了为什么单线程的redis那么快,主要介绍了几点原因,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考...

    假装懂编程5862021-11-17
  • Redis详解Redis基本命令与使用场景

    详解Redis基本命令与使用场景

    REmote DIctionary Server(Redis)是一个由Salvatore Sanfilippo写的key-value 存储系统,是跨平台的非关系型数据库,是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网...

    Grey Zeng8662021-08-08
  • RedisSpring boot+redis实现消息发布与订阅的代码

    Spring boot+redis实现消息发布与订阅的代码

    这篇文章主要介绍了Spring boot+redis实现消息发布与订阅,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值需要的朋友...

    源码分析8502020-05-31
  • Redis浅谈Redis缓存有哪些淘汰策略

    浅谈Redis缓存有哪些淘汰策略

    redis用做缓存是一种非常常见的手段,然而由于内存大小的限制,会导致redis在内存空间满了以后需要处理继续存入的数据,所以就需要淘汰策略,本文就详...

    XiaoLin_Java4262021-09-17
  • Redisredis分布式锁之可重入锁的实现代码

    redis分布式锁之可重入锁的实现代码

    相信大家都知道可重入锁的作用防止在同一线程中多次获取锁而导致死锁发生,本文通过几个例子给大家分享redis分布式锁之可重入锁的实现代码,对redi...

    _否极泰来8992021-08-05
  • RedisRedis上实现分布式锁以提高性能的方案研究

    Redis上实现分布式锁以提高性能的方案研究

    这篇文章主要介绍了Redis上实现分布式锁以提高性能的方案研究,其中重点需要理解异步算法与锁的自动释放,需要的朋友可以参考下 ...

    Kelly6952019-10-27
  • RedisRedis数据库基础知识复习(图解)

    Redis数据库基础知识复习(图解)

    在网上看到一篇很不错的 Redis 文章,内容很精炼,而且图画的非常棒,所以分享给大家一起拜读拜读,主要说了「Redis 介绍、Redis 架构、Redis 持久化」这...

    小林coding7292022-11-02
  • RedisRedis主从复制原理和复制方式那点事!

    Redis主从复制原理和复制方式那点事!

    在Redis中主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器(数据备份了)。被复制的服务器称为主服务器(master),对主服务器进行复制...

    小许code4882023-12-25