Redis 学习 - 01 简介、安装、配置

Redis 简介

Redis 的由来

2008 年,意大利的一家创业公司 Merzia 推出了一款基于 MySQL 的网站实时统计系统 LLOOGG,然而没过多久,该公司的创始人 Salvatore Sanfilippo 便对 MySQL 的性能感到失望,于是他决定亲自为 LLOOGG 量身定做一个数据库,并于 2009 年开发完成,这个数据库就是 Redis。

不过 Salvatore Sanfilippo 并不满足只将 Redis 用于 LLOOGG 这一款产品,而是希望更多的人使用它,于是在同一年 Salvatore Sanfilippo 将 Redis 开源发布,并开始和 Redis 的另一名主要的代码贡献者 Pieter Noordhuis 一起继续着 Redis 的开发,直到今天。

Salvatore Sanfilippo 自己也没有想到,短短的几年时间,Redis 就拥有了庞大的用户群体。国内如 BAT、新浪微博、知乎等,国外如 GitHub、Stack Overflow、Flickr等都是 Redis 的用户。

发展时间线:

  • VMware 公司从 2010 年开始赞助 Redis 的开发,Salvatore Sanfilippo 和 Pieter Noordhuis 也分别于同年的 3 月和 5 月加入 VMware,全职开发 Redis

  • 而 2013 年 5 月至 2015 年 6 月期间,其开发由 Pivotal 赞助

  • 2015 年 6 月,Redis Labs 为进一步的开发进行赞助一直到现在

Redis 代码托管在 GitHub 上(https://github.com/redis/redis),开发十分活跃。

什么是 Redis

以下是官方文档解释。

Redis 是一个使用 ANSI C 编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。

它通过提供多种键值数据类型来适应不同场景下的存储需求,例如:

  • string - 字符串
  • hash - 哈希
  • list - 列表
  • set - 集合
  • 带范围查询的排序集合
  • bitmap - 位图
  • hyperlogolog - 超日志
  • geospatial index - 地理空间索引
  • stream - 流

Redis 具有内置的复制功能,解析执行 Lua 脚本,LRU 缓存控制,事务和不同级别的磁盘持久性,并通过 Redist Sentinel 和 Redis Cluster 自动分区提供高可用性。

Redis 的存储结构

在大多数编程语言中都有一种数据结构:字典,例如代码 dict["key"] = "value" 中:

  • dict 是一个字典结构变量
  • key 是键名
  • value 是键值

在字典中我们可以获取或设置键名对应的键值,也可以删除一个键。

Redis 是 REmote DIctionary Server(远程字典服务器)的缩写,它以字典结构存储数据,并允许其他应用通过 TCP 协议读写字典中的内容。

Redis 字典中的键值除了可以是字符串,还可以是其它数据类型。其中比较常见的有:

类型说明
Strings字符串
Hashes哈希/散列,是由与值相关联的字段组成的内容。字段和值都是字符串。这与 Ruby 或 Python 哈希非常相似。类似于 JavaScript 中的对象结构。
Lists列表,根据插入顺序排序的字符串元素的集合。它们基本上是链表。
Sets未排序的字符串元素集合,集合中的数据是不重复的
Sorted sets与 Sets 类似,但每个字符串元素都与一个称为分数的浮点值相关联。元素总是按它们的分数排序,因此与 Sets 不同,可以检索一系列元素(例如,您可能会问:给我前 10 名或后 10 名)

内存存储与持久化

Redis 数据库中所有数据都存储在内存中。相对于磁盘,内存的数据读/写速度要快得多,所以我们通常用 Redis 做缓存数据库,在一台普通电脑上,Redis 可以在一秒内读写超过 10 万个键值。

Redis 官网的性能测试显示,在 Linux 2.6、Xeon X3320 2.5 GHz 服务器上,50 个并发的情况下请求 100000 次,SET 操作可达 110000 次/s,GET 操作可达 81000 次/s

将数据存储在内存中也有问题,比如程序退出后内存中的数据会丢失。不过 Redis 提供了对持久化的支持,即可以将内存中的数据异步写入到硬盘中,同时不影响继续提供服务。

功能丰富

Redis 虽然是作为数据库开发的,但是由于提供了丰富的功能,越来越多人将其用作缓存、队列系统等。

1、作为缓存系统

Redis 可以为每个键设置生存时间,生存时间到期后会自动被删除。这一功能配合出色的性能让 Redis 可以作为缓存来使用。作为缓存系统,Redis 还可以限定数据占用的最大空间,在数据达到空间限制后可以按照一定的规则自动淘汰不需要的键。

2、作为队列系统

除此之外,Redis 的列表类型键可以用来实现队列,并且支持阻塞式读取,可以很容易的实现一个高性能的优先级队列。

3、“发布/订阅”功能

同时在更高层面上,Redis 还支持“发布/订阅”的消息模式,可以基于此构建聊天室等系统。

简单稳定

即使功能再丰富,如果使用起来太复杂也很难吸引人。Redis 直观的存储结构使得通过程序与 Redis 交互十分简单。

在 Redis 中使用命令来读写数据,命令语句之于 Redis 就相当于 SQL 语言之于关系数据库。例如在关系数据库中要获取 posts 表内 id 为 1 的记录的 title 字段可以使用如下 SQL 语句实现:

SELECT title FROM posts WHERE id=1 LIMIT 1

相对应的,在 Redis 中要读取键名为 post: 1 的散列类型键的 title 字段的值,可以使用如下语句实现:

HGET post:1 title

其中,HGET 就是一个命令,post:1 是键名,title 是要读取的数据字段。

Redis 提供了 250 多个命令,听起来很多,但是常用的也就几十个,并且每个命令都很容易记忆。Redis 命令列表:Command reference – Redis

Redis 提供了几十种不同编程语言的客户端(https://redis.io/clients),这些库都很好的封装了 Redis 的命令,使得在程序中与 Redis 进行交互变得更容易。

Redis 应用场景

Redis是一个 Key-Value 存储系统,大部分情况下是因为其高性能的特性,被当做缓存使用,这里介绍下Redis经常遇到的使用场景。

一个产品的使用场景肯定是需要根据产品的特性,先列举一下 Redis 的特点:

  • 读写性能优异
  • 持久化
  • 数据类型丰富
  • 单线程
  • 数据自动过期
  • 发布订阅
  • 分布式

这里我们通过几个场景,不同维度说下 Redis 的应用。

1、缓存系统

缓存现在几乎是所有中大型网站都在用的功能,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis 提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在 Redis 用在缓存的场合非常多。

2、排行榜

很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。

3、计数器

什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景。

4、分布式会话

集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理。

5、分布式锁

在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,大大影响了数据库的性能。可以利用Redis的setnx功能来编写分布式的锁,如果设置返回1说明获取锁成功,否则获取锁失败,实际应用中要考虑的细节要更多。

6、社交网络

点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库类型不适合存储这种类型的数据,Redis提供的哈希、集合等数据结构能很方便的的实现这些功能。

7、最新列表

Redis列表结构,LPUSH可以在列表头部插入一个内容ID作为关键字,LTRIM可用来限制列表的数量,这样列表永远为N个ID,无需查询最新的列表,直接根据ID去到对应的内容页即可。

8、消息系统

消息队列是大型网站必用中间件,如 ActiveMQ、RabbitMQ、Kafka 等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis 提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。

示例:秒杀和 Redis 的结合

秒杀是现在互联网系统中常见的营销模式,作为开发者,其实最不愿意这样的活动,因为非技术人员无法理解到其中的技术难度,导致在资源协调上总是有些偏差。秒杀其实经常会出现的问题包括:

  • 并发太高导致程序阻塞。
  • 库存无法有效控制,出现超卖的情况。

其实解决这些问题基本就两个方案:

  • 数据尽量缓存,阻断用户和数据库的直接交互。
  • 通过锁来控制避免超卖现象。

现在说明一下,如果现在做一个秒杀,那么,Redis 应该如何结合进行使用?

  • 提前预热数据,放入Redis
  • 商品列表放入Redis List
  • 商品的详情数据 Redis Hash 保存,设置过期时间
  • 商品的库存数据Redis Sorted Set 保存
  • 用户的地址信息 Redis Set 保存
  • 订单产生扣库存通过 Redis 制造分布式锁,库存同步扣除
  • 订单产生后发货的数据,产生 Redis List,通过消息队列处理
  • 秒杀结束后,再把 Redis 数据和数据库进行同步

以上是一个简略的秒杀系统和 Redis 结合的方案,当然实际可能还会引入 HTTP 缓存,或者将消息对接用 MQ 代替等方案,也会出现业务遗漏的情况,这个只是希望能抛砖引玉。

相关资源

  • 官网:https://redis.io/
  • GitHub 仓库:https://github.com/redis/redis
  • 交互式学习 Redis(搭建好的 Redis 学习环境):https://try.redis.io/
  • Redis 中文网(非官方):http://www.redis.cn/
  • Redis 命令参考:http://doc.redisfans.com/

Redis 安装

关于 Redis 的版本

Redis 借鉴了 Linux 操作系统对于版本号的命名规则:

  • 版本号第二位如果是奇数,则为非稳定版本(Unstable),例如 2.7、2.9、3.1
  • 版本号第二位如果是偶数,则为稳定版本(Stable),例如 2.6、3.0、3.2

当前奇数版本就是下一个稳定版本的开发版本,例如 2.9 版本是 3.0 版本的开发版本。

通常在生产环境选取偶数版本的 Redis,而奇数版本则用于提前了解和体验某些新的特性。

获取 Redis 的方式

获取 Redis 的方式有很多种:

  • 安装到自己的电脑上
  • 安装到虚拟机上
  • 安装到远程服务器上
  • 从 Docker Hub 获取 Redis 的 Docker 镜像

在 macOS 中安装 Redis

在 macOS 中有两种方式:

  • 方式一:编译安装,同 Linux
  • 方式二(推荐):使用 Homebrew 安装

macOS 系统下的软件包管理工具 Homebrew 提供了较新版本的 Redis 包,可以直接使用它安装 Redis,省去了在 Linux 上需要手动编译的麻烦。

1、安装 Homebrew

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

2、通过 Homebrew 安装 Redis

brew install redis

在 Windows 中安装 Redis

Redis 官方不支持 Windows。

2011 年微软向 Redis 提交了一个补丁,以使 Redis 可以在 Windows 下编译运行。但被作者拒绝了,原因是在服务器领域上 Linux 已经得到了广泛的使用,让 Redis 能在 Windows 下运行相比而言显得不那么重要。并且 Redis 有很多操作系统相关的特性,兼容 Windows 会耗费过大的精力而影响 Redis 的开发。

尽管如此,微软还是发布了一个可以在 Windows 下的 Redis 版本,但这个项目已经不再维护。

如果实在想要在 Windows 上学习使用 Redis,可以尝试 Memurai,它是一个 Redis for Windows 的替代品,它的核心基于 Redis 源码并且完全兼容 Redis,但是该项目并未得到微软官方的认可。

在 Linux 中安装 Redis

使用以下命令下载、提取和编译 Redis:

# 下载 Redis 源码压缩包
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
# 或使用这个地址下载,这个地址始终指向最新的稳定版本
# wget http://download.redis.io/redis-stable.tar.gz

# 解压压缩包
tar xzf redis-6.2.6.tar.gz

# 进入 Redis 源码目录
cd redis-6.2.6

# 编译安装
make

现在编译的二进制可执行文件可以在 src 目录中找到。执行以下文件运行 Redis:

# 使用完整路径运行 Redis
src/redis-server
# Ctrl+C 停止 Redis,后面介绍停止命令

要想直接使用 Redis 命令去运行 Redis 服务器,需要将可执行文件拷贝到环境变量中的目录中,执行位于该目录下的可执行文件都不需要加上它的完整路径。

可以手动拷贝或直接在源码目录下执行这个命令:

make install

这条命令会将 Redis 二进制可执行文件拷贝到了 /usr/local/bin 目录中, PATH 环境变量默认配置了 /usr/local/bin 目录。

在这里插入图片描述

# 直接运行 Redis
redis-server

Redis 运行、停止和连接

运行 Redis

编译后的 Redis 源码目录的 src 文件夹中会有以下几个可执行文件:

可执行文件说明
redis-serverRedis 服务器
redis-cli与 Redis 交互的命令行界面客户端工具
redis-benchmarkRedis 性能测试工具
redis-check-aofAOF 文件修复工具
redis-check-rdbRDB 文件检查工具(3.0 及更早版本为 redis-check-dump)
redis-sentinel哨兵模式工具(监视和故障切换)

另外,通过编译源码安装的方式,还会在源码根目录产生一个 redis.conf 的配置文件。

在这些可执行文件中最常用的是 redis-serverredis-cli

直接运行 redis-server 即可启动 Redis 服务器:

redis-server

Redis 默认使用 6379 端口,可以通过 --port 参数指定启动端口:

redis-server --port 1234

直接运行 redis-server 会在前台运行 Redis 服务,占用命令行窗口。

可以使用 --daemonize 参数并设置为 yes,以在后端运行 Redis:

redis-server --daemonize yes

查看 Redis 运行状态:

# 查看当前包含 redis 的进程
# 如果能看到 redis-server 的进程,表示 Redis 服务器处于运行状态
ps -ef | grep -i redis

在这里插入图片描述

停止 Redis

考虑到 Redis 有可能正在将内存中的数据同步到硬盘中,强行终止 Redis 进程(例如 Ctrl + C)可能会导致数据丢失。

所以正确停止 Redis 的方式应该是向 Redis 发送 SHUTDOWN 命令:

# 注意:这里用的是 redis-cli 而不是 redis-server
redis-cli shutdown

当 Redis 执行 SHUTDOWN 命令后,会先断开所有客户端连接,然后根据配置执行持久化,最后完成推出。

Redis 可以妥善处理 SIGTERM 信号,所以使用 kill Redis 进程的 PID 的方式也可以正常结束 Redis,效果与发送 SHUTDOWN 命令一样:

# 通过进程号停止 Redis
kill -9 280697

可以通过 ps -ef | grep -i redis 查看停止后是否还有 redis-server 进程。

连接 Redis

redis-cli 是 Redis 自带的基于命令行的 Redis 客户端工具,也是学习和测试 Redis 的重要工具。

运行 redis-cli 即可连接数据库:

redis-cli

默认情况下连接 127.0.0.1:6379 的数据库,也可以指定服务器地址和端口:

redis-cli -h 127.0.0.1 -p 1234

正常情况下,此时已经连接上了 Redis 数据库,可以执行下面测试命令:

# PING 命令如果输出 PONG 表示连接正常
127.0.0.1:6379> PING
PONG
# 向 Redis 中存储一个 key 为 foo,值为 bar 的数据
127.0.0.1:6379> SET foo bar
OK
# 读取数据
127.0.0.1:6379> GET foo
"bar"
# 查询所有数据的 key
127.0.0.1:6379> KEYS *
1) "foo"

断开连接:

  • 命令:quit
  • 快捷键:Ctrl + C

Redis 配置

上面介绍了可以通过 redis-server 的启动参数 --port 设置 Redis 服务的端口号,除此之外 Redis 还支持其他配置选项,如是否开启持久化、日志级别等。

有几种方式进行 Redis 配置:

  1. 命令行参数
  2. 配置文件
  3. 在服务器运行时更改 Redis 配置

通过命令行传递参数

最简单的方式就是在启动 redis-server 的时候直接传递命令参数:

redis-server --port 6379 --host 127.0.0.1

配置文件

由于可以配置的选项较多,通过启动参数设置这些选项并不方便,所以 Redis 支持通过配置文件来设置这些选项。

Redis 提供了一个配置文件的模块 redis.conf,位于源代码目录的根目录路中。

该文件只是一个配置文件的模板,让配置生效的方法是在启动时将配置文件的路径作为启动参数传递给 redis-server:

redis-server <配置文件路径>

通过启动参数传递同名的配置选项会覆盖配置文件中的相应的参数,例如:

redis-server <配置为念路径> --port 3000

建议把配置文件放到统一的目录中(例如 /etc/redis),以端口号命名(例如 6379.conf)。

拷贝配置文件模块到目标文件:

cp <redis 源代码根目录>/redis.conf <redis 配置文件目录>/6379.conf

在服务器运行时更改 Redis 配置

还可以在 Redis 运行时通过 redis-cli 的 CONFIG SET 命令在不重新启动 Redis 的情况下动态修改部分 Redis 配置:

CONFIG SET logLevel warning

注意:在运行期间只能对部分配置项进行修改。

同样,在运行的时候也可以使用 CONFIG GET 命令获得 Redis 当前的配置情况:

CONFIG GET logLevel

Redis 中的多数据库

通过 redis-server 启动的一个 Redis 服务就是一个 Redis 实例。

一个 Redis 实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中。这与我们熟知的在一个关系型数据库中可以创建多个数据库类似,所以可以将其中的每个字典都理解成一个独立的数据库。

Redis 默认支持 16 个数据库,分别编号为:012、…、1415

  • Reids 不支持自定义数据库名称
  • 因为每个数据库都以编号命名,所以开发者必须要明确哪个数据库存放了哪些数据
  • 可以通过配置参数 databases 修改支持的数据库个数

每个数据库都是独立的,也就是说在 0 号数据库插入的数据,在 1 号数据库是访问不到的。

客户端与 Redis 建立连接后自动选择 0 号数据库,可以使用 SELECT 命令来切换数据库:

# 连接 Redis 默认连接的 0 号数据库
redis-cli
127.0.0.1:6379> SET foo bar
OK
127.0.0.1:6379> GET foo
"bar"
127.0.0.1:6379> SELECT 1
OK
# 1 号数据库没有存储 foo
127.0.0.1:6379> GET foo
(nil)
127.0.0.1:6379> KEYS *
(empty array)
# 切换的数据库编号超过设置的值,就会报错
127.0.0.1:6379> SELECT 16
(error) ERR DB index is out of range

Redis 不支持为每个数据库设置不同的访问密码,所以一个客户端要么拥有全部数据库的访问权限,要么一个都没有。

多个数据库之间并不是完全隔离的,例如 FLUSHALL 命令可以清空一个 Redis 实例中所有数据库中的数据。

综上所述,这些数据库更像是一个命名空间,而不适合存储不同应用程序的数据,例如不适合使用 0 号数据库存储 A 应用数据,而使用 1 号数据库存储 B 应用数据,这是非常不推荐的做法!!

不同的应用应该使用不同的 Redis 实例存储数据。

由于 Redis 非常轻量,一个空的 Redis 占用的内存只有 1 MB 左右,所以不用担心多个 Redis 实例会额外占用很多内存的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值