简单认识redis - 7redis实现分布式

1.为什么要实现分布式

一、提升性能

  1. 资源利用最大化
    • 在单台机器上,硬件资源(如 CPU、内存、磁盘 I/O 等)是有限的。随着业务的增长,单个服务器可能无法满足大量并发请求的处理需求。通过分布式系统,可以将负载分散到多个节点上,每个节点处理一部分请求,从而充分利用各个节点的资源,提高整体的处理能力。
    • 例如,一个大型电商网站在促销活动期间会面临海量的用户访问请求。如果仅依靠单台服务器,可能会因为 CPU 满载或内存不足导致响应缓慢甚至系统崩溃。而分布式系统可以将用户请求分配到多个服务器上同时处理,提高响应速度。
  2. 并行处理
    • 分布式系统允许对任务进行并行处理。对于一些复杂的计算任务,如大数据分析、机器学习中的模型训练等,可以将任务分解成多个子任务,并在不同的节点上同时执行这些子任务。
    • 例如,在处理海量数据的排序任务时,可以将数据分成多个部分,每个部分在一个独立的节点上进行排序,最后再将各个部分的排序结果合并起来,这样可以大大缩短任务的处理时间。

二、提高可用性和容错性

  1. 避免单点故障
    • 在单服务器架构中,如果服务器出现故障(如硬件故障、软件故障、网络故障等),整个系统将无法正常运行。而分布式系统由多个节点组成,即使某个节点出现故障,其他节点仍然可以继续提供服务,系统整体不会完全瘫痪。
    • 例如,一个分布式文件存储系统中,数据被复制到多个节点上。如果其中一个存储节点发生故障,用户仍然可以从其他副本节点获取数据,从而保证了系统的可用性。
  2. 容错性增强
    • 分布式系统可以通过冗余备份和故障恢复机制来提高容错能力。可以在多个节点上保存相同的数据副本,当某个节点的数据损坏或丢失时,可以从其他副本节点恢复数据。
    • 例如,在一些分布式数据库系统中,采用主从复制的方式,主节点负责数据的写入操作,从节点复制主节点的数据并提供读操作。当主节点出现故障时,可以迅速将从节点提升为新的主节点,继续提供服务并恢复数据。

三、满足大规模数据存储和管理需求

  1. 存储容量扩展
    • 随着业务的发展,数据量会不断增长,单台服务器的存储容量可能无法满足需求。分布式系统可以通过添加更多的存储节点来扩展存储容量,几乎没有理论上的存储上限。
    • 例如,云存储服务提供商(如 Amazon S3、Google Cloud Storage 等)采用分布式存储架构,可以存储海量的用户数据,通过不断增加存储节点来满足用户日益增长的存储需求。
  2. 数据分布与管理
    • 对于大规模数据,分布式系统可以采用合适的数据分布策略(如数据分片等)将数据合理地分布在不同的节点上,便于数据的管理、查询和更新操作。
    • 例如,在一个全球范围的社交网络应用中,用户数据可以根据地域或用户 ID 等规则分布在不同的服务器上,这样既方便了数据的就近访问,也提高了数据管理的效率。

二. Redis 实现分布式的几种常见方式

一、分布式锁

  1. 原理

    • 在分布式系统中,不同进程可能需要对共享资源进行互斥访问。Redis 的 SETNX(SET if Not eXists)命令可以用于实现分布式锁。当一个进程想要获取锁时,它尝试使用 SETNX 命令设置一个特定的键值对(例如,键为 "lock_key",值可以是进程标识或随机字符串)。如果 SETNX 命令返回 1,表示锁获取成功,因为键不存在;如果返回 0,表示锁已经被其他进程获取。
    • 为了防止死锁,获取锁的进程还需要设置一个过期时间(可以使用 EXPIRE 命令)。这样,即使进程在持有锁期间崩溃,锁也会在过期后自动释放。
  2. 示例代码(使用 Python 和 Redis - Python 客户端 redis - py)

    复制代码
    import redis
    import time
    
    def acquire_lock(conn, lock_name, acquire_timeout = 10):
        identifier = str(uuid.uuid4())
        end = time.time() + acquire_timeout
        while time.time() < end:
            if conn.setnx(lock_name, identifier):
                conn.expire(lock_name, 10)
                return identifier
            elif not conn.ttl(lock_name):
                conn.expire(lock_name, 10)
            time.sleep(0.001)
        return False
    
    def release_lock(conn, lock_name, identifier):
        pipe = conn.pipeline(True)
        while True:
            try:
                pipe.watch(lock_name)
                if pipe.get(lock_name) == identifier:
                    pipe.multi()
                    pipe.delete(lock_name)
                    pipe.execute()
                    return True
                pipe.unwatch()
                break
            except redis.exceptions.WatchError:
                pass
        return False
    
    
    r = redis.Redis(host='localhost', port = 6379, db = 0)
    lock_name = "my_lock"
    identifier = acquire_lock(r, lock_name)
    if identifier:
        # 执行业务逻辑
        print("获取锁成功,执行业务逻辑")
        release_lock(r, lock_name, identifier)
    else:
        print("获取锁失败")

二、分布式计数器

  1. 原理

    • Redis 的 INCR(INCRement)命令可以用于实现分布式计数器。多个进程可以安全地对同一个 Redis 键执行 INCR 操作,Redis 会原子性地增加键的值。例如,可以用它来统计分布式系统中的某个事件发生的次数,如网站的访问次数、消息的发送次数等。
  2. 示例代码(继续使用 Python 和 redis - py)

    复制代码
    import redis
    
    r = redis.Redis(host='localhost', port = 6379, db = 0)
    counter_key = "visit_count"
    r.incr(counter_key)
    count = r.get(counter_key)
    print(f"当前访问次数: {count.decode('utf - 8')}")

三、数据分片(Sharding)

  1. 原理
    • 当数据量过大时,将数据分布到多个 Redis 实例(节点)上可以提高存储能力和性能。有多种数据分片方法,例如范围分片、哈希分片等。
    • 哈希分片是比较常用的一种。通过对数据的键进行哈希计算,然后根据哈希结果将数据分配到不同的 Redis 节点。例如,计算键的 CRC16 或 CRC32 哈希值,然后将哈希值对节点数量取模,确定数据应该存储到哪个节点。
  2. 示例实现(概念性)
    • 假设我们有 3 个 Redis 节点,节点 1(IP: 192.168.1.101)、节点 2(IP: 192.168.1.102)和节点 3(IP: 192.168.1.103)。

    • 对于要存储的键 "user:123",首先计算其哈希值(假设使用 CRC16),得到哈希值为 12345。然后 12345 % 3 = 0,所以数据应该存储到节点 1。

    • 在实际应用中,需要构建一个中间层来处理数据分片逻辑,使得应用程序不需要关心数据具体存储在哪个节点,这个中间层负责根据分片规则将操作转发到正确的 Redis 节点。

四、Redis Cluster(集群模式)

  1. 原理
    • Redis Cluster 是 Redis 官方提供的分布式解决方案。它将数据自动分片到多个节点上,并且提供了一定的高可用性。
    • Redis Cluster 使用哈希槽(Hash Slot)来进行数据分片,共有 16384 个哈希槽。每个节点负责一部分哈希槽。当客户端想要操作某个键时,通过对键进行 CRC16 哈希计算,然后对 16384 取模,得到哈希槽编号,再根据哈希槽编号找到负责该槽的节点进行操作。
    • 它还提供了主从复制功能,每个主节点可以有一个或多个从节点。当主节点故障时,从节点可以被提升为新的主节点,保证了系统的可用性。
  2. 部署和使用
    • 部署 Redis Cluster 通常需要配置多个 Redis 节点,指定每个节点的角色(主节点或从节点)、IP 地址、端口等信息。

    • 在应用程序中,使用支持 Redis Cluster 的客户端(如 redis - py - cluster 等)来与集群进行交互。客户端会自动根据键计算哈希槽,并将操作发送到正确的节点。例如:

      from rediscluster import RedisCluster

      startup_nodes = [{"host": "192.168.1.101", "port": 7000},
      {"host": "192.168.1.102", "port": 7000},
      {"host": "192.168.1.103", "port": 7000}]
      rc = RedisCluster(startup_nodes = startup_nodes, decode_responses=True)

      rc.set('key1', 'value1')
      value = rc.get('key1')
      print(value)

相关推荐
Elastic 中国社区官方博客4 小时前
在 Elasticsearch 中使用 Mistral Chat completions 进行上下文工程
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
编程爱好者熊浪6 小时前
两次连接池泄露的BUG
java·数据库
cr7xin7 小时前
缓存三大问题及解决方案
redis·后端·缓存
TDengine (老段)8 小时前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq7422349848 小时前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE8 小时前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy12393102169 小时前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎9 小时前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
杨云龙UP9 小时前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql
l1t9 小时前
利用DeepSeek辅助修改luadbi-duckdb读取DuckDB decimal数据类型
c语言·数据库·单元测试·lua·duckdb