【Redis】初识 Redis

1 什么是 Redis

Redis 是一种基于键值对(key-value)的 NoSQL 数据库,与很多键值对数据库不同的是,Redis 中的键固定为 string,但值可以由string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、Bitmaps(位图)、HyperLogLog、GEO(地理信息定位)等多种数据结构和算法组成,因此 Redis 可以满足很多的应用场景,而且因为 Redis 会将所有数据都存放在内存中,所以它的读写性能非常惊人。不仅如此,Redis 还可以将内存的数据利用快照和日志的形式保存到硬盘上,这样在发生类似断电或者机器故障的时候,内存中的数据不会“丢失”。除了上述功能以外,Redis 还提供了键过期、发布订阅、事务、流水线、Lua 脚本等附加功能。总之,如果在合适的场景使用 Redis,它就会像一把瑞士军刀一样所向披靡。

2008年,Redis 的作者 Salvatore Sanfilippo 在开发一个叫 LLOOGG 的网站时,需要实现一个高性能的队列功能,最开始是使用 MySQL来实现的,但后来发现无论怎么优化 SQL 语句等都不能使网站的性能提高上去,再加上自己囊中羞涩,于是他决定自己做一个专属于 LLOOGG 的数据库,这就是 Redis 的前身。后来,Salvatore Sanfilippo 将 Redis 1.0 的源码发布到 Github 上,可能连他自己都没想到,Redis 后来如此受欢迎。

假如现在有人问 Redis 的作者都有谁在使用 Redis,我想他可以开玩笑的回答:还有谁不使用 Redis,当然这只是开玩笑,但是从Redis 的官方公司统计来看,有很多重量级的公司都在使用 Redis,如国外的 Twitter、Instagram、Stack Overflow、Github 等,国内就更多了,如果单单从体量来统计,新浪微博可以说是全球最大的 Redis 使用者,除了新浪微博,还有像阿里巴巴、腾讯、搜狐、优酷土豆、美团、小米、唯品会等公司都是 Redis 的使用者。除此之外,许多开源技术像 ELK 等已经把 Redis 作为它们组件中的重要一环,而且 Redis 还提供了模块系统让第三方人员实现功能扩展,让 Redis 发挥出更大的威力。所以,可以这么说,熟练使用和运维 Redis 已经成为开发运维人员的必备技能。

2 Redis 的特点

Redis 之所以受到如此多公司的青睐,必然有之过人之处,下面是关于 Redis 的几个重要特性。

2.1 速度快

速度快是 Redis 最大的特点。Redis 执行命令的速度非常快,官方给出的数字是读写性能可以达到 10 万 / 秒,当然这也取决于机器的性能。下面是 Redis 速度快的几个原因:

  • Redis 的所有数据都是存放在内存中的,因此相较于 MySQL 这种数据存储在硬盘中的数据库,访问速度要快很多,这是Redis 速度快的最主要原因。下图谷歌公司 2009 年给出的各层级硬件执行速度,可以看到内存的访问速度大约是硬盘的十万倍。
  • Redis 的核心功能通过操作内存中的数据结构完成,相较于 MySQL 操作表来说,逻辑上要简单很多,所耗费的 CPU 资源也少很多。
  • Redis 使用的是单线程模型,减少了多线程之间线程切换、锁的竞争等资源消耗。(Redis 在 6.0 版本引入了多线程机制,但主要也是在处理网络和 IO,不涉及到数据命令,即命令的执行仍然采用了单线程模式) 注意:我们之前学习多线程的时候,总是说多线程能够提高效率,它的前提是处理 CPU 密集型任务,多线程能够充分利用多核资源;但 Redis 核心功能通过操作内存数据结构就能够完成,这并不会占用很多 CPU,因此单线程可以充分利用现代处理器的高速缓存,减少上下文切换的开销,从而实现高性能。
  • Redis 是用 C 语言实现的,一般来说 C语言 实现的程序 “距离” 操作系统更近,执行速度相对会更快。(网上对这一点说法存在争议,因为我们说 Redis 快一般是和 MySQL 进行比较的,而 MySQL 也是使用 C语言 实现的。)
  • 作者对于 Redis 源代码可以说是精打细磨,曾经有人评价 Redis 是少有的集性能和优雅于一身的开源代码。

2.2 可编程性

我们可以通过简单的交互式命令对 Redis 进行操作,也可以通过一些脚本的方式,如 Lua 脚本,来批量执行一些操作或创建新的 Redis 命令。

2.3 可拓展性

Redis 是一种基于键值对(key-value)的 NoSQL 数据库,Redis 中的键固定为 string,但值可以由string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、Bitmaps(位图)、HyperLogLog、GEO(地理信息定位)等多种数据结构和算法组成,这使得 Redis 不仅能便于在许多应用场景的开发,同时也能提高开发效率。

同时,Redis 还支持通过 C/C++/Rust 来编写 Redis 拓展 (本质上是一个动态链接库),这样使得公司可以根据自己的业务需要,通过扩展让 Redis 支持更多的数据结构和命令,定制化开发。

2.4 持久化

通常来看,将数据放在内存中是不安全的,一旦发生断电或者机器故障,重要的数据可能就会丢失,因此 Redis 提供了两种持久化方式:RDB 和 AOF,即可以用两种策略将内存的数据保存到硬盘中,这样就保证了数据的可持久性。

2.5 主从复制

Redis 提供了复制功能,实现了多个相同数据的 Redis 副本,复制功能是分布式 Redis 的基础。Redis 主从复制架构如下图所示:

2.5 高可用和分布式

Redis 提供了高可用实现的 Redis 哨兵(Redis Sentinel),能够保证 Redis 结点的故障发现和故障自动转移。也提供了 Redis 集群(Redis Cluster),是真正的分布式实现,提供了高可用、读写和容量的扩展性。

2.6 客户端语言多

Redis 提供了简单的 TCP 通信协议,很多编程语言可以很方便地接入到 Redis,并且由于 Redis 受到社区和各大公司的广泛认可,所以支持 Redis 的客户端语言也非常多,几乎涵盖了主流的编程语言,例如 C、C++、Java、PHP、Python、NodeJS 等。

3 Redis 使用场景

要充分理解 Redis 的作用,需要读者对网站的架构有一定的基础理解,如果你缺少这方面的背景知识,建议先移步我上一篇文章 分布式架构演进之路 ,再继续本篇的学习。

3.1 实时数据存储

Redis 的多种内存数据结构可以为需要低延迟和高吞吐量的实时应用程序构建数据基础设施,即 Redis 可以作为数据库。在大多数情况下,数据存储优先考虑的是容量,但也有一些场景考虑的是速度,比如在商业搜索业务中,由于它对性能要求非常高,因此需要使用类似于 Redis 这样的数据库,将需要检索的数据都存储在内存中。

3.2 缓存和 Session 存储

在缓存方面:由于 MySQL 将数据存储在硬盘中,因此访问速度很慢,又由于存在 “二八原则”,因此我们可以将热点数据拷贝一份放在 Redis 中作为缓存,从而有效提高数据访问速度。Redis 提供了键值过期时间设置,并且也提供了灵活控制最大内存和内存溢出后的淘汰策略,可以很好的实现缓存。

在 Session 方面:

  • 在单机系统中,用户的 Session 信息是直接存储在应用服务器中的,用户访问服务器时服务器根据用户浏览器中的 cookie 信息(SessionId)来辨识用户。
  • 但是在分布式系统中,由于用户请求可能被负载均衡器分配到任意一台应用服务器上,因此就可能会出现需要用户重复登录的情况,因为该用户的 Session 信息只存在于为用户提供过服务的应用服务器中,这显然是不科学的。
  • 为了解决上述问题,我们可以将用户的 Session 信息单独拎出来,放在一组独立的机器上存储,由于服务器为用户提供服务需要先验证用户身份信息,因此存储用户 Session 信息的服务器速度必须要快,此时就可以考虑使用 Redis;并且这样做还有一个好处,就是即使应用服务器重启了,用户的 Session 信息也不会丢失。

Redis 作为数据库和 Redis 作为缓存的区别在于:

  • 在数据库中,Redis 存储的是全量数据,这里的数据是不能随便丢的。
  • 而在缓存中,Redis 中存储的是从全量数据库中拷贝过来的部分数据,即使丢失了影响也不大。

3.3 消息队列

在文章最开始介绍 Redis 的时候,我们提到过 Salvatore Sanfilippo 开发 Redis 的初衷其实是用它来实现一个高性能的队列功能,即消息队列,但随着 Redis 的发展,Redis 在用作缓存方面大获成功,用作消息队列方面却显得一般。

消息队列系统可以说是⼀个大型网站的必备基础组件,通过它我们可以实现一个网络版本的生产者消费者模型,从而在分布式系统中做到业务解耦与非实时业务削峰等工作。现在业界存在许多知名的消息队列组件,比如 RabbitMQ、Kafka、RocketMQ等,它们在消息队列中的功能要比 Redis 完善,但如果公司业务对消息队列的功能依赖不是很多,那么使用 Redis 作为消息队列也是完全可以的。

4 Redis 重大版本

Redis自发布以来经历了多个重大版本更新,以下是一些主要的版本及其特点:

  • Redis 2.6 :于2012年发布,引入了服务端Lua脚本支持、键过期时间毫秒级精度、从节点只读功能等多项特性。
  • Redis 2.8 :2013年发布,增加了部分主从复制功能,尝试性地支持IPv6,以及Redis Sentinel的第二版等。
  • Redis 3.0 :2015年发布,引入了官方的分布式实现Redis Cluster,优化了内存访问,并提高了性能。
  • Redis 3.2 :2016年发布,添加了GEO相关功能和新的List编码类型quicklist等。
  • Redis 4.0 :提供了模块系统、PSYNC2.0、新的缓存剔除算法LFU、非阻塞del命令等。
  • Redis 5.0 :引入了新的流数据类型、Redis模块API、RDB增加了LFU和LRU信息等。
  • Redis 6.0 :引入了多线程IO、新模块API、更好的过期循环、支持SSL等。
  • Redis 7.0 :新增Function自定义函数库、支持Client-Eviction、Sharded-Pub/Sub、命令执行耗时直方图等。

每个版本的发布都带来了新特性和性能改进,以满足不同场景下的需求。Redis的版本命名规则是偶数为稳定版本,奇数为开发版本,这种规则有助于用户选择合适的版本进行部署。

关于 Redis 更多版本以及版本更多变更细节可以查看 GitHub:https://github.com/redis/redis/releases

5 CentOS7 安装 Redis5

上面我们介绍了 Redis 几个重要的版本,在这里我们选择 Redis5 版本进行学习,原因是 Redis5 已经支持了大部分的功能特性,同时相较于 Redis7 版本,更容易进行安装使用,而且目前很多企业中使用的也是 Redis5 版本。

Redis 的官方并不支持微软的 Windows 操作系统,因为 Redis 的许多特性都是和操作系统相关的,所以支持 Windows 会增加维护成本,而且更重要的是大部分公司都在使用 Linux 操作系统,而 Redis 在 Linux 操作系统上的表现已经得到实践的证明。当然 Redis 作为一款优秀的开源技术,还是吸引到微软公司的注意,微软公司的开源技术组在 Github 上维护了一个 Redis 分支。不过还是强烈建议大家在 Linux 上使用 Redis。

1. 使用 yum 安装

首先安装 scl 源,再安装 redis:

代码语言:javascript
复制
yum install centos-release-scl-rh
yum install rh-redis5-redis

2. 创建符号链接

默认安装的目录为 /opt/rh/rh-redis5/root/usr/bin/ ,藏的太深了,不方便使用。可以通过符号链接,把需要用到的关键内容设置到方便使用的目录中。

针对可执行程序设置符号链接:

代码语言:javascript
复制
cd /usr/bin
ln -s /opt/rh/rh-redis5/root/usr/bin/redis-server ./redis-server
ln -s /opt/rh/rh-redis5/root/usr/bin/redis-sentinel ./redis-sentinel
ln -s /opt/rh/rh-redis5/root/usr/bin/redis-cli ./redis-cli

针对配置文件设置符号链接:

代码语言:javascript
复制
cd /etc/
ln -s /etc/opt/rh/rh-redis5/ ./redis

CentOS7 yum 源中自带的 Redis 安装包版本是 Redis3.2,因此我们需要通过 scl 源来安装 Redis5 版本。而 CentOS8 yum 源中自带的 Redis 版本是 Redis5,因此直接 yum install redis 即可,不用进行上述一系列操作。

3. 支持远程连接

默认情况下,Redis 只绑定在 127.0.0.1 接口上,即只允许从 127.0.0.1(localhost)上进行连接 Redis 服务,为了允许 Redis 接受远程访问,需要修改 Redis 的配置文件 /etc/redis.conf

  • 定位到 bind 127.0.0.1 开头的一行,修改为 bind 0.0.0.0 以添加全接口支持。
  • 关闭保护模式,protected-mode no
代码语言:javascript
复制
bind 0.0.0.0 
protected-mode no 

同时,我们还可以将 daemonize 修改为 yes,让 redis-server 变为守护进程:

代码语言:javascript
复制
daemonize yes

4. 设置工作目录

先先创建工作目录:

代码语言:javascript
复制
mkdir -p /var/lib/redis 

再在 /etc/redis.conf 配置文件中,设置 Redis 工作目录:

代码语言:javascript
复制
dir /var/lib/redis

5. 设置日志目录

先创建日志目录:

代码语言:javascript
复制
mkdir -p /var/log/redis/ 

再在 /etc/redis.conf 配置文件中,设置 Redis 日志目录:

代码语言:javascript
复制
logfile /var/log/redis/redis-server.log

至此,Redis5 安装以及相关配置完成。

启动 redis-server

Redis 是一个 客户端-服务器 结构的程序,Redis 服务器,即 redis-server 是 Redis 本体,负责存储和管理数据;而 Redis 客户端,即 redis-cli 通过网络访问 redis-server 中的数据

代码语言:javascript
复制
redis-server /etc/redis/redis.conf 

启动 redis-cli

代码语言:javascript
复制
redis-cli -h {host} -p {port}

启动 redis-cli 之后,我们可以输入 ping 命令,如果返回 pong,说明 redis-cli 可以连通 redis-server。

停止 redis-server

首先通过 netstat 命令查看 redis-server 对应的 PID,然后 kill -9 即可:

代码语言:javascript
复制
netstat -nltp | grep redis
kill -9 xxx