一.Redis的安装和使用
1、什么 Redis
REmote DIctionary Server,简称 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 敖丙,《吊打面试官》系列-Redis双写一致性、并发竞争、线程模型,感谢~
2、安装
Redis装起来,实在是过于简单,让我几乎“无从下手”。因为连configure
文件都不需要,你只需要做个make
和make install
就好。我在这里下载的是redis-3.0.1版.
如果报找不到gc++
, 执行以下命令即可。
yum -y install make gcc gcc-c++ ncurses-devel
yum -y install zlib zlib-devel
如果报
error: jemalloc/jemalloc.h: No such file or directory
使用以下命令即可编译通过
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/
目录下,然后执行命令
redis-server /etc/redis/redis.conf
4、测试
通过客户端命令redis-cli
访问Redis
set name sherlock
get name
进行数据测试:
redis-benchmark -l
5、关闭
可通过客户端命令redis-cli完成Redis关闭操作,当然,也可以通过 kill 命令来关闭服务。
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和 CONFIG GET命令用编程方式查询并设置配置。
二.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
- 2.Redis实战(系列)http://blog.csdn.net/it_man/article/details/9730559
- 3.高性能网站架构设计之缓存篇(1)- Redis的安装与使用 http://www.cnblogs.com/zhaoguihua/p/redis-001.html
- 4.linux环境 redis overcommit_memory 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/
- 6.高性能网站架构设计之缓存篇(5)- Redis 集群(上) http://www.cnblogs.com/zhaoguihua/p/redis-005.html
- 7.高性能网站架构设计之缓存篇(6)- Redis 集群(中) http://www.cnblogs.com/zhaoguihua/p/redis-006.html
评论区