微信公众号:编程笔记本
点击上方蓝字关注我,我们一起学编程
如果觉得内容还不错,请帮忙分享一下
有任何疑问或者想看的内容,欢迎私信
今天我们来学习一下 Redis 的使用。
目录
介绍
Redis 是完全开源免费的,遵守 BSD 协议,是一个高性能的 key-value 数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list、set、zset、hash 等数据结构的存储。
- Redis 支持数据的备份,即 master-slave 模式的数据备份。
优势:
- 性能极高:Redis 能读的速度是 110000 次每秒,写的速度是 81000 次每秒。
- 丰富的数据类型:Redis 支持二进制案例的 Strings、Lists、Hashes、Sets 及 Ordered Sets 数据类型操作。
- 原子:Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI 和 EXEC 指令包起来。
- 丰富的特性:Redis 还支持 publish/subscribe、通知、key 过期等等特性。
区别:
Redis 与其他 key-value 存储有什么不同呢?
- Redis 有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis 的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
- Redis 运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样 Redis 可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
安装
因为笔者的主机是 linux 系统,因此我们只介绍 linux 环境下的安装方式。
wget http://download.redis.io/releases/redis-5.0.8.tar.gz
tar xzf redis-5.0.8.tar.gz
cd redis-5.0.8/
make
由于 Redis 是开源软件,所以我们可以选择在线安装。第一句是下载源码,第二句是解压,后面三句是进入安装目录并执行安装。这也是 linux 环境下,大部分软件安装的流程和方式。
安装完成后,我们需要添加环境变量,以便于在任何位置启动 redis 。
# 切换到root用户,修改/etc/profile文件,添加:
export PATH=$PATH:<redis-server和redis-cli所在目录>
启动 redis 服务器:
jincheng@jincheng:~$ redis-server
2492:C 13 Apr 2020 14:55:23.175 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2492:C 13 Apr 2020 14:55:23.175 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=2492, just started
2492:C 13 Apr 2020 14:55:23.175 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
2492:M 13 Apr 2020 14:55:23.176 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 5.0.8 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 2492
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
2492:M 13 Apr 2020 14:55:23.178 # Server initialized
2492:M 13 Apr 2020 14:55:23.178 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
2492:M 13 Apr 2020 14:55:23.178 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
2492:M 13 Apr 2020 14:55:23.178 * Ready to accept connections
启动 redis 命令行客户端:
jincheng@jincheng:~$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
可以看到,服务器已响应。其中,127.0.0.1 是本机 IP ,6379 是 redis 默认的服务端口。
配置
Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf 。
详细的配置说明如下:
图片-1
以特定配置文件启动 redis 服务:
jincheng@jincheng:~$ redis-server /home/jincheng/SoftWare/redis-5.0.8/redis.conf
数据类型
Redis 支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及 zset(sorted set:有序集合)。
具体如下表所示:
图片-2
String(字符串)
string 是 redis 最基本的类型,可以理解为与 Memcached 一模一样的类型,一个 key 对应一个 value 。string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象。string 类型的值最大能存储 512MB 。
jincheng@jincheng:~$ redis-cli
127.0.0.1:6379> SET jincheng "ok"
OK
127.0.0.1:6379> get jincheng
"ok"
127.0.0.1:6379>
redis 中的命令不区分大小写。在以上实例中我们使用了 SET 和 GET 命令。键为 jincheng,对应的值为 ok 。
注意:一个键最大能存储 512MB。
Hash(哈希)
Redis hash 是一个键值对 (key=>value) 集合。是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
127.0.0.1:6379> hmset person name "jincheng" age "18" sex "male"
OK
127.0.0.1:6379> hget person name
"jincheng"
127.0.0.1:6379> hget person age
"18"
127.0.0.1:6379> hget person sex
"male"
127.0.0.1:6379>
上述实例中我们使用了 HMSET, HGET 命令,HMSET 设置了三个 field=>value 对, HGET 获取对应 field 对应的 value。每个 hash 可以存储 2^32 -1 个键值对。
List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
127.0.0.1:6379> lpush phones nokia
(integer) 1
127.0.0.1:6379> lpush phones huawei oppo vivo
(integer) 4
127.0.0.1:6379> lrange phones 0 10
1) "vivo"
2) "oppo"
3) "huawei"
4) "nokia"
127.0.0.1:6379>
一个列表最多可存储 2^32 - 1 个元素。
Set(集合)
Redis 的 Set 是 string 类型的无序集合。集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是 O(1)。
127.0.0.1:6379> sadd date "today"
(integer) 1
127.0.0.1:6379> sadd date "yesterday"
(integer) 1
127.0.0.1:6379> sadd date "tomorrow"
(integer) 1
127.0.0.1:6379> sadd date "today" "yesterday"
(integer) 0
127.0.0.1:6379> smembers date
1) "tomorrow"
2) "yesterday"
3) "today"
127.0.0.1:6379>
sadd 命令:添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。
一个集合中最大的成员数为 2^32 - 1 个,且不保存重复的值。
zset(sorted set:有序集合)
Redis zset 和 set 一样也是 string 类型元素的集合,但不允许重复的成员。不同的是每个元素都会关联一个double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。zset 的成员是唯一的,但分数(score) 却可以重复。
127.0.0.1:6379> zadd fruit 0 apple 0 banana
(integer) 2
127.0.0.1:6379> zadd fruit 0 pear
(integer) 1
127.0.0.1:6379> zadd fruit 1 apple
(integer) 0
127.0.0.1:6379> zrangebyscore fruit 0 10000
1) "banana"
2) "pear"
3) "apple"
127.0.0.1:6379>
zadd 命令:zadd key score member
添加元素到集合,元素在集合中存在则更新对应 score 。
命令
Redis 命令用于在 redis 服务上执行操作。要在 redis 服务上执行命令需要一个 redis 客户端。
在本机上执行命令:
在本机上执行 redis 命令,仅需在命令行中输入 redis-cli 即可:
jincheng@LAPTOP-E4NSNKIT:~$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
在远程服务上执行命令:
此时我们需要登录远程主机的 redis 服务器,那么我们就需要知道服务器的 IP 地址、端口号、登陆密码。
由于默认的配置文件中配置的是不需要密码,所以我们先来创建密码:
jincheng@LAPTOP-E4NSNKIT:~$ redis-cli
127.0.0.1:6379> config set requirepass codingbook
OK
127.0.0.1:6379>
上面的操作已经在 redis 上设置了密码:codingbook 。当我们再次登录时,若不提供密码,则 redis 服务器会提示需要认证:
jincheng@LAPTOP-E4NSNKIT:~$ redis-cli
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6379>
所以,在 redis 设置了密码以后,我们在登陆上服务器之后,一定先进行认证:
jincheng@LAPTOP-E4NSNKIT:~$ redis-cli
127.0.0.1:6379> auth codingbook
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379>
有了密码以后,下面我们再来演示如何登陆远程 redis 服务器:
jincheng@LAPTOP-E4NSNKIT:~$ redis-cli -h 127.0.0.1 -p 6379 -a "codingbook"
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
上面的命令表示:登录 IP 地址为 127.0.0.1 、端口号为 6379 、密码为 codingbook 的 redis 服务器。
键
先看一个实例:
jincheng@LAPTOP-E4NSNKIT:~$ redis-cli
127.0.0.1:6379> SET tool redis
OK
127.0.0.1:6379> DEL tool
(integer) 1
127.0.0.1:6379> DEL tool
(integer) 0
127.0.0.1:6379>
在上面的实例中,DEL
是一个命令,执行删除操作,tool
是一个键,如果键被删除成功,命令执行后输出 (integer) 1,否则将输出 (integer) 0 。
与键相关的命令
图-3
字符串
先看一个实例:
127.0.0.1:6379> SET name jincheng
OK
127.0.0.1:6379> GET name
"jincheng"
127.0.0.1:6379>
在以上实例中我们使用了 SET
和 GET
命令,键为 name。
与字符串相关的命令
图-4
哈希
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。Redis 中每个 hash 可以存储 2^32 - 1 个键值对。
127.0.0.1:6379> HMSET person name "jincheng" age "26" school "HFUT"
OK
127.0.0.1:6379> HGET person name
"jincheng"
127.0.0.1:6379> HGETALL person
1) "name"
2) "jincheng"
3) "age"
4) "26"
5) "school"
6) "HFUT"
127.0.0.1:6379>
在以上实例中,我们设置了人的一些描述信息(name、age、school) 到哈希表 person 中。
与哈希相关的命令
图-5
列表
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。一个列表最多可以包含 2^32 - 1 个元素。
127.0.0.1:6379> LPUSH phone huawei
(integer) 1
127.0.0.1:6379> LPUSH phone oppo vivo
(integer) 3
127.0.0.1:6379> LRANGE phone 0 10
1) "vivo"
2) "oppo"
3) "huawei"
127.0.0.1:6379>
在以上实例中我们使用了 LPUSH
将三个值插入了名为 phone 的列表当中。
与列表相关的命令
图-6
集合
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是 O(1)。集合中最大的成员数为 2^32 - 1 。
127.0.0.1:6379> SADD lang C C++ GO SQL
(integer) 4
127.0.0.1:6379> SADD lang Python C++
(integer) 1
127.0.0.1:6379> SMEMBERS lang
1) "C++"
2) "SQL"
3) "C"
4) "GO"
5) "Python"
127.0.0.1:6379>
在以上实例中我们通过 SADD
命令向名为 lang 的集合插入若干个元素,重复元素只存储一份。
与集合相关的命令
图-7
有序集合
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是 O(1) 。集合中最大的成员数为 2^32 - 1 。
127.0.0.1:6379> ZADD year 1 2008
(integer) 1
127.0.0.1:6379> ZADD year 2 2010
(integer) 1
127.0.0.1:6379> ZADD year 3 2018
(integer) 1
127.0.0.1:6379> ZADD year 3 2018
(integer) 0
127.0.0.1:6379> ZADD year 4 2018
(integer) 0
127.0.0.1:6379> ZRANGE year 0 10 WITHSCORES
1) "2008"
2) "1"
3) "2010"
4) "2"
5) "2018"
6) "4"
127.0.0.1:6379>
与有序集合相关的命令
图-8
HyperLogLog
Redis 在 2.8.9 版本添加了 HyperLogLog 结构。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的.
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
什么是基数?
比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为 5 。 基数估计就是在误差可接受的范围内,快速计算基数。
127.0.0.1:6379> PFADD num 1 2 3 4 5
(integer) 1
127.0.0.1:6379> PFADD num 2 4 6 8 0
(integer) 1
127.0.0.1:6379> PFCOUNT num
(integer) 8
127.0.0.1:6379>
与 HyperLogLog 相关的命令
图-9
发布订阅
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis 客户端可以订阅任意数量的频道。
下图展示了三个客户端订阅了同一个频道:
图-10
一旦频道收到某信息,频道会立刻将信息发送到订阅它的客户端:
图-11
以下实例演示了发布订阅是如何工作的:
127.0.0.1:6379> SUBSCRIBE channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
现在,我们先重新开启个 redis 客户端,然后在同一个频道 channel1 发布两次消息,订阅者就能接收到消息。
jincheng@LAPTOP-E4NSNKIT:~/SoftWare/redis-5.0.8/src$ ./redis-cli
127.0.0.1:6379> auth codingbook
OK
127.0.0.1:6379> PUBLISH channel1 hello
(integer) 1
127.0.0.1:6379> PUBLISH channel1 world
(integer) 1
127.0.0.1:6379>
此时,之前的打开的客户端显示如下:
127.0.0.1:6379> SUBSCRIBE channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "hello"
1) "message"
2) "channel1"
3) "world"
与发布订阅相关的命令
图-12
事务
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
- 批量操作在发送
EXEC
命令前被放入队列缓存。 - 收到
EXEC
命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。 - 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:开始事务、命令入队、执行事务。
以下是一个事务的例子, 它先以 MULTI
开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC
命令触发事务, 一并执行事务中的所有命令:
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET person-name "jincheng"
QUEUED
127.0.0.1:6379> GET person-name
QUEUED
127.0.0.1:6379> SADD pets "dog"
QUEUED
127.0.0.1:6379> SMEMBERS pets
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) "jincheng"
3) (integer) 1
4) 1) "dog"
127.0.0.1:6379>
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
与事务相关的命令
图-13
脚本
Redis 脚本使用 Lua 解释器来执行脚本。 Redis 2.6 版本通过内嵌支持 Lua 环境。执行脚本的常用命令为 EVAL
。
EVAL
命令的语法如下:
redis 127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]
以下实例演示了 redis 脚本工作过程:
127.0.0.1:6379> EVAL "return {KEYS[1], KEYS[2], ARGV[1], ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"
127.0.0.1:6379>
与脚本相关的命令
图-14
连接
Redis 连接命令主要是用于连接 redis 服务。
以下实例演示了客户端如何通过密码验证连接到 redis 服务,并检测服务是否在运行:
127.0.0.1:6379> AUTH codingbook
OK
127.0.0.1:6379> PING
PONG
127.0.0.1:6379>
与连接相关的命令
图-15
服务器
Redis 服务器命令主要是用于管理 redis 服务。
以下实例演示了如何获取 redis 服务器的统计信息:
127.0.0.1:6379> INFO
# Server
redis_version:5.0.8
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:3a89591144f2525c
redis_mode:standalone
os:Linux 4.4.0-18362-Microsoft x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:7.5.0
process_id:155
run_id:7264c9d98ad21bcea11f2ce8ca8b2ba56d7d3a15
tcp_port:6379
uptime_in_seconds:5341
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:9971340
executable:/home/jincheng/SoftWare/redis-5.0.8/src/./redis-server
config_file:/home/jincheng/SoftWare/redis-5.0.8/redis.conf
# Clients
connected_clients:1
client_recent_max_input_buffer:2
client_recent_max_output_buffer:0
blocked_clients:0
# Memory
used_memory:855912
used_memory_human:835.85K
used_memory_rss:4136960
used_memory_rss_human:3.95M
used_memory_peak:875240
used_memory_peak_human:854.73K
used_memory_peak_perc:97.79%
used_memory_overhead:841638
used_memory_startup:791488
used_memory_dataset:14274
used_memory_dataset_perc:22.16%
allocator_allocated:940232
allocator_active:1212416
allocator_resident:10964992
total_system_memory:8459030528
total_system_memory_human:7.88G
used_memory_lua:40960
used_memory_lua_human:40.00K
used_memory_scripts:152
used_memory_scripts_human:152B
number_of_cached_scripts:1
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.29
allocator_frag_bytes:272184
allocator_rss_ratio:9.04
allocator_rss_bytes:9752576
rss_overhead_ratio:0.38
rss_overhead_bytes:-6828032
mem_fragmentation_ratio:5.08
mem_fragmentation_bytes:3323304
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:49694
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1587029043
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
# Stats
total_connections_received:9
total_commands_processed:55
instantaneous_ops_per_sec:0
total_net_input_bytes:2153
total_net_output_bytes:12584
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
evicted_keys:0
keyspace_hits:8
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:2982
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
# Replication
role:master
connected_slaves:0
master_replid:fbe38bb20ef7a906520b5b343a4f2cc256b7d3c6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:0.406250
used_cpu_user:0.250000
used_cpu_sys_children:0.031250
used_cpu_user_children:0.000000
# Cluster
cluster_enabled:0
# Keyspace
db0:keys=6,expires=0,avg_ttl=0
127.0.0.1:6379>
与服务器相关的命令
图-16
数据备份与恢复
Redis SAVE
命令用于创建当前数据库的备份。该命令将在 redis 安装目录中创建 dump.rdb 文件。
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379>
现在我们看一下安装目录下是否有该文件:
jincheng@LAPTOP-E4NSNKIT:~/SoftWare/redis-5.0.8/src$ cd /home/jincheng/SoftWare/redis-5.0.8/src
jincheng@LAPTOP-E4NSNKIT:~/SoftWare/redis-5.0.8/src$ ls
Makefile cluster.o geo.o lzf_c.c rax.h rio.o syncio.o
Makefile.dep config.c geohash.c lzf_c.o rax.o scripting.c t_hash.c
adlist.c config.h geohash.h lzf_d.c rax_malloc.h scripting.o t_hash.o
adlist.h config.o geohash.o lzf_d.o rdb.c sds.c t_list.c
adlist.o crc16.c geohash_helper.c memtest.c rdb.h sds.h t_list.o
ae.c crc16.o geohash_helper.h memtest.o rdb.o sds.o t_set.c
ae.h crc64.c geohash_helper.o mkreleasehdr.sh redis-benchmark sdsalloc.h t_set.o
ae.o crc64.h help.h module.c redis-benchmark.c sentinel.c t_stream.c
ae_epoll.c crc64.o hyperloglog.c module.o redis-benchmark.o sentinel.o t_stream.o
ae_evport.c db.c hyperloglog.o modules redis-check-aof server.c t_string.c
ae_kqueue.c db.o intset.c multi.c redis-check-aof.c server.h t_string.o
ae_select.c debug.c intset.h multi.o redis-check-aof.o server.o t_zset.c
anet.c debug.o intset.o networking.c redis-check-rdb setproctitle.c t_zset.o
anet.h debugmacro.h latency.c networking.o redis-check-rdb.c setproctitle.o testhelp.h
anet.o defrag.c latency.h notify.c redis-check-rdb.o sha1.c util.c
aof.c defrag.o latency.o notify.o redis-cli sha1.h util.h
aof.o dict.c lazyfree.c object.c redis-cli.c sha1.o util.o
asciilogo.h dict.h lazyfree.o object.o redis-cli.o siphash.c valgrind.sup
atomicvar.h dict.o listpack.c pqsort.c redis-sentinel siphash.o version.h
bio.c dump.rdb listpack.h pqsort.h redis-server slowlog.c ziplist.c
bio.h endianconv.c listpack.o pqsort.o redis-trib.rb slowlog.h ziplist.h
bio.o endianconv.h listpack_malloc.h pubsub.c redisassert.h slowlog.o ziplist.o
bitops.c endianconv.o localtime.c pubsub.o redismodule.h solarisfixes.h zipmap.c
bitops.o evict.c localtime.o quicklist.c release.c sort.c zipmap.h
blocked.c evict.o lolwut.c quicklist.h release.h sort.o zipmap.o
blocked.o expire.c lolwut.o quicklist.o release.o sparkline.c zmalloc.c
childinfo.c expire.o lolwut5.c rand.c replication.c sparkline.h zmalloc.h
childinfo.o fmacros.h lolwut5.o rand.h replication.o sparkline.o zmalloc.o
cluster.c geo.c lzf.h rand.o rio.c stream.h
cluster.h geo.h lzfP.h rax.c rio.h syncio.c
jincheng@LAPTOP-E4NSNKIT:~/SoftWare/redis-5.0.8/src$ find . -name "dump.rdb"
./dump.rdb
jincheng@LAPTOP-E4NSNKIT:~/SoftWare/redis-5.0.8/src$
可以看到,安装目录下的确有了备份文件。如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。
BGSAVE
创建 redis 备份文件也可以使用命令 BGSAVE
,该命令在后台执行。
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379>
安全
我们可以通过 redis 的配置文件设置密码参数,这样客户端连接到 redis 服务就需要密码验证,这样可以让你的 redis 服务更安全。
我们可以通过以下命令查看是否设置了密码验证:
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) ""
127.0.0.1:6379>
默认情况下 requirepass 参数是空的,这就意味着你无需通过密码验证就可以连接到 redis 服务。你可以通过以下命令来修改该参数:
127.0.0.1:6379> CONFIG SET requirepass "codingbook"
OK
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "codingbook"
设置密码后,客户端连接 redis 服务就需要密码验证,否则无法执行命令。
使用 AUTH
命令进行认证:
127.0.0.1:6379> AUTH codingbook
OK
127.0.0.1:6379>
性能测试
Redis 性能测试是通过同时执行多个命令实现的。
redis 性能测试的基本命令如下:
redis-benchmark [option] [option value]
注意:该命令是在 redis 的目录下执行的,而不是 redis 客户端的内部指令。
以下实例同时执行 10000 个请求来检测性能:
jincheng@LAPTOP-E4NSNKIT:~$ cd /home/jincheng/SoftWare/redis-5.0.8/src/
jincheng@LAPTOP-E4NSNKIT:~/SoftWare/redis-5.0.8/src$ ./redis-benchmark -n 10000
====== PING_INLINE ======
10000 requests completed in 0.34 seconds
50 parallel clients
3 bytes payload
keep alive: 1
90.65% <= 1 milliseconds
99.91% <= 2 milliseconds
100.00% <= 2 milliseconds
29673.59 requests per second
====== PING_BULK ======
10000 requests completed in 0.33 seconds
50 parallel clients
3 bytes payload
keep alive: 1
92.36% <= 1 milliseconds
99.89% <= 2 milliseconds
100.00% <= 2 milliseconds
30303.03 requests per second
====== SET ======
10000 requests completed in 0.33 seconds
50 parallel clients
3 bytes payload
keep alive: 1
94.34% <= 1 milliseconds
100.00% <= 1 milliseconds
30581.04 requests per second
====== GET ======
10000 requests completed in 0.33 seconds
50 parallel clients
3 bytes payload
keep alive: 1
93.25% <= 1 milliseconds
99.91% <= 2 milliseconds
100.00% <= 2 milliseconds
30211.48 requests per second
jincheng@LAPTOP-E4NSNKIT:~/SoftWare/redis-5.0.8/src$
redis 性能测试工具可选参数如下所示:
图-17
客户端连接
Redis 通过监听一个 TCP 端口或者 Unix socket 的方式来接收来自客户端的连接,当一个连接建立后,Redis 内部会进行以下一些操作:
- 首先,客户端 socket 会被设置为非阻塞模式,因为 Redis 在网络事件处理上采用的是非阻塞多路复用模型。
- 然后为这个 socket 设置 TCP_NODELAY 属性,禁用 Nagle 算法
- 然后创建一个可读的文件事件用于监听这个客户端 socket 的数据发送
最大连接数
在 Redis2.4 中,最大连接数是被直接硬编码在代码里面的,而在2.6版本中这个值变成可配置的。maxclients 的默认值是 10000,你也可以在 redis.conf 中对这个值进行修改。
127.0.0.1:6379> CONFIG GET maxclients
1) "maxclients"
2) "10000"
127.0.0.1:6379>
也可以在启动服务器的时候指定最大连接数:
redis-server --maxclients 100000
客户端命令
图片-18
管道技术
Redis是一种基于客户端-服务端模型以及请求/响应协议的 TCP 服务。这意味着通常情况下一个请求会遵循以下步骤:
- 客户端向服务端发送一个查询请求,并监听 Socket 返回,通常是以阻塞模式,等待服务端响应。
- 服务端处理命令,并将结果返回给客户端。
Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
127.0.0.1:6379> (echo -en "PING\r\n SET tool redis\r\nGET tool\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n"; sleep 10) | nc localhost 6379
+PONG
+OK
redis
:1
:2
:3
127.0.0.1:6379>
以上实例中我们通过使用 PING 命令查看 redis 服务是否可用, 之后我们设置了 tool 的值为 redis,然后我们获取 tool 的值并使得 visitor 自增 3 次。在返回的结果中我们可以看到这些命令一次性向 redis 服务提交,并最终一次性读取所有服务端的响应。
分区
分区是分割数据到多个 Redis 实例的处理过程,因此每个实例只保存 key 的一个子集。
分区的优势:
- 通过利用多台计算机内存的和值,允许我们构造更大的数据库。
- 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。
分区的不足:
- redis 的一些特性在分区方面表现的不是很好:
- 涉及多个 key 的操作通常是不被支持的。举例来说,当两个 set 映射到不同的 redis 实例上时,你就不能对这两个 set 执行交集操作。
- 涉及多个 key 的 redis 事务不能使用。
- 当使用分区时,数据处理较为复杂,比如你需要处理多个 rdb/aof 文件,并且从多个实例和主机备份持久化文件。
- 增加或删除容量也比较复杂。redis 集群大多数支持在运行时增加、删除节点的透明数据平衡的能力,但是类似于客户端分区、代理等其他系统则不支持这项特性。然而,一种叫做 presharding 的技术对此是有帮助的。
分区类型:
Redis 有两种类型分区。 假设有 4 个 Redis 实例 R0,R1,R2,R3,和类似 user:1,user:2 这样的表示用户的多个 key ,对既定的 key 有多种不同方式来选择这个 key 存放在哪个实例中。也就是说,有不同的系统来映射某个 key 到某个 Redis 服务。
范围分区
最简单的分区方式是按范围分区,就是映射一定范围的对象到特定的 Redis 实例。
比如,ID 从 0 到 10000 的用户会保存到实例 R0,ID 从 10001 到 20000 的用户会保存到R1,以此类推。
这种方式是可行的,并且在实际中使用,不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对 Redis 来说并非是好的方法。
哈希分区
另外一种分区方法是 hash 分区。这对任何 key 都适用,也无需是 object_name: 这种形式,像下面描述的一样简单:
- 用一个 hash 函数将 key 转换为一个数字,比如使用 crc32 hash 函数。对 key foobar 执行 crc32(foobar) 会输出类似 93024922 的整数。
- 对这个整数取模,将其转化为 0-3 之间的数字,就可以将这个整数映射到 4 个 Redis 实例中的一个了。93024922 % 4 = 2,就是说 key foobar 应该被存到 R2 实例中。注意:取模操作是取除的余数,通常在多种编程语言中用 % 操作符实现。