# 一.Redis的安装和使用
## 1、什么 Redis
**RE**mote **DI**ctionary **S**erver,简称 Redis,可以直接理解为远程字典服务,是一个类似于Memcached的Key-Value存储系统。相比Memcached,它支持更丰富的数据结构,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型),并提供了数据持久化机制,在某些场景下,你完全可以把它当做非关系型数据库来使用。它是一个高性能的存储系统,能支持超过 100K+ 每秒的读写频率。同时还支持消息的发布/订阅,从而让你在构建高性能消息队列系统时多了另一种选择。
## 2、Redis VS Memcached,为啥选择用Redis作为缓存中间件?
### Memcached 的特点
- 处理请求时使用多线程异步 IO 的方式,可以合理利用 CPU 多核的优势,性能非常优秀;
- 功能简单,使用内存存储数据;
- 内存结构以及钙化问题
> Memcached采用LRU淘汰算法,在内存容量满时踢出过期失效和LRU数据,为新数据腾出内存空间。不过该淘汰算法在内存空间不足以分配新的Slab情况下,只会在同一类Slab内部踢出数据。
即当某个Slab容量满,且内存不足够分配新的Slab,只会在相同Slab内部踢出数据,而不会挪用或者踢出其他Slab的数据。这种局部剔除数据的淘汰算法带来一个问题:``Slab钙化``。
- 对缓存的数据可以设置失效期,过期后的数据会被清除;
- 失效的策略采用延迟失效,就是当再次使用数据时检查是否失效;
- 当容量存满时,会对缓存中的数据进行剔除,剔除时除了会对过期 key 进行清理,还会按 LRU 策略对数据进行剔除。
### Memcached 的一些限制
这些限制在现在的互联网场景下很致命,成为大家选择Redis、MongoDB的重要原因:
- key 不能超过 250 个字节;
- value 不能超过 1M 字节;
- key 的最大失效时间是 30 天;
- 只支持 K-V 结构,不提供持久化和主从同步功能。
### Redis 支持复杂的数据结构
Redis 相比 Memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。如果需要缓存能够支持更复杂的结构和操作, Redis 会是不错的选择。
### Redis 原生支持集群模式
在 redis3.x 版本中,便能支持 Cluster 模式,而 Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据。
### 性能对比
由于 Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis 在存储小数据时比 Memcached 性能更高。
而在 100k 以上的数据中,Memcached 性能要高于 Redis,虽然 Redis 最近也在存储大数据的性能上进行优化,但是比起 Remcached,还是稍有逊色。
> 此部分来自[《吊打面试官》系列-Redis常见面试题 by 敖丙](https://juejin.im/post/5dcaebea518825571f5c4ab0),[《吊打面试官》系列-Redis双写一致性、并发竞争、线程模型](https://juejin.im/post/5dc850b4e51d452c2308ee27),感谢~
## 2、安装
Redis装起来,实在是过于简单,让我几乎“无从下手”。因为连`configure`文件都不需要,你只需要做个`make`和`make install`就好。我在这里下载的是redis-3.0.1版.
如果报找不到`gc++`, 执行以下命令即可。
```bash
yum -y install make gcc gcc-c++ ncurses-devel
yum -y install zlib zlib-devel
```
如果报
`error: jemalloc/jemalloc.h: No such file or directory`
使用以下命令即可编译通过
```bash
make MALLOC=libc
```
关于分配器 `allocator`, 如果有 `MALLOC` 这个环境变量,会用这个环境变量的 去建立Redis。而且 `libc` 并不是默认的 分配器, 默认的是 `jemalloc`, 因为 `jemalloc` 被证明有比`libc`更少的 `fragmentation problems` 。但是如果你又没有 `jemalloc` 而只有 `libc` 当然 `make` 出错。 所以加这么一个参数。
## 3、运行
- 1.启动服务,先进入 src 目录,然后执行 `redis-server`。(`6379` 是 redis 默认端口)
- 2.也可以把默认的配置文件——`redis.conf`拷贝到固定的目录下,例如:`/etc/redis/`目录下,然后执行命令
```bash
redis-server /etc/redis/redis.conf
```
## 4、测试
通过客户端命令`redis-cli`访问Redis
```bash
set name sherlock
get name
```
进行数据测试:
```bash
redis-benchmark -l
```
## 5、关闭
可通过客户端命令redis-cli完成Redis关闭操作,当然,也可以通过 kill 命令来关闭服务。
```bash
redis-cli shutdown
```
## 6、调优
### 1) /etc/sysctl.conf
刚才启动后有以下警告:
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.
需要修改`/etc/sysctl.conf`文件:
末尾追加**`vm.overcommit_memory=1`**
然后执行**`sysctl vm.overcommit_memory=1`**,使之生效:
### 2) /proc/sys/vm/overcommit_memory
为了调整内存分配策略,需要配置`/proc/sys/vm/overcommit_memory`
- 0:表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
- 1:表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
- 2:表示内核允许分配超过所有物理内存和交换空间总和的内存
默认为0,如果内存情况比较紧张的话,设为1:
`echo 1 > /proc/sys/vm/overcommit_memory`
### 3) redis.conf
前面启动Redis后,总是在命令行里不断跳着各种日志,很麻烦。即便通过**`&`**,令其后台运行,也无济于事。这就需要修改`redis.conf`,以Daemo模式运行!
redis.conf参数:
- daemonize:是否以后台daemon方式运行
- pidfile:pid文件位置
- port:监听的端口号
- timeout:请求超时时间
- loglevel:log信息级别
- logfile:log文件位置
- databases:开启数据库的数量
- save \* \*:保存快照的频率,第一个\*表示多长时间(秒级),第三个\*表示执行多少次写操作。在一定时间内执行一定数量的写操作时,自动保存快照。可设置多个条件。
- rdbcompression:是否使用压缩
- dbfilename:数据快照文件名(只是文件名,不包括目录)
- dir:数据快照的保存目录(这个是目录)
- appendonly:是否开启appendonlylog,开启的话每次写操作会记一条log,这会提高数据抗风险能力,但影响效率。
- appendfsync:appendonlylog如何同步到磁盘(三个选项,分别是每次写都强制调用fsync、每秒启用一次fsync、不调用fsync等待系统自己同步)
- slaveof <masterip\> <masterport\> :主从配置,在redis-slave上配置master的ip port,即可。
例如,我们可以修改为如下方式:
daemonize yes #守护进程模式
save 60 1000 #当时间间隔超过60秒,或存储超过1000条记录时,进行持久化。
maxmemory 256mb #分配256MB内存
PS:切记,一定要设定**maxmemmory**,且配置大小要小于物理内存,留有足够的内存供系统使用。
### 4) TCP somaxconn配置修改
刚才启动后还有以下警告:
17366:M 26 May 15:28:57.245 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
`/proc/sys/net/core/somaxconn` 这个参数,linux中内核的一个不错的参数somaxconn
对于一个TCP连接,Server与Client需要通过三次握手来建立网络连接.当三次握手成功后,我们可以看到端口的状态由LISTEN转变为ESTABLISHED,接着这条链路上就可以开始传送数据了.
每一个处于监听(Listen)状态的端口,都有自己的监听队列.监听队列的长度,与如下两方面有关:
- somaxconn参数.
- 使用该端口的程序中listen()函数.
关于somaxconn参数:
定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数,默认值为128,具体信息为:
Purpose:
Specifies the maximum listen backlog.
Values:
Default: 128 connections
Range: 0 to MAXSHORT
Type: Connect
Diagnosis:
N/A
Tuning
Increase this parameter on busy Web servers to handle peak connection rates.
看下FREEBSD的解析:
限制了接收新 TCP 连接侦听队列的大小。对于一个经常处理新连接的高负载 web服务环境来说,默认的 `128` 太小了。大多数环境这个值建议增加到 1024 或者更多。 服务进程会自己限制侦听队列的大小(例如 `sendmail(8)` 或者 `Apache`),常常在它们的配置文件中有设置队列大小的选项。大的侦听队列对防止拒绝服务 DoS 攻击也会有所帮助。
我们可以通过,
echo 511 >/proc/sys/net/core/somaxconn
来修改这个参数。
### 5) 下面介绍另外一种配置方式,通过命令行来配置。
假如说我们不想修改配置文件来启动指定端口号的redis服务,我们可以在终端上执行下面的命令:
redis-server --port 6379 --daemonize yes
redis-cli -p 6379
但我还是推荐使用配置文件的方式。
如果在生产环境里面需要修改某些配置项,但我们又不想停掉服务,怎么办?
Redis允许在运行的过程中,在不重启服务器的情况下更改服务器配置,同时也支持 使用特殊的[CONFIG SET](http://www.redis.cn/commands/config-set.html)和 [CONFIG GET](http://www.redis.cn/commands/config-get.html)命令用编程方式查询并设置配置。
# 二.Redis 主从复制
Redis 的主从复制配置非常容易,但我们先来了解一下它的一些特性。
- 1.redis 使用异步复制。从 redis 2.8 开始,slave 也会周期性的告诉 master 现在的数据量。可能只是个机制,用途应该不大。
- 2.一个 master 可以拥有多个 slave,废话,这也是业界的标配吧。
- 3.slave 可以接收来自其他 slave 的连接。意思是不是就是说 slave 在接收其他的slave的连接之后成为 master ?等下我们来验证。
- 4.redis 复制在 master 这一端是非阻塞的,也就是说在和 slave 同步数据的时候,master 仍然可以执行客户端的操作命令而不受其影响。这点都不能保证,要你干嘛?
- 5.redis 复制在 slave 这一端也是非阻塞的。在配置文件里面有 slave-serve-stale-data 这一项,如果它为 yes ,slave 在执行同步时,它可以使用老版本的数据来处理查询请求,如果是 no ,slave 将返回一个错误。在完成同步后,slave 需要删除老数据,加载新数据,在这个阶段,slave 会阻止连接进来。
- 6.Replication can be used both for scalability, in order to have multiple slaves for read-only queries (for example, heavy SORT operations can be offloaded to slaves), or simply for data redundancy.这句话我也没理解什么意思。
- 7.使用复制可以避免 master 因为需要把全部的数据集写入磁盘而造成的开销,因此可以把 master 中 save 配置项全部注释掉,不让它进行保存,然后配置 slave ,让 slave 保存。虽然有这个特性,但是我们好像一般不这么做。
好吧,我们做几个例子练习一下。
先打开三个终端,然后起三个实例,分别用三个 client 去连接它们:
master
$ ./redis-server --port 10000 --daemonize yes
$ ./redis-cli -p 10000
slave 01:
$ ./redis-server --port 10001 --daemonize yes
$ ./redis-cli -p 10001
slave 02:
$ ./redis-server --port 10002 --daemonize yes
$ ./redis-cli -p 10002
上面只是让它们的实例启动了并用客户端去连接它,并没有设置主从关系。在 `slave 01` 和 `slave 02` 上执行下面的命令:
127.0.0.1:10001> slaveof 127.0.0.1 10000
OK
127.0.0.1:10001>
这样就设置好了主从关系。我们来试试有没有效果。
127.0.0.1:10001> get name
(nil)
127.0.0.1:10001>
这个时候是没有值的。
master 上执行:
127.0.0.1:10000> set name sherlock
OK
127.0.0.1:10000>
然后看看 slave 上有没有:
127.0.0.1:10001> get name
"sherlock"
127.0.0.1:10001>
127.0.0.1:10002> get name
"sherlock"
127.0.0.1:10002>
有了,是不是很easy ?已经有了感性的认识,我们来介绍一下它的原理吧。
当你设置了主从关系后,`slave` 在第一次连接或者重新连接 `master` 时,`slave` 都会发送一条同步指令给`master`;
`master` 接到指令后,开始启动后台保存进程保存数据,接着收集所有的数据修改指令。后台保存完了,`master` 就把这份数据发送给 `slave`,`slave` 先把数据保存到磁盘,然后把它加载到内存中,`master` 接着就把收集的数据修改指令一行一行的发给 `slave`,`slave` 接收到之后重新执行该指令,这样就实现了数据同步。
`slave` 在与 `master` 失去联系后,自动的重新连接。如果 `master` 收到了多个 `slave` 的同步请求,它会执行单个后台保存来为所有的 `slave` 服务。
一旦 `master` 和 `slave` 在失去联系并重新连接上,总是会重新进行一次完整的同步。不过从 `redis 2.8` 开始,只是部分重新同步也是可以的。具体请大家参考官方文档。
#三.主从备份
在从服务器上执行下列命令:
$备份
redis-cli save
$关闭redis服务器
redis-cli shutdown
然后,拷贝数据目录下的`rdb`文件。
# 参考
- 1.有关linux下redis overcommit_memory的问题
[http://blog.csdn.net/whycold/article/details/21388455](http://blog.csdn.net/whycold/article/details/21388455 "有关linux下redis overcommit_memory的问题")
- 2.Redis实战(系列)[http://blog.csdn.net/it_man/article/details/9730559](http://blog.csdn.net/it_man/article/details/9730559)
- 3.高性能网站架构设计之缓存篇(1)- Redis的安装与使用 [http://www.cnblogs.com/zhaoguihua/p/redis-001.html](http://www.cnblogs.com/zhaoguihua/p/redis-001.html)
- 4.linux环境 redis overcommit_memory [https://blog.hackroad.com/operations-engineer/linux_server/1422.html](https://blog.hackroad.com/operations-engineer/linux_server/1422.html)
- 5.理解和配置 Linux 下的 OOM Killer [http://www.vpsee.com/2013/10/how-to-configure-the-linux-oom-killer/](http://www.vpsee.com/2013/10/how-to-configure-the-linux-oom-killer/)
- 6.高性能网站架构设计之缓存篇(5)- Redis 集群(上) [http://www.cnblogs.com/zhaoguihua/p/redis-005.html](http://www.cnblogs.com/zhaoguihua/p/redis-005.html)
- 7.高性能网站架构设计之缓存篇(6)- Redis 集群(中) [http://www.cnblogs.com/zhaoguihua/p/redis-006.html](http://www.cnblogs.com/zhaoguihua/p/redis-006.html)
Redis Studing