Redis 的使用难吗?不难,Redis 用好容易吗?不容易。Redis 的使用虽然不难,但与业务结合的应用场景特别多、特别紧,用好并不容易。我们希望通过一篇文章及 Demo,即可轻松、快速入门并学会应用。
一、Redis 简介
Redis 是一个开源的 Key-Value 存储,但又不仅仅是 Key-Value 存储,用官网上的话来说,Redis 是一个数据结构存储,可用作数据库、缓存和消息中间件。相对于传统的 Key-Value 存储 Memcached 来说,Redis 具有如下特点:
- 速度快
- 丰富的数据结构,除 String 之外,还有 List、Hash、Set、Sorted Set
- 单线程,避免了线程切换和锁的性能消耗
- 原子操作
- 可持久化(RDB 与 AOF)
- 发布 / 订阅
- 支持 Lua 脚本
- 分布式锁
- 事务
- 主从复制与高可用(Redis Sentinel)
- 集群(3.0 版本以上)
二、Redis 数据结构
1、String
这是最简单的 Redis 类型。如果只使用这种类型,Redis 就像一个可持久化的 Memcached 服务器。
2、List
Redis 的 List 是基于双向链表实现的,可以支持反向查找和遍历。
常用案例:聊天系统、社交网络中获取用户最新发表的帖子、简单的消息队列、新闻的分页列表、博客的评论系统。
3、Hash
Hash 是一个 String 类型的 field 和 value 之间的映射表,请见下图,类似于.NET 中的 Hashtable 和 Dictionary。主要用来存储对象,可以避免序列化的开销和并发修改控制的问题。
4、Set
Set 也是一个列表,不过它的特殊之处在于它是可以自动排重的:当需要存储一个列表数据,而又不希望出现重复的时候,Set 是一个很好的选择(比如 ID 的集合)。并且 Set 提供了判断某个成员是否在一个 Set 集合内的接口,这也是 List 所没有的。
5、Sorted Set
Sorted Set 和 Set 的使用场景类似,区别是 Sorted Set 会根据提供的 score 参数来进行自动排序。当你需要一个有序的并且不重复的集合列表,那么就可以选择 Sorted Set 数据结构。常用案例:游戏中的排行榜。
三、 Redis 重要特性
以下特性请重点看管道和事务。
1、管道
Redis 管道是指客户端可以将多个命令一次性发送到服务器,然后由服务器一次性返回所有结果。管道技术在批量执行命令的时候可以大大减少网络传输的开销,提高性能。
2、事务
Redis 事务是一组命令的集合。一个事务中的命令要么都执行,要么都不执行。如果命令在运行期间出现错误,不会自动回滚。
管道与事务的区别:管道主要是网络上的优化,客户端缓冲一组命令,一次性发送到服务器端执行,但是并不能保证命令是在同一个事务里面执行;而事务是原子性的,可以确保命令执行的时候不会有来自其他客户端的命令插入到命令序列中。
3、分布式锁
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作,如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
4、地理信息
从 Redis 3.2 版本开始,新增了地理信息相关的命令,可以将用户给定的地理位置信息(经纬度)存储起来,并对这些信息进行操作。
四、 使用方法
步骤 1、在需要使用 Redis 的项目中引用 FxCommon.dll 和 Redis.dll。
步骤 2、在 App.config 或 Web.config 文件中添加如下配置:
<add key="RedisServerIP" value="redis:uuid845tylabc123@139.198.13.12:4125"/> <!-- 提供的 Redis 环境是单机版配置。如果 Redis 是主从配置,则还需设置 RedisSlaveServerIP--> <!--<add key="RedisSlaveServerIP" value="redis:uuid845tylabc123@139.198.13.13:4125"/>--> <!--Redis 数据库。如果不需要指定 Redis 数据库,就配置默认值 0--> <add key="RedisDefaultDb" value="0"/>
步骤 3、使用 PooledRedisClientManager 类创建 Redis 连接池:
// 读取 Redis 主机 IP 配置信息 string[] redisMasterHosts = ConfigurationManager.ConnectionStrings["RedisServerIP"].ConnectionString.Split(','); // 如果 Redis 服务器是主从配置,那么还需要读取 Redis Slave 机的 IP 配置信息 string[] redisSlaveHosts = null; var slaveConnection = ConfigurationManager.ConnectionStrings["RedisSlaveServerIP"]; if (slaveConnection != null && !string.IsNullOrWhiteSpace(slaveConnection.ConnectionString)) { string redisSlaveHostConfig = slaveConnection.ConnectionString; redisSlaveHosts = redisSlaveHostConfig.Split(','); } // 读取 RedisDefaultDb 配置 int defaultDb = 0; string defaultDbSetting = ConfigurationManager.AppSettings["RedisDefaultDb"]; if (!string.IsNullOrWhiteSpace(defaultDbSetting)) { int.TryParse(defaultDbSetting, out defaultDb); } var redisClientManagerConfig = new RedisClientManagerConfig { MaxReadPoolSize = 50, MaxWritePoolSize = 50, DefaultDb = defaultDb }; // 创建 Redis 连接池 Manager = new PooledRedisClientManager(redisMasterHosts, redisSlaveHosts, redisClientManagerConfig) { PoolTimeout = 2000, ConnectTimeout = 500 };
步骤 4、通过 PooledRedisClientManager 的实例获取 Redis 客户端,然后就可以开始通过 Redis 客户端的 API 进行操作。
五、其它
5.1、 Redis Key 命名规范
Redis Key 命名规范:AppID:KeyName。
可能有很多人习惯用英文状态的点号来作为 AppID 和 KeyName 的分隔符,而笔者建议使用冒号作为 AppID 和 KeyName 的分隔符,其原因是:这么写会使 Redis Key 会以 AppID 作为分类显示在 Redis Desktop Manager 中,方便你能够快速查到要查阅的 Redis Key 对应的 Redis Value 值,请见下图:
但如果使用英文状态的点号来作为分隔符的话,那么在Redis Desktop Manager 中,Redis Key 就不会被分类了,请见下图:
5.2、常见应用问题
- 缓存穿透处理:什么是缓存穿透?当根据 Redis key 在缓存中查询后,不存在对应 Value,就应该会在后端系统如 DB 中去查找,该 Key 的并发请求量一旦变大,那么就会对 DB 造成很大的压力。解决办法有:a. 前端风险控制,将恶意穿透情况排除在外;b. 对查询结果为空的情况依然进行缓存,但缓存时间会设置得很短,一般是几分钟。
- 缓存雪崩处理:什么是缓存雪崩?当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统 (比如 DB) 带来很大压力。解决办法有:后端连接数限制,错误阈值限制,超时处理,缓存失效时间均匀分布,前端永不失效及后端主动更新。
- 缓存时长:策略定位复杂,需要多维度的计算。
- 缓存失效:按时失效,事件失效,后端主动更新。
- 缓存 Key:Hash、规则、前缀 +Hash,异常情况可人工干预。
- Lua 脚本:服务端批量处理及事务能力,有条件逻辑的可扩展脚本。使用它的好处有:减少网络开销、原子操作、可复用。
- Limit:可滑动时间窗口,如应用于 Session,Memcached 需每次传 Key 和 Value。
六、Demo 下载及更多资料
- RedisDemo 下载地址: https://github.com/das2017/RedisDemo
- RedisDesktopManage 下载地址: https://redisdesktop.com/
- Redis 官网: https://redis.io/
- ServiceStack.Redis 客户端: https://github.com/ServiceStack/ServiceStack.Redis
- Redis 命令大全: http://www.redis.cn/commands.html
本系列文章涉及内容清单如下,其中有感兴趣的,欢迎关注:
- 开篇:中小型研发团队架构实践三要点
- 缓存 Redis
- 消息队列 RabbitMQ:如何用好消息队列 RabbitMQ?
- 集中式日志 ELK
- 任务调度 Job:中小型研发团队架构实践之任务调度 Job
- 应用监控 Metrics:应用监控怎么做?
- 微服务框架 MSA
- 搜索利器 Solr
- 分布式协调器 ZooKeeper
- 小工具:Dapper.NET/EmitMapper/AutoMapper/Autofac/NuGet
- 发布工具 Jenkins
- 总体架构设计:电商如何做企业总体架构?
- 单个项目架构设计
- 统一应用分层:如何规范公司所有应用分层?
- 调试工具 WinDbg
- 单点登录
- 企业支付网关
- 结篇
作者介绍
张辉清,10 多年的 IT 老兵,先后担任携程架构师、古大集团首席架构、中青易游 CTO 等职务,主导过两家公司的技术架构升级改造工作。现关注架构与工程效率,技术与业务的匹配与融合,技术价值与创新。
杨丽,拥有多年互联网应用系统研发经验,曾就职于古大集团,现任职中青易游的系统架构师,主要负责公司研发中心业务系统的架构设计以及新技术积累和培训。现阶段主要关注开源软件、软件架构、微服务以及大数据。
感谢雨多田光对本文的审校。
评论