三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Redis Stack部署与实战:从安装到高可用,解锁实时数据平台

Redis Stack部署与实战:从安装到高可用,解锁实时数据平台

1. 从Redis到Redis Stack:为什么你需要这个“全家桶”

如果你接触过Redis,大概率是从它的缓存功能开始的。一个简单的SETGET命令,就能让数据库查询压力骤降,性能立竿见影。但如果你以为Redis只是个缓存中间件,那可能就错过了它最近几年最激动人心的进化。我最初也是抱着“装个缓存”的心态去部署Redis,直到在项目中遇到了更复杂的需求:比如,想对用户行为做实时统计和排名,用原生的Sorted Set写起来异常繁琐;又比如,想对存储在Redis里的JSON文档进行灵活查询,而不是一股脑儿取出来在应用层处理。这些场景让我开始寻找更强大的工具,最终发现了Redis Stack。

Redis Stack不是一个全新的数据库,而是Redis官方推出的一个“增强版”发行版。你可以把它理解为一个预装了多个顶级扩展的Redis服务器,开箱即用。它的核心是Redis本身,但在此基础上,捆绑了四个强大的模块:RedisJSON、RedisSearch、RedisTimeSeries和RedisBloom。这意味着,部署一个Redis Stack,你就同时拥有了一个文档数据库、一个搜索引擎、一个时间序列数据库和一个概率数据结构库。对于现代应用开发,尤其是微服务、实时分析、物联网这些场景,这种“多合一”的能力极具吸引力。你不用再费心去分别寻找、编译、集成各种第三方模块,官方已经为你做好了兼容性测试和打包,稳定性和性能都有保障。

最近在技术社区里,关于“本地部署”、“一体化部署”的讨论非常热烈,无论是ollama、dify还是minimax的本地部署,核心诉求都是将强大的能力收归自有环境,确保数据隐私、降低延迟和拥有完全的控制权。Redis Stack的部署理念与此高度契合。它让你能在自己的服务器、虚拟机甚至Docker容器里,快速搭建起一个功能完备的实时数据平台。无论是作为微服务架构中的核心数据层,还是为你的AI应用(比如本地部署的LLM)提供高速的向量检索支持(通过RedisSearch的向量搜索功能),Redis Stack都能扮演关键角色。接下来,我将从一个实践者的角度,带你完成从部署、安装到核心功能使用的完整旅程,并分享那些官方文档里不会写的配置细节和避坑经验。

2. 部署前的决策:选择适合你的安装方式

部署Redis Stack和部署传统Redis一样,有多种路径可选。选择哪种方式,取决于你的使用场景、技术栈和环境约束。没有最好的,只有最合适的。这里我详细拆解三种主流方式:Docker部署、原生包安装和源码编译,并告诉你我通常在什么情况下会怎么选。

2.1 Docker部署:敏捷开发与云原生环境的首选

Docker无疑是当前最流行的部署方式,尤其适合开发、测试环境以及基于Kubernetes的云原生架构。它的优势在于环境隔离、依赖统一和极致的可重复性。

操作步骤与核心命令:

  1. 拉取镜像:Redis Stack的Docker镜像托管在Docker Hub和Redis自家的容器注册中心。官方推荐使用后者以获得最佳性能和支持。

    # 使用Docker Hub镜像(通用) docker pull redis/redis-stack:latest # 或使用Redis官方容器注册中心(推荐) docker pull redis/redis-stack-server:latest

    这里有一个关键细节:redis/redis-stack镜像包含了RedisInsight(一个图形化管理工具)的Web界面,而redis/redis-stack-server是纯服务器版本,更轻量。对于生产环境或无UI需求的容器,我强烈建议使用-server版本。

  2. 运行容器:最基本的运行命令如下,它将容器内的6379端口映射到主机的6379端口。

    docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest

    解释一下参数和端口:

    • -p 6379:6379:这是Redis服务的默认端口,你的应用程序将通过这个端口连接。
    • -p 8001:8001:这是RedisInsight Web管理界面的端口。如果你用的是-server镜像,则不需要映射8001端口。
    • 数据持久化是生产部署的生命线。Redis默认将所有数据保存在内存中,虽然也支持RDB快照和AOF日志两种持久化方式,但在Docker中,你必须将数据目录挂载到宿主机,否则容器重启后数据将全部丢失。
      docker run -d --name redis-stack \ -p 6379:6379 \ -p 8001:8001 \ -v /your/local/data:/data \ redis/redis-stack:latest
      这条命令将容器内的/data目录挂载到了宿主机的/your/local/data路径。Redis的持久化文件(dump.rdbappendonly.aof)就会写在这里。请务必确保宿主机目录存在且Docker进程有写入权限。

Docker部署的避坑经验:

  • 内存与交换空间:在Docker或Kubernetes中,务必为容器设置明确的内存限制(-mresources.limits.memory)。Redis的性能极度依赖内存,如果容器内存不足被系统OOM Killer终止,或者频繁使用交换空间,性能会急剧下降。我的经验法则是,限制值应略高于你预估的业务数据量,并为RDB快照创建等操作留出余量。
  • 网络模式:在Docker Compose或K8s中,确保相关服务(你的应用容器)与Redis Stack容器在同一个自定义网络中,使用容器名进行服务发现,这比依赖固定的主机IP和端口要稳定得多。
  • 生产环境配置:通过环境变量或自定义配置文件来覆盖默认配置。例如,设置密码、调整持久化策略:
    docker run -d --name redis-stack \ -p 6379:6379 \ -v /your/local/data:/data \ -v /your/local/redis-stack.conf:/etc/redis-stack.conf \ -e REDIS_ARGS="--requirepass your-strong-password --appendonly yes" \ redis/redis-stack-server:latest
    这里我通过REDIS_ARGS环境变量传递了Redis服务器的启动参数,设定了密码并开启了AOF持久化。更复杂的配置建议使用挂载配置文件的方式。

2.2 原生包安装:追求极致性能与控制力的选择

如果你在物理机或虚拟机上部署,并且希望获得最直接的控制和潜在的最佳性能,那么使用系统包管理器(如apt、yum)安装是最佳选择。这种方式服务以系统守护进程运行,管理起来更符合运维习惯。

Ubuntu/Debian 系统安装步骤:

  1. 导入GPG密钥并添加仓库:这是为了确保软件包的来源可信。
    curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
  2. 更新并安装
    sudo apt-get update sudo apt-get install redis-stack-server
    安装完成后,服务会自动启动。你可以使用systemctl status redis-stack-server来检查运行状态。

RHEL/CentOS/Rocky Linux 系统安装步骤:

  1. 添加仓库并安装
    curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /etc/yum.repos.d/redis.repo echo "[redis-stack] name=Redis Stack baseurl=https://packages.redis.io/redislabs/redislabs-rpm/rhel/8/x86_64/ enabled=1 gpgcheck=1 gpgkey=https://packages.redis.io/gpg" | sudo tee /etc/yum.repos.d/redis-stack.repo sudo yum install redis-stack-server

原生安装后的关键配置:安装包通常会提供一个默认的配置文件,位置在/etc/redis-stack/redis-stack.conf。在投入生产前,你必须修改它。

  • 绑定地址:默认的bind 127.0.0.1只允许本地连接。如果你需要从其他服务器访问,需要将其改为bind 0.0.0.0(监听所有接口)并务必配合防火墙和密码认证,否则等于将数据库暴露在公网。
  • 守护进程与日志:确保daemonize yes,并以合适的日志级别(loglevel notice)和路径(logfile /var/log/redis/redis-stack.log)运行。
  • 数据目录:检查dir /var/lib/redis,确保该目录有足够的磁盘空间和正确的权限(redis用户可写)。
  • 内存策略maxmemory参数必须设置。一个常见的误区和灾难是忘记设置此参数,导致Redis无限使用内存,最终拖垮整个服务器。根据你的系统内存,设置一个安全值,例如maxmemory 4gb。同时,设置maxmemory-policy allkeys-lruvolatile-lru来定义内存满时的淘汰策略。

2.3 源码编译:针对特定系统或深度定制的最后手段

除非你有非常特殊的需求(比如需要针对特定的CPU架构进行优化,或者想使用某个尚未发布到稳定版的分支),否则我不推荐初学者或生产环境使用源码编译。这个过程涉及依赖管理、编译选项,复杂度较高。

如果你确实需要,大致流程如下:

  1. 安装编译依赖:gccmakelibc6-dev等。
  2. 从Redis GitHub仓库下载Redis Stack的源码(注意,Redis Stack的模块源码集成在同一个仓库中)。
  3. 进入源码目录,执行makemake install
  4. 手动处理服务脚本、配置文件和数据目录。

这种方式将配置和管理的所有责任都交给了你,需要深厚的Linux系统管理知识。对于绝大多数场景,Docker或原生包安装已经足够优秀。

3. 验证部署与初识RedisInsight

部署完成后,第一件事不是急着写代码,而是验证服务是否正常运行,并熟悉一下这个强大的管理工具——RedisInsight。它能让你直观地看到Redis Stack的“全家桶”能力。

3.1 基础连接与服务状态检查

无论通过哪种方式安装,都可以使用Redis自带的命令行工具redis-cli进行连接测试。

# 连接本地默认端口的Redis redis-cli # 如果设置了密码,使用-a参数(注意,密码会出现在历史命令中,生产环境不建议) # 更安全的方式是:先连接,再使用AUTH命令 redis-cli 127.0.0.1:6379> AUTH your-password OK # 执行一个简单的PING-PONG测试 127.0.0.1:6379> PING PONG # 查看服务器信息,这里包含了Redis版本、运行模式、模块列表等关键信息 127.0.0.1:6379> INFO server # Server redis_version:7.2.0 redis_mode:standalone ...

看到PONG回应和正常的INFO输出,说明Redis服务本身已经就绪。

3.2 RedisInsight:你的可视化控制中心

如果你部署的是包含UI的镜像(非-server版)或单独安装了RedisInsight,现在可以通过浏览器访问http://你的服务器IP:8001。首次打开需要添加数据库连接。

添加连接时的注意事项:

  • Host:如果RedisInsight和Redis Stack在同一台机器,用127.0.0.1localhost。如果在容器网络或不同主机,需填写正确的IP或容器名。
  • Port:默认6379。
  • Name:给这个连接起个有意义的名字,如“生产环境-主节点”。
  • Username/Password:如果配置了ACL(访问控制列表)或简单密码,在此处填写。默认安装可能没有密码,但生产环境必须设置

连接成功后,RedisInsight的界面会让你眼前一亮。左侧是导航栏,核心功能包括:

  • Browser:以树状结构浏览所有键,支持按模式搜索,直观展示不同类型键(String, Hash, List, Set, JSON等)的值。
  • CLI:一个增强版的Web命令行界面,不仅支持所有Redis命令,还提供语法高亮、命令提示和历史记录,比单纯的redis-cli友好得多。
  • Profiler:实时监控服务器接收到的所有命令,用于性能分析和调试,可以清晰看到每个命令的执行时间和客户端信息。
  • Slow Log:查看执行时间超过阈值的慢查询,是优化性能的关键工具。
  • Memory Analysis:分析内存使用情况,找出哪些键占用了大量空间。

通过RedisInsight验证模块加载:这是确认Redis Stack“全家桶”功能是否就位的关键一步。在CLI或Browser中,输入命令:

127.0.0.1:6379> MODULE LIST

你会看到一个列表,其中应该包含类似以下输出:

1) 1) "name" 2) "ReJSON" 3) "ver" 4) "20009" 2) 1) "name" 2) "search" 3) "ver" 4) "20409" 3) 1) "name" 2) "timeseries" 3) "ver" 4) "10499" 4) 1) "name" 2) "bf" 3) "ver" 4) "20407"

这分别对应了RedisJSON、RedisSearch、RedisTimeSeries和RedisBloom(BF)四个模块。看到它们,就意味着你可以开始使用这些扩展命令了。

4. 核心模块实战:超越简单键值对

现在,服务已经跑起来了,管理工具也熟悉了。是时候深入核心,看看Redis Stack的四个模块如何解决实际问题。我将通过具体的场景和命令示例来展示它们的威力。

4.1 RedisJSON:把Redis当作文档数据库

传统Redis处理复杂对象时,通常需要序列化成字符串(如JSON字符串)存储,查询和更新部分字段非常低效,需要反序列化-修改-再序列化。RedisJSON引入了原生JSON支持。

场景:存储用户Profile信息。

# 1. 直接存储一个JSON文档 127.0.0.1:6379> JSON.SET user:1000 $ '{"name":"Alice","age":30,"email":"alice@example.com","address":{"city":"Shanghai","zip":"200000"},"tags":["engineer","redis"]}' OK # 2. 点符号获取整个文档或特定字段 127.0.0.1:6379> JSON.GET user:1000 "{\"name\":\"Alice\",\"age\":30,\"email\":\"alice@example.com\",\"address\":{\"city\":\"Shanghai\",\"zip\":\"200000\"},\"tags\":[\"engineer\",\"redis\"]}" 127.0.0.1:6379> JSON.GET user:1000 .name "\"Alice\"" 127.0.0.1:6379> JSON.GET user:1000 .address.city "\"Shanghai\"" # 3. 原子性地更新特定字段,无需读取整个文档 127.0.0.1:6379> JSON.SET user:1000 .age 31 OK 127.0.0.1:6379> JSON.ARRAPPEND user:1000 .tags '"developer"' (integer) 3 # 返回更新后数组的长度 # 4. 数字运算 127.0.0.1:6379> JSON.NUMINCRBY user:1000 .age 1 "32"

实操心得JSON.SET的路径参数$表示文档根目录。对于嵌套字段,使用点符号(.)访问,如.address.city。数组操作有专门的命令如JSON.ARRAPPEND,JSON.ARRINSERT等,非常方便。这极大地简化了缓存用户会话、商品详情等半结构化数据的逻辑。

4.2 RedisSearch:全文检索与二级索引

这是我认为最强大的模块之一。它让Redis具备了像Elasticsearch那样的全文搜索和复杂查询能力,但延迟是亚毫秒级的。

场景:为博客文章建立搜索索引。

# 1. 创建一个索引,定义schema(模式) 127.0.0.1:6379> FT.CREATE blogIdx ON JSON PREFIX 1 "post:" SCHEMA $.title AS title TEXT $.content AS content TEXT $.author AS author TAG $.created_at AS created_at NUMERIC SORTABLE OK

这条命令创建了一个名为blogIdx的索引,作用于所有以post:为前缀的JSON键。它从JSON文档中提取字段:titlecontent作为可全文搜索的TEXT类型;author作为可精确过滤的TAG类型;created_at作为可排序的NUMERIC类型。

# 2. 添加几篇博客文章(JSON文档) 127.0.0.1:6379> JSON.SET post:1 $ '{"title":"Getting Started with Redis Stack","content":"This is a tutorial about Redis Stack...","author":"alice","created_at":1698765432}' OK 127.0.0.1:6379> JSON.SET post:2 $ '{"title":"Advanced Search Patterns","content":"Deep dive into FT.SEARCH queries...","author":"bob","created_at":1698770000}' OK # 索引会自动更新,无需手动操作 # 3. 执行搜索 # 3.1 简单全文搜索 127.0.0.1:6379> FT.SEARCH blogIdx "tutorial" 1) (integer) 1 # 匹配到的文档数量 2) "post:1" # 键名 3) 1) "$" 2) "{\"title\":\"Getting Started with Redis Stack\",\"content\":\"This is a tutorial about Redis Stack...\",\"author\":\"alice\",\"created_at\":1698765432}" # 3.2 带过滤条件的搜索(作者是alice,且内容包含Redis) 127.0.0.1:6379> FT.SEARCH blogIdx "@author:{alice} @content:redis" 1) (integer) 1 2) "post:1" ... # 3.3 范围查询与排序(创建时间在某个范围,按时间倒序) 127.0.0.1:6379> FT.SEARCH blogIdx "@created_at:[1698760000 1698780000]" SORTBY created_at DESC 1) (integer) 2 2) "post:2" 3) 1) "$" 2) "{\"title\":\"Advanced Search Patterns\",\"content\":\"Deep dive into FT.SEARCH queries...\",\"author\":\"bob\",\"created_at\":1698770000}" 4) "post:1" ...

避坑经验:创建索引时,PREFIX参数至关重要,它定义了索引覆盖的键范围。如果漏掉或写错,数据将不会被索引。另外,对于TAG类型字段,查询时值需要用花括号{}包裹,且默认是精确匹配。RedisSearch还支持拼音搜索、同义词、停用词等高级特性,对于中文搜索,需要额外配置分词器(如 Friso 或 Jieba),但这通常需要从源码编译时加入支持,是进阶话题。

4.3 RedisTimeSeries:高效处理时间序列数据

专门为监控指标、物联网传感器数据、应用程序事件等时间序列场景优化。相比用Sorted Set或List来存时间戳-值对,它提供了更专业的压缩算法、聚合查询和过期策略。

场景:记录服务器的CPU使用率。

# 1. 创建一个时间序列 127.0.0.1:6379> TS.CREATE cpu_usage LABELS metric cpu host server-01 OK # 这里添加了标签(LABELS),便于后续按维度查询和聚合。 # 2. 添加数据点(时间戳-值)。时间戳可以自动生成(*),也可以指定(毫秒级)。 127.0.0.1:6379> TS.ADD cpu_usage * 45.6 (integer) 1698765432000 # 返回自动生成的时间戳 127.0.0.1:6379> TS.ADD cpu_usage 1698765433000 48.2 (integer) 1698765433000 # 3. 范围查询 127.0.0.1:6379> TS.RANGE cpu_usage 1698765432000 1698765433000 1) 1) (integer) 1698765432000 2) 45.6 2) 1) (integer) 1698765433000 2) 48.2 # 4. 聚合查询(例如,查询最近1小时的数据,每5分钟计算一个平均值) 127.0.0.1:6379> TS.RANGE cpu_usage 1698765432000 1698765433000 AGGREGATION avg 300000 1) 1) (integer) 1698765432000 2) 46.9 # 这是45.6和48.2在5分钟窗口内的平均值(示例)

核心优势:内存效率极高,支持降采样(downsampling),自动过期(通过RETENTION参数设置),并且与Grafana等监控工具有原生集成。对于需要实时查询历史趋势的场景,比如“显示过去24小时API的99分位响应时间”,RedisTimeSeries比直接往Redis里塞数据要专业和高效得多。

4.4 RedisBloom:概率数据结构解决大数据难题

Bloom Filter(布隆过滤器)是一种空间效率极高的概率数据结构,用于判断一个元素是否可能在一个集合中,或者肯定不在集合中。它存在一定的误判率(False Positive),但绝不会漏判(False Negative)。RedisBloom模块提供了布隆过滤器、布谷鸟过滤器等数据结构。

场景:防止缓存穿透(频繁查询一个不存在的数据,导致请求直接打到数据库)。

# 1. 创建一个布隆过滤器,指定初始容量和错误率 127.0.0.1:6379> BF.RESERVE recent_users 0.01 1000000 OK # 参数:过滤器名,错误率(1%),初始容量(100万)。错误率越低,所需空间越大。 # 2. 将已存在的用户ID添加到过滤器中(例如,从数据库加载热门用户) 127.0.0.1:6379> BF.ADD recent_users user123 (integer) 1 127.0.0.1:6379> BF.ADD recent_users user456 (integer) 1 # 3. 查询一个用户是否存在 127.0.0.1:6379> BF.EXISTS recent_users user123 (integer) 1 # 1表示“可能存在” 127.0.0.1:6379> BF.EXISTS recent_users user999 (integer) 0 # 0表示“肯定不存在” # 4. 批量添加和检查 127.0.0.1:6379> BF.MADD recent_users user789 user101112 1) (integer) 1 2) (integer) 1

应用逻辑:当收到查询请求userXYZ时,先到布隆过滤器BF.EXISTS。如果返回0,可以确定数据库中不存在此用户,直接返回“未找到”,无需查询数据库和缓存,完美解决缓存穿透。如果返回1,则可能存在,此时再去查询缓存或数据库。即使有1%的误判,也只是导致一次不必要的缓存/数据库查询,而不会引起系统雪崩。

注意事项:布隆过滤器一旦创建,其容量和错误率是固定的。如果实际元素数量远超初始容量,误判率会急剧上升。因此,预估容量时要留足余量。对于持续增长的数据集,可以考虑使用可伸缩布隆过滤器(BF.SCAND)或定期重建过滤器。

5. 生产环境配置、安全与监控指南

让Redis Stack在开发环境跑起来只是第一步,让它稳定、安全、高效地服务于生产环境,才是真正的挑战。这部分内容往往是新手最容易忽略,也最容易踩坑的地方。

5.1 安全配置:筑起第一道防线

一个暴露在公网且没有密码的Redis服务器,是黑客最爱的靶子之一。安全配置必须做,且要做对。

  1. 设置强密码:这是最基本的要求。在配置文件redis-stack.conf中修改或添加:

    requirepass YourSuperStrongPassword123!

    重启服务生效。之后所有客户端连接都需要使用AUTH命令或连接时提供密码。

  2. 禁用危险命令:一些命令如FLUSHALL(清空所有数据)、CONFIG(修改配置)在生产环境是极度危险的。可以通过重命名来禁用它们:

    rename-command FLUSHALL "" rename-command CONFIG ""

    这样,即使攻击者获得了访问权限,也无法执行这些破坏性操作。你也可以将它们重命名为一个复杂的、只有管理员知道的字符串,而不是直接禁用。

  3. 启用保护模式并绑定网络:确保配置中包含:

    protected-mode yes bind 127.0.0.1 # 或者绑定到特定的内部网络IP,而非0.0.0.0

    protected-mode是Redis的一个安全网,当没有设置密码且绑定在所有接口时,它只接受本地回环连接。但绝不能依赖于此,正确的做法是设置密码并严格限制bind地址。

  4. 使用ACL进行更细粒度控制(Redis 6.0+):ACL提供了用户级别的权限管理,比单一密码强大得多。

    # 创建一个只能读特定键前缀的用户 127.0.0.1:6379> ACL SETUSER appuser on >appuser_password ~app:* +@read OK

    这条命令创建了一个用户appuser,密码为appuser_password,只允许访问以app:开头的键,并且只拥有读命令的权限。这符合最小权限原则。

5.2 持久化策略:在性能与可靠性间权衡

Redis提供了RDB和AOF两种持久化机制,理解它们的区别并合理配置至关重要。

  • RDB(快照):在指定时间间隔内,生成数据集的时间点快照。文件紧凑,恢复速度快。但会丢失最后一次快照之后的所有数据。
    save 900 1 # 900秒内至少有1个key被更改,则触发保存 save 300 10 # 300秒内至少有10个key被更改 save 60 10000 # 60秒内至少有10000个key被更改 dbfilename dump.rdb dir /var/lib/redis
  • AOF(追加文件):记录每一个写操作命令,以日志形式追加到文件末尾。数据安全性更高,默认每秒同步一次(appendfsync everysec),最多丢失一秒数据。但文件通常比RDB大,恢复速度慢。
    appendonly yes appendfilename "appendonly.aof" appendfsync everysec

我的生产环境配置建议

  • 两者同时启用appendonly yes并配置合理的save规则。这样可以利用RDB快速恢复大部分数据,再用AOF日志重放最近的操作,兼顾速度和安全性。
  • 监控磁盘空间:AOF文件会不断增长,即使有重写机制。确保dir指向的目录有充足空间,并设置监控告警。
  • 备份!备份!备份!:将RDB和AOF文件定期备份到异地(如云存储)。可以结合cron任务和SCPrsync来实现自动化备份。

5.3 内存管理与性能优化

Redis是内存数据库,内存管理是性能的核心。

  1. 必须设置maxmemory:如前所述,这是防止系统崩溃的底线。根据系统总内存和应用需求设定,例如留出20%给系统和其他进程。

    maxmemory 8gb
  2. 选择合适的淘汰策略:当内存达到maxmemory时,根据maxmemory-policy决定如何淘汰数据。

    • volatile-lru:从已设置过期时间的键中,淘汰最近最少使用的。
    • allkeys-lru:从所有键中,淘汰最近最少使用的。这是最通用的策略
    • volatile-ttl:淘汰剩余生存时间最短的键。
    • noeviction:不淘汰,返回错误。适用于数据绝对不能丢失的场景,但要求应用能妥善处理写错误。 根据你的数据特性选择。如果所有数据都有过期时间,用volatile-*策略;如果数据都有长期价值,用allkeys-lru
  3. 监控慢查询:使用SLOWLOG命令或RedisInsight的Slow Log面板来发现潜在的性能瓶颈。

    slowlog-log-slower-than 10000 # 单位微秒,记录执行超过10毫秒的命令 slowlog-max-len 128 # 最多记录多少条慢日志

    定期检查慢日志,优化那些耗时的命令或数据结构设计。

  4. 合理使用Pipeline和连接池:减少网络往返次数。对于批量操作,使用Pipeline将多个命令打包一次发送。在客户端使用连接池,避免频繁创建和销毁连接的开销。

5.4 监控与告警:让问题可视化

“没有监控的系统就是在裸奔。” 对于Redis Stack,除了基础的服务器监控(CPU、内存、磁盘、网络),还需要专门的Redis监控。

  1. Redis INFO命令:这是最丰富的信息源。通过INFO allINFO下的各个子部分(如INFO memory,INFO stats,INFO replication)可以获取几乎所有运行时指标。很多监控系统(如Prometheus)的Redis Exporter就是通过定期执行INFO命令来采集数据的。

  2. Prometheus + Grafana:这是当前最流行的监控组合。

    • 部署redis_exporter,它会将Redis的INFO指标转换为Prometheus格式。
    • 在Prometheus配置中抓取redis_exporter的指标。
    • 在Grafana中导入现成的Redis监控仪表盘(如ID 763),你就能看到实时的命中率、内存使用、连接数、命令吞吐量、慢查询等关键图表。
  3. 关键告警项

    • 内存使用率:持续高于maxmemory的90%。
    • 连接数:异常飙升,可能意味着连接泄漏或攻击。
    • 命中率:Keyspace命中率持续低于90%,可能需要优化缓存策略或扩容。
    • 阻塞客户端数量:长时间有阻塞客户端,可能发生了慢查询或大Key操作。
    • 主从复制状态:如果使用了主从,监控复制延迟(master_repl_offsetslave_repl_offset的差值)。

6. 从单机到高可用:复制与哨兵模式入门

单点部署有宕机风险。对于要求高可用的生产环境,至少需要配置主从复制(Replication)。Redis通过简单的配置就能实现数据的异步复制。

6.1 主从复制配置

假设我们有两台服务器,server-a(IP: 192.168.1.10) 作为主节点,server-b(IP: 192.168.1.11) 作为从节点。

在从节点(server-b)的配置文件redis-stack.conf中,只需添加一行:

replicaof 192.168.1.10 6379 # 如果主节点有密码,还需要添加 masterauth YourMasterPassword

重启从节点的Redis服务。从节点会连接主节点,进行全量数据同步(RDB传输),然后持续同步新的写命令。

验证复制状态:在主节点或从节点执行:

127.0.0.1:6379> INFO replication # Replication role:master # 在主节点上显示为master connected_slaves:1 slave0:ip=192.168.1.11,port=6379,state=online,offset=...,lag=0 ... # 在从节点上显示为slave role:slave master_host:192.168.1.10 master_port:6379 master_link_status:up ...

看到master_link_status:upstate=online,说明复制链路正常。从节点默认是只读的,所有写操作必须发送到主节点。

6.2 使用Redis Sentinel实现自动故障转移

主从复制解决了数据备份和读扩展的问题,但没有解决主节点自动故障转移。Redis Sentinel(哨兵)是一个分布式系统,用于监控主从实例,并在主节点故障时,自动将一个从节点提升为新的主节点,并让其他从节点指向新的主节点。

部署Sentinel(至少3个实例以形成多数派决策):Sentinel实际上是一个特殊的Redis进程,使用不同的配置文件(如sentinel.conf)。

一个基本的sentinel.conf配置如下:

port 26379 # Sentinel默认端口 daemonize yes logfile "/var/log/redis/sentinel.log" # 监控名为 mymaster 的主节点,2表示至少需要2个Sentinel同意才判定客观下线 sentinel monitor mymaster 192.168.1.10 6379 2 # 主节点密码 sentinel auth-pass mymaster YourMasterPassword # 故障转移超时时间(毫秒) sentinel down-after-milliseconds mymaster 5000 # 故障转移时,允许有多少个从节点同时对新主节点进行同步 sentinel parallel-syncs mymaster 1 # 故障转移超时时间 sentinel failover-timeout mymaster 180000

在三个独立的服务器或容器中启动Sentinel进程:

redis-sentinel /path/to/sentinel.conf # 或 redis-server /path/to/sentinel.conf --sentinel

工作原理

  1. 每个Sentinel会定期向主节点、从节点以及其他Sentinel发送PING命令。
  2. 如果主节点在down-after-milliseconds时间内没有有效回复,该Sentinel会将其标记为“主观下线”。
  3. 当足够数量(quorum,本例中为2)的Sentinel都认为主节点主观下线,则主节点被标记为“客观下线”。
  4. Sentinel集群会通过Raft算法选举出一个领导者Sentinel来执行故障转移。
  5. 领导者Sentinel会选择一个合适的从节点(通常数据最全、优先级高),将其提升为新的主节点。
  6. 通过发布订阅通知其他从节点和客户端关于新的主节点的信息。

客户端集成:支持Sentinel的客户端(如Jedis、Lettuce、redis-py)可以通过连接Sentinel节点来获取当前的主节点地址,从而实现自动重连到新的主节点。这是实现高可用应用的关键。

对于更复杂的场景,如大规模数据分片和线性扩展,则需要使用Redis Cluster。但Sentinel模式已经能满足大多数中小规模应用的高可用需求,且配置和理解起来相对简单。部署完成后,你可以通过redis-cli连接Sentinel端口,使用SENTINEL mastersSENTINEL slaves mymaster等命令来查看监控状态。

← 返回列表