Redis 入门:从 Docker 跑起来到用 Go 操作 Redis 入门从 Docker 跑起来到用 Go 操作这篇博客按学习顺序组织每一章都建立在前一章的基础上。建议从头往下读不要跳。学完每一章你都能动手做点什么而不是看完一堆概念还不会用。学习路线先搞懂 Redis 是什么 → 用 Docker 跑起来 → 搞清楚配置文件从哪来 → 边用边学数据类型 → 理解数据怎么不丢 → 最后用 Go 代码操作它。第一章Redis 是什么Redis 是一个把数据放在内存里的数据库。你可以把它理解成一个超快的键值仓库你给它一个 key键它给你一个 value值因为数据在内存里读写速度极快微秒级它不只是存字符串还支持列表、集合、有序集合等结构所以能做的事很多缓存、计数器、排行榜、消息队列、分布式锁。为什么快三句话数据在内存里、命令单线程执行没有锁竞争、底层数据结构专门优化过。记住这三句就够了细节后面用到再展开。第二章用 Docker 把 Redis 跑起来这一章只讲 Docker 方式。学完你能在本机跑起一个 Redis并进去敲命令。2.1 先补几个 Docker 概念不用系统学 Docker但这四个词必须懂否则后面的命令你看不懂概念通俗解释镜像image一个安装包模板比如redis:latest就是 Redis 的安装包容器container镜像跑起来的实例。一个镜像可以跑出多个容器端口映射-p把宿主机的端口接到容器内的端口让你本机能访问容器里的服务卷挂载-v把宿主机的目录/文件接到容器内的某个路径容器删了数据还在还有一个关键认知容器内部是一个独立的小系统它有自己的一套文件路径。你在宿主机上写文件容器里默认看不到除非用-v把它接进去。2.2 拉取镜像dockerpull redis:latest这行是把 Redis 官方镜像下载到本地。latest是标签表示最新稳定版。2.3 最简单的运行dockerrun-d--namemy-redis-p6379:6379 redis:latest逐段解释docker run创建并启动一个容器-d后台运行不占你的终端--name my-redis给容器起名之后用这个名字操作它-p 6379:6379宿主机 6379 → 容器 6379这样你本机就能连上redis:latest用哪个镜像。⚠️这种跑法没有挂载任何东西容器一删里面的数据和配置全没。现在只是先让你看到它能跑后面会改成持久化的跑法。2.4 进去敲命令验证dockerexec-itmy-redis redis-clidocker exec -it进入一个正在运行的容器开一个交互式终端my-redis容器名redis-cli在容器里执行的命令也就是 Redis 自带的命令行客户端。进去之后敲127.0.0.1:6379pingPONG127.0.0.1:6379setnameAliceOK127.0.0.1:6379get nameAlice看到PONG就说明 Redis 跑起来了。输入exit退出。这一章完成你已经有一个能用的 Redis 了。第三章redis.conf 从哪来上一章的 Redis 是用默认参数启动的。真实使用中你要改端口、设密码、开持久化这些都得靠配置文件redis.conf。但问题来了这个文件在哪答案官方镜像里有一份但你需要把它拿出来改再挂回去。3.1 为什么需要配置文件docker run后面可以跟一串参数比如--port 6380来临时指定配置。但参数多了之后命令会变得巨长、没法版本管理、改一次要重启整个容器重建。配置文件的好处集中管理、可读、可提交到 Git、改完只需重启容器。3.2 获取官方模板三种方式任选其一方式一从已经跑起来的容器里拷出来最直接# 先把容器跑起来如果上一章的还在跳过这步dockerrun-d--namemy-redis-p6379:6379 redis:latest# 把容器里的配置文件拷到宿主机当前目录dockercpmy-redis:/usr/local/etc/redis/redis.conf ./redis.conf/usr/local/etc/redis/redis.conf是 Redis 官方镜像里配置文件的标准位置。拷出来后你就能用编辑器打开看里面每一行都有注释。方式二从 Redis 官网下载注释最全wgethttps://download.redis.io/redis-stable/redis.conf这是源码仓库里的完整版配置模板注释最详细适合当参考书翻。方式三自己手写一份最小配置推荐实际使用官方模板有几百行你真正要改的就那么几项。实际项目中推荐手写一份精简版只保留自己需要的配置清晰可控。3.3 写一份最小可用配置新建文件redis.conf内容如下# 允许所有来源连接容器内必须这样对外访问靠端口映射和密码控制 bind 0.0.0.0 # 保护模式 protected-mode yes # 端口 port 6379 # 容器里必须 no否则 Redis 会转后台、容器主进程退出、容器直接停掉 daemonize no # 访问密码生产必设 requirepass your_password # 数据文件存放目录与容器内 /data 对应 dir /datadaemonize no是容器场景下最容易踩的坑。传统服务器上 Redis 喜欢用yes转后台但容器要求主进程在前台跑配成yes会导致容器启动了但立刻 Exited。3.4 挂载配置启动现在把配置文件和数据目录一起挂载进去# 准备数据目录mkdir-p/opt/redis/data# 启动挂载配置和数据dockerrun-d\--namemy-redis\-p6379:6379\-v/opt/redis/redis.conf:/usr/local/etc/redis/redis.conf\-v/opt/redis/data:/data\redis:latest\redis-server /usr/local/etc/redis/redis.conf两个-v是关键第一个把宿主机的配置文件接进容器容器里的 Redis 读的就是你改的那份第二个把宿主机的数据目录接进容器持久化文件落到宿主机容器删了数据还在。最后的redis-server /usr/local/etc/redis/redis.conf是覆盖镜像默认启动命令——告诉容器别用默认参数启动了读我挂进去的这份配置。3.5 验证dockerexec-itmy-redis redis-cli-ayour_passwordping# PONG-a后面跟密码因为你在配置里设了requirepass。这一章完成你知道了redis.conf从哪来、怎么写、怎么挂进容器以及为什么必须挂。第四章数据类型Redis 有五种常用数据类型 一种特殊的发布订阅。这一章边敲边学每一节都可以在redis-cli里直接验证。先进容器dockerexec-itmy-redis redis-cli-ayour_password4.1 String字符串——最基础用来存单个值文本、数字、序列化后的对象。SET nameAlice# 存GET name# 取 → AliceMSET k1 v1 k2 v2# 批量设置MGET k1 k2# 批量获取SETEX token60abc# 设置并带过期时间秒SETNX lock1# 仅当 key 不存在时才设置APPEND name Wang# 追加 → Alice WangSTRLEN name# 长度# 原子操作INCR views# 计数器 1key 不存在时从 0 开始INCRBY views10# 10DECR views# -1INCRBYFLOAT price0.5# 浮点递增典型场景缓存、计数器浏览量、点赞数、分布式锁SET lock uuid NX EX 30。4.2 Hash哈希——存对象一个 Hash 就是一个字段 → 值的映射适合存对象。相比把整个对象序列化成 StringHash 可以单独读写某个字段。HSET user:1001 nameAliceage25# 设置多个字段HGET user:1001 name# 取单个字段 → AliceHGETALL user:1001# 取全部字段和值HINCRBY user:1001 age1# 字段原子 1HDEL user:1001 age# 删字段HLEN user:1001# 字段数量典型场景用户信息、商品属性、购物车field商品ID, value数量。4.3 List列表——有序、双端操作有序的字符串链表可以从左、右两端插入和弹出。RPUSH queuetask1task2# 右边插入LPUSH queuetask0# 左边插入LRANGE queue0-1# 取全部0 到 -1 表示从头到尾LPOP queue# 左边弹出RPOP queue# 右边弹出LLEN queue# 长度LREM queue2a# 删除 2 个值为 a 的元素LTRIM queue099# 只保留前 100 个两个经典组合LPUSHRPOPFIFO 队列先进先出LPUSHLPOPLIFO 栈后进先出典型场景简单消息队列、最新 N 条动态LPUSH LTRIM、栈。4.4 Set集合——无序、不重复自动去重的集合支持交、并、差运算。SADD tagsredisdbcache# 添加重复的自动忽略SMEMBERS tags# 取全部成员SISMEMBER tagsredis# 判断是否存在 → 1SCARD tags# 成员数量SREM tagsdb# 删除成员SADD user:A:followu1u2SADD user:B:followu2u3SINTER user:A:follow user:B:follow# 交集 → u2共同关注SUNION user:A:follow user:B:follow# 并集 → u1, u2, u3SDIFF user:A:follow user:B:follow# 差集A 有 B 没有→ u1典型场景去重统计UV、标签、共同好友、黑白名单。4.5 ZSet有序集合——带分数的排行榜每个成员带一个 score分数按 score 自动排序。成员唯一分数可以重复。ZADD rank100Alice90Bob85Carol# 添加成员和分数ZSCORE rankAlice# 查分数 → 100ZINCRBY rank5Bob# 分数 5ZCARD rank# 成员数量ZREM rankCarol# 删除成员ZRANGE rank0-1# 按分数升序取全部ZREVRANGE rank02# 降序取前 3排行榜 Top3ZRANGEBYSCORE rank8590# 取分数在 [85, 90] 的成员典型场景排行榜最经典、延迟队列score 存到期时间戳、带权重的优先级队列。4.6 发布订阅Pub/Sub——广播消息前面五种是存数据发布订阅是传消息一个客户端往频道发消息所有订阅了该频道的客户端实时收到。开两个终端都先进容器# 终端 A订阅频道 newsdockerexec-itmy-redis redis-cli-ayour_password127.0.0.1:6379SUBSCRIBE news Reading messages...(press Ctrl-C to quit)# 终端 B往频道 news 发消息dockerexec-itmy-redis redis-cli-ayour_password127.0.0.1:6379PUBLISH newshello everyone(integer)1# 返回值表示有几个订阅者收到了此时终端 A 会立刻打印messagenewshello everyone还支持模式订阅用通配符匹配多个频道PSUBSCRIBE news.*# 订阅所有以 news. 开头的频道重要限制决定了它的使用场景消息不持久化发布时没在线的订阅者事后收不到没有确认机制发出去就算完不管有没有人真正处理不适合可靠消息要可靠消息请用 Redis Stream 或专业 MQKafka、RabbitMQ。典型场景实时通知如系统公告广播、聊天室广播、配置变更通知——能容忍偶尔丢失的实时消息。4.7 通用命令与类型无关这些命令对所有类型都适用日常排查和运维必不可少KEYS pattern# 按模式查 key生产慎用会阻塞用 SCAN 代替SCAN0MATCH user:* COUNT100# 渐进式遍历生产推荐TYPE key# 查看 key 的类型EXISTS key# 是否存在DEL key# 删除EXPIRE key3600# 设置过期秒TTL key# 剩余过期时间-1 永不过期-2 不存在PERSIST key# 移除过期时间RENAME key newkey# 重命名OBJECT ENCODING key# 查看底层编码调试优化用4.8 怎么选需求选什么存单个值、计数String存对象、按字段读写Hash要顺序、双端操作List去重、集合运算Set按分数排序、排行榜ZSet实时广播、不要求可靠发布订阅第五章持久化——数据怎么不丢前四章你已经会把数据存进 Redis 了但有个问题Redis 在内存里关机或重启数据就没了。持久化就是解决这个的。5.1 两种基础方式RDB快照把某个时刻的全量数据整体写成一个二进制文件dump.rdb。优点文件紧凑恢复快适合备份缺点两次快照之间崩溃会丢数据。配置多久、多少次修改后触发快照save 900 1 # 900 秒内至少 1 个键被改 save 300 10 # 300 秒内至少 10 个键被改 save 60 10000 # 60 秒内至少 10000 个键被改AOF追加日志把每条写命令记录下来重启时重放。优点数据安全性高最多丢 1 秒左右缺点文件会变大需要定期重写压缩。配置appendonly yes appendfsync everysec # 每秒同步一次生产推荐appendfsync三档always每条都同步最安全最慢、everysec推荐最多丢 1 秒、no交给系统最快最不安全。5.2 混合持久化——生产推荐Redis 4.0 引入把 RDB 和 AOF 的优点合在一起AOF 重写时文件头写 RDB 快照后面追加增量命令。重启时先加载头部 RDB快再回放尾部 AOF数据全。配置appendonly yes appendfsync everysec aof-use-rdb-preamble yes # Redis 5.0 默认开启现代生产环境基本都用这个。你只需要在redis.conf里加上上面三行。5.3 怎么选纯缓存、丢了能重建 →不开持久化性能最好数据不能丢哪怕 1 秒→ 用 AOF 的appendfsync always但性能会降大多数生产场景→混合持久化默认推荐。5.4 验证在redis.conf加上混合持久化的三行重启容器然后往 Redis 里写点数据看宿主机数据目录ls-lh/opt/redis/data/# 应该能看到 appendonly.aof 和 dump.rdb第六章事务与原子操作简单了解一下够用就行。6.1 单命令天然原子SET、INCR、HINCRBY这些单条命令本身就是原子的。简单的读-改-写场景优先用这些不需要事务。例如分布式锁SET lock:resourceuuidNX EX30NX保证 key 不存在才设置互斥EX 30保证 30 秒后自动释放防死锁整条命令原子执行。6.2 事务MULTI / EXEC把多条命令打包一次性连续执行MULTI INCR counter1 INCR counter2 EXEC# 返回 [结果1, 结果2]关键认知Redis 事务没有回滚。如果某条命令运行时出错已执行的命令不会撤销后面的命令继续执行。它只保证打包的命令连续执行、中间不被其他客户端插入不是关系型数据库那种 ACID 事务。6.3 什么时候用单条命令能搞定 → 用单命令SET NX、INCR多条命令要连续执行 →MULTI/EXEC但要清楚没有回滚。更复杂的检查-判断-修改逻辑超出了本文范围入门阶段先掌握这两种即可。第七章用 Go 操作 Redis最基础这一章只讲最基础、能马上跑起来的部分。复杂的 Pipeline、事务、脚本等你真正需要时再查。7.1 安装在 Go 项目里go get github.com/redis/go-redis/v97.2 连接新建main.gopackagemainimport(contextfmtgithub.com/redis/go-redis/v9)funcmain(){// 创建客户端告诉它 Redis 在哪rdb:redis.NewClient(redis.Options{Addr:localhost:6379,Password:your_password,// 你在 redis.conf 里设的密码DB:0,})deferrdb.Close()// context 是 Go 网络操作的固定参数先照抄ctx:context.Background()// 测试连接iferr:rdb.Ping(ctx).Err();err!nil{fmt.Println(连接失败:,err)return}fmt.Println(连接成功)}运行go run main.go看到连接成功就通了。如果报连接失败先确认docker ps里my-redis在跑。7.3 存一个值、取一个值// 存对应 Redis 的 SET name Aliceerr:rdb.Set(ctx,name,Alice,0).Err()iferr!nil{fmt.Println(存失败:,err)return}// 取对应 Redis 的 GET nameval,err:rdb.Get(ctx,name).Result()iferr!nil{fmt.Println(取失败:,err)return}fmt.Println(取到的值:,val)// Alice7.4 三条必须记住的规律规律一方法名 Redis 命令名改成驼峰Redis 命令Go 方法SETrdb.Set(...)GETrdb.Get(...)HSETrdb.HSet(...)LPUSHrdb.LPush(...)SADDrdb.SAdd(...)ZADDrdb.ZAdd(...)用到什么类型查一下 Redis 命令叫什么把首字母大写、驼峰化基本就对了。规律二写操作跟.Err()读操作跟.Result()Set、Incr、HSet等写入类rdb.Set(...).Err()只关心有没有报错Get、HGetAll、LRange等读取类rdb.Get(...).Result()同时拿到值和错误。规律三过期时间用time.Duration0表示永久rdb.Set(ctx,token,abc,0)// 永久rdb.Set(ctx,token,abc,30*time.Minute)// 30 分钟rdb.Set(ctx,token,abc,10*time.Second)// 10 秒7.5 处理key 不存在Get一个不存在的 key 时go-redis 返回一个特殊错误redis.Nil。这不是故障只是没找到。val,err:rdb.Get(ctx,可能不存在的key).Result()iferrredis.Nil{fmt.Println(key 不存在正常情况)}elseiferr!nil{fmt.Println(真出错了:,err)}else{fmt.Println(值是:,val)}这是新手最容易困惑的地方一定要把redis.Nil单独判断出来。7.6 完整可跑的例子把上面所有内容串起来复制到main.go直接跑packagemainimport(contextfmttimegithub.com/redis/go-redis/v9)funcmain(){ctx:context.Background()rdb:redis.NewClient(redis.Options{Addr:localhost:6379,Password:your_password,DB:0,})deferrdb.Close()// 连接测试iferr:rdb.Ping(ctx).Err();err!nil{fmt.Println(连接失败:,err)return}fmt.Println( 连接成功 )// 存 / 取rdb.Set(ctx,user:name,Alice,0)name,_:rdb.Get(ctx,user:name).Result()fmt.Println(String:,name)// 带过期rdb.Set(ctx,sms:code,123456,5*time.Minute)// 计数器rdb.Set(ctx,views,0,0)views,_:rdb.IncrBy(ctx,views,10).Result()fmt.Println(计数器:,views)// Hashrdb.HSet(ctx,user:1001,name,Bob,age,25)age,_:rdb.HGet(ctx,user:1001,age).Result()fmt.Println(Hash age:,age)// key 不存在_,err:rdb.Get(ctx,不存在的key).Result()iferrredis.Nil{fmt.Println(key 不存在正常)}}跑通它go-redis 的基础就算入门了。以后遇到具体场景缓存对象、分布式锁、排行榜再按需查对应命令。第八章学习路径总结回顾一下你走过的路搞懂 Redis 是什么——内存数据库快是因为内存 单线程 好数据结构。用 Docker 跑起来——镜像、容器、端口映射、卷挂载四个概念一个docker run就能启动。搞清楚 redis.conf——官方镜像里有一份拷出来改成精简版用-v挂进去配合redis-server xxx.conf启动。容器里daemonize必须no。数据类型——String/Hash/List/Set/ZSet 五种存数据发布订阅用来广播实时消息不要求可靠。持久化——RDB 快照、AOF 日志生产用混合持久化appendonly yesaof-use-rdb-preamble yes。事务——单命令天然原子优先用多条打包用MULTI/EXEC但没回滚。go-redis——三个规律方法名改驼峰、写.Err()读.Result()、redis.Nil是不存在不是错误。下一步可以学什么按需连接池配置PoolSize、MinIdleConns高并发时调Pipeline一次发多条命令减少网络往返Redis 集群 / 哨兵单机不够用时的方案Redis Stream需要可靠消息队列时用Lua 脚本需要检查-判断-修改的原子复杂逻辑时用。