Redis Studing

一.Redis的安装和使用

1、什么 Redis

REmote DIctionary Server,简称 Redis,可以直接理解为远程字典服务,是一个类似于Memcached的Key-Value存储系统。相比Memcached,它支持更丰富的数据结构,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型),并提供了数据持久化机制,在某些场景下,你完全可以把它当做非关系型数据库来使用。它是一个高性能的存储系统,能支持超过 100K+ 每秒的读写频率。同时还支持消息的发布/订阅,从而让你在构建高性能消息队列系统时多了另一种选择。

PS:使用Memcached,让我感触颇深的是Object Size的问题,由于SQL未作优化直接映射对象,导致缓存对象大于1MB,Memcached就抛了异常。而Redis默认缓存对象512MB,最大支持1GB。至少在缓存对象时,可以有更大的伸缩空间了! 此外,是数据类型。Memcached比较简单,而Redis可以支持更多复杂的数据类型。

2、安装

Redis装起来,实在是过于简单,让我几乎“无从下手”。因为连configure文件都不需要,你只需要做个makemake 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 :主从配置,在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 SETCONFIG 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 01slave 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 就把这份数据发送给 slaveslave 先把数据保存到磁盘,然后把它加载到内存中,master 接着就把收集的数据修改指令一行一行的发给 slaveslave 接收到之后重新执行该指令,这样就实现了数据同步。

slave 在与 master 失去联系后,自动的重新连接。如果 master 收到了多个 slave 的同步请求,它会执行单个后台保存来为所有的 slave 服务。

一旦 masterslave 在失去联系并重新连接上,总是会重新进行一次完整的同步。不过从 redis 2.8 开始,只是部分重新同步也是可以的。具体请大家参考官方文档。

三.主从备份

在从服务器上执行下列命令:

$备份

redis-cli save

$关闭redis服务器

redis-cli shutdown

然后,拷贝数据目录下的rdb文件。

参考