redis缓存服务器

redis 缓存数据库

1.1 redis 的简单介绍

    Redis是一个开源(BSD许可)的,ANSI C语言编写的,高级键值(key-value)缓存和支持永久存储NoSql数据库产品。
    内存中的数据结构存储系统,他可以用作数据库、缓存和消息中间件。
    它支持多种数据类型。字符串(string)、字典(hash)、列表(list)、集合(set)、有序集合(sorted set)
    运行于大多数POSIX系统,如Linux、*BSD、OS X等。
    基本配合后端数据库使用,存放的只是用户当前频繁调去的数据
    作者: Salvatore Sanfilippo

1.2 redis的功能特点

    1)高速读写(因为是在内存上的数据库)
    2)数据类型丰富
    3)支持持久化(把内存上的数据写到磁盘上)
    4)多种内存分配及回收策略
    5)支持多事物
    6)消息队列、消息订阅(先订阅后发送)
    7)支持高可用
    8)支持分布式分片集群

1.3 Memcache、redis和Tair的对比

企业缓存数据库解决方案对比

1.3.1 Memcached:

优点:高性能读写,单一的数据类型,支持客户端式分布式集群,一致性hash多核结构,多线程读写性能高
缺点:无持久化,节点故障可能出现缓存穿透,分布式需要客户端实现,跨机房数据同步困难,架构扩容复杂度高

1.3.2 Redis:

优点:高性能读写,多数据类型支持,数据持久化,高可用架构,支持自定义虚拟内存,支持分布式分片集群,单线程读写性能极高
缺点:多线程读写较Mencached慢

1.3.3 Tair:淘宝使用

优点:高性能读写,支持三种存储引擎(ddb/rdb/ldb),支持高可用,支持分布式分片集群,支撑了几乎所有淘宝业务的缓存。
缺点:单机情况下,读写性能较上两种较慢

1.4 Redis的应用场景

1)数据高速缓存
2)Web会话缓存(session cache)
3)排行榜应用(有序集合、sorted set)
4)消息队列
5)发布订阅

1.5 Redis的安装配置

1.5.1 下载redis的源码包

wget http://download.redis.io/releases/redis-3.2.9.tar.gz

1.5.2 移动到/server/application/目录下,这个目录随意自己

[root@shoufu ~]# mkdir -p /server/application
[root@shoufu ~]# cd /server/application/
[root@shoufu application]# wget http://download.redis.io/releases/redis-3.2.9.tar.gz
[root@shoufu application]# ls
redis-3.2.9.tar.gz

1.5.3 解压/安装

[root@shoufu application]# tar  xf redis-3.2.9.tar.gz 
[root@shoufu application]# rm -rf redis-3.2.9.tar.gz 
#建立一个软连接,方便以后软件升级
[root@shoufu application]# ln -s /server/application/redis-3.2.9/ /server/application/redis
#因为redis官方已经编译过源码包了,所以我们不需要执行./configure了,直接安装即可
[root@shoufu redis]# make && make install
..............
    INSTALL install
make[1]: Leaving directory `/server/application/redis-3.2.9/src'
#正在离开这个目录,安装完成

1.5.4 把redis的命令存在的路径写到PATH的环境变量中去,能更好的执行命令

[root@shoufu src]# tail -2 /root/.bash_profile 
export PATH=/server/application/redis/src:$PATH

1.6 配置Redis,并启动

1.6.1 未指定配置文件启动

[root@shoufu src]# redis-server &       #在后台启动
[1] 5530
[root@shoufu src]# 5530:C 13 Aug 11:40:24.774 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf

#你当前没有指定配置文件,以默认的配置文件启动,如果你想指定配置文件你可以redis-server 文件所在位置

1.6.2 配置redis的配置文件

先创建一个配置文件所在的位置:
mkdir -p /server/application/redis/conf.d/
vim /server/application/redis/conf.d/6379.conf
#守护进程方式启动,后台运行
daemonize yes   
#端口号
port 6379
#日志文件
logfile /var/log/redis.log
#RDB持久化文件名*
dbfilename dump.rdb
#RDB持久化文件位置
dir /server/application/redis/data/6379

1.6.3 指定配置文件启动

[root@shoufu redis]# redis-server /server/application/redis/conf.d/6379.conf 
[root@shoufu redis]# netstat  -ntalp | grep redis
tcp 0   0 0.0.0.0:6379                0.0.0.0:*                   LISTEN      5556/redis-server * 
tcp 0   0 :::6379                     :::*                        LISTEN      5556/redis-server *

1.6.4 连接测试

[root@shoufu redis]# redis-cli 
127.0.0.1:6379> set name test   #简单的写入以恶搞字符串
OK
127.0.0.1:6379> get name
"test"
127.0.0.1:6379> exit
#127.0.0.1:6379   从那个地址的连接进来,

1.6.5 关闭redis

[root@shoufu redis]# redis-cli shutdown
[root@shoufu redis]# netstat  -ntalp | grep redis
[root@shoufu redis]#

1.6.6 Redis的安全配置

在配置文件里面加上
#监听的地址,要加上127.0.0.1,否则从本地不能登录
bind 10.0.0.200 127.0.0.1
#取消保护模式,是否只允许本地登录
protected no
#增加密码
requirepass {password}

1.6.6.1 不设置上述的内容,先远程登录测试

[root@shoufu redis]# redis-cli -h 10.0.0.200
10.0.0.200:6379> get name
(error) DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface.(redis默认只允许本地登录,远程登录被屏蔽). If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password.(设定一个监听地址或者一个密码认证,配合使用) NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.

1.6.6.2 在配置文件里面配置安全

[root@shoufu redis]# tail -3 /server/application/redis/conf.d/6379.conf 
protected-mode no
bind 10.0.0.200 127.0.0.1
requirepass 123123
#关闭redis
[root@shoufu redis]# redis-cli shutdown
#重新指定配置文件启动
[root@shoufu redis]# !redis-server
redis-server /server/application/redis/conf.d/6379.conf 
[root@shoufu redis]# netstat -ntalp | grep redis

1.6.6.3 连接测试

#通过远程连接的方式测试连接
[root@shoufu redis]# redis-cli -h 10.0.0.200
10.0.0.200:6379> get name
#虽然连接进来,但是获取数据时提示我们需要认证,
(error) NOAUTH Authentication required.
#在redis内部进行认证,推荐使用
10.0.0.200:6379> auth 123123
OK
10.0.0.200:6379> get name
(nil)
10.0.0.200:6379> exit
#在命令行提供认证
[root@shoufu redis]# redis-cli -h 10.0.0.200 -a 123123
10.0.0.200:6379> get name
(nil)

1.6.7 Redis数据的持久化

1.6.7.1 RDB持久化

可以在指定的时间间隔生成数据集的时间点快照(point-in-time-snapshot);相当于在一定时间内把当前redis缓存数据库里面的数据拍个照片,存放到磁盘上的永久化文件上(dbfilename),性能比AOF持久化高,突然宕机可能会照成少量的数据丢失

1.6.7.2 RDB持久的优点

1)RDB是一种表示某个即时点的Redis数据的紧凑文件。RDB文件适合用于备份。例如,你可能想要每小时归档最近24小时的RDB文件,每天保存近30天的RDB快照。这允许你很容易的恢复不同版本的数据集以容灾。
2)RDB非常适合于灾难恢复,作为一个紧凑的单一文件,可以被传输到远程的数据中心。
3)RDB最大化了Redis的性能,因为Redis父进程持久化时唯一需要做的是启动(fork)一个子进程,由子进程完成所有剩余工作。父进程实例不需要执行像磁盘IO这样的操作。
4)RDB在重启保存了大数据集的实例时比AOF要快。

1.6.7.3 RDB的缺点

1)当你需要在Redis停止工作(例如停电)时最小化数据丢失,RDB可能不太好。你可以配置不同的保存点(save point)来保存RDB文件(例如,至少5分钟和对数据集100次写之后,但是你可以有多个保存点)。然而,你通常每隔5分钟或更久创建一个RDB快照,所以一旦Redis因为任何原因没有正确关闭而停止工作,你就得做好最近几分钟数据丢失的准备了。
2)RDB需要经常调用fork()子进程来持久化到磁盘。如果数据集很大的话,fork()比较耗时,结果就是,当数据集非常大并且CPU性能不够强大的话,Redis会停止服务客户端几毫秒甚至一秒。AOF也需要fork(),但是你可以调整多久频率重写日志而不会有损(trade-off)持久性(durability)。

1.6.7.4 AOF持久化

记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF文件中命令全部以Redis协议的格式来保存,新命令会被追加到文件末尾。因为每执行一条写操作,都要对磁盘上写一次,所以性能比较低,安全性最好,实时记录

1.6.7.5 AOF持久化的优点

1)使用AOF Redis会更具有可持久性(durable):你可以有很多不同的fsync策略:没有fsync,每秒fsync,每次请求时fsync。使用默认的每秒fsync策略,写性能也仍然很不错(fsync是由后台线程完成的,主线程继续努力地执行写请求),即便你也就仅仅只损失一秒钟的写数据。
2)AOF日志是一个追加文件,所以不需要定位,在断电时也没有损坏问题。即使由于某种原因文件末尾是一个写到一半的命令(磁盘满或者其他原因),redis-check-aof工具也可以很轻易的修复。
3)当AOF文件变得很大时,Redis会自动在后台进行重写。重写是绝对安全的,因为Redis继续往旧的文件中追加,使用创建当前数据集所需的最小操作集合来创建一个全新的文件,一旦第二个文件创建完毕,Redis就会切换这两个文件,并开始往新文件追加。
4)AOF文件里面包含一个接一个的操作,以易于理解和解析的格式存储。你也可以轻易的导出一个AOF文件。例如,即使你不小心错误地使用FLUSHALL命令清空一切,如果此时并没有执行重写,你仍然可以保存你的数据集,你只要停止服务器,删除最后一条命令,然后重启Redis就可以。

1.6.7.6 AOF的缺点

1)对同样的数据集,AOF文件通常要大于等价的RDB文件。
2)AOF可能比RDB慢,这取决于准确的fsync策略。通常fsync设置为每秒一次的话性能仍然很高,如果关闭fsync,即使在很高的负载下也和RDB一样的快。不过,即使在很大的写负载情况下,RDB还是能提供能好的最大延迟保证。
3)在过去,我们经历了一些针对特殊命令(例如,像BRPOPLPUSH这样的阻塞命令)的罕见bug,导致在数据加载时无法恢复到保存时的样子。这些bug很罕见,我们也在测试套件中进行了测试,自动随机创造复杂的数据集,然后加载它们以检查一切是否正常,但是,这类bug几乎不可能出现在RDB持久化中。为了说得更清楚一点:Redis AOF是通过递增地更新一个已经存在的状态,像MySQL或者MongoDB一样,而RDB快照是一次又一次地从头开始创造一切,概念上更健壮。但是,1)要注意Redis每次重写AOF时都是以当前数据集中的真实数据从头开始,相对于一直追加的AOF文件(或者一次重写读取老的AOF文件而不是读内存中的数据)对bug的免疫力更强。2)我们还没有收到一份用户在真实世界中检测到崩溃的报告。

1.6.7.7 RDB和AOF的选择:

一般来说,如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户单独使用AOF,但是我们并不鼓励这样,因为时常进行RDB快照非常方便于数据库备份,启动速度也较之快,还避免了AOF引擎的bug。

注意:基于这些原因,将来我们可能会统一AOF和RDB为一种单一的持久化模型(长远计划)。 下面的部分将介绍两种持久化模型等多的细节。

1.6.7.8 快照的工作方式

        默认情况下,Redis保存数据集快照到磁盘,名为dump.rdb的二进制文件。你可以设置让Redis在N秒内至少有M次数据集改动时保存数据集,或者你也可以手动调用SAVE或者BGSAVE命令。

例如,这个配置会让Redis在每个60秒内至少有1000次键改动时自动转储数据集到磁盘:
#配置文件里面加上
save 60 1000

1.6.7.9 Redis配置

#60S内有1000次改写就拍照
save 60 1000 
高级配置
stop-writes-on-bgsave-error yes
rdbcompression yes 
rdbchecksum yes
dbfilename dump.rdb
dir ./ 
以上配置分别表示:
后台备份进程出错时,主进程停不停止写入? 主进程不停止容易造成数据不一致 
导出的rdb文件是否压缩 如果rdb的大小很大的话建议这么做
导入rbd恢复时数据时,要不要检验rdb的完整性 验证版本是不是一致
导出来的rdb文件名
rdb的放置路径

1.6.7.10 AOF持久化配置

#基本配置
appendonly yes/no
appendfsync always
appendfsync everysec
appendfsync no
配置分别表示:
是否打开aof日志功能
每1个命令,都立即同步到aof 
每秒写1次
写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof.
#高级配置
no-appendfsync-on-rewrite yes/no
auto-aof-rewrite-percentage 100 
auto-aof-rewrite-min-size 64mb
配置分别表示:
正在导出rdb快照的过程中,要不要停止同步aof
aof文件大小比起上次重写时的大小,增长率100%时重写,缺点:业务开始的时候,会重复重写多次。
aof文件,至少超过64M时,重写

1.7 Redis管理

1.7.1 全局key操作

删 
flushdb             清空当前选择的数据库 
del mykey mykey2        删除了两个 Keys 
改 
move mysetkey 1         将当前数据库中的 mysetkey 键移入到 ID 为 1 的数据库中 
rename mykey mykey1     将 mykey 改名为 mykey1 
renamenx oldkey newkey  如果 newkey 已经存在,则无效 
expire mykey 100        将该键的超时设置为 100 秒
persist mykey       将该 Key 的超时去掉,变成持久化的键 
查 
keys my*            获取当前数据库中所有以my开头的key 
exists mykey        若不存在,返回0;存在返回1 
select 0            打开 ID 为 0 的数据库 
ttl mykey           查看存货时间还剩下多少秒
type mykey          返回mykey对应的值的类型 
randomkey           返回数据库中的任意键

1.7.2 string(字符串)

增
set mykey "test"            为键设置新值,并覆盖原有值
getset mycounter 0              设置值,取值同时进行
setex mykey 10 "hello"          设置指定 Key 的过期时间为10秒,在存活时间可以获取value
setnx mykey "hello"             若该键不存在,则为键设置新值
mset key3  "zyx"  key4 "xyz"    批量设置键
删
del mykey                   删除已有键
改
append mykey "hello"            若该键并不存在,返回当前 Value 的长度
                            该键已经存在,返回追加后 Value的长度
incr mykey                  值增加1,若该key不存在,创建key,初始值设为0,增加后结果为1
decrby  mykey  5            值减少5
setrange mykey 20 dd            把第21和22个字节,替换为dd, 超过value长度,自动补0
查  
exists mykey                    判断该键是否存在,存在返回 1,否则返回0
get mykey                   获取Key对应的value
strlen mykey                获取指定 Key 的字符长度
ttl mykey                   查看一下指定 Key 的剩余存活时间(秒数)
getrange mykey 1 20             获取第2到第20个字节,若20超过value长度,则截取第2个和后面所有的
mget key3 key4                  批量获取键

1.7.3 hash(字典)

增
hset myhash field1 "s"    
若字段field1不存在,创建该键及与其关联的Hashes, Hashes中,key为field1 ,并设value为s ,若存在会覆盖原value
hsetnx myhash field1 s    
若字段field1不存在,创建该键及与其关联的Hashes, Hashes中,key为field1 ,并设value为s, 若字段field1存在,则无效
hmset myhash field1 "hello" field2 "world       一次性设置多个字段
删
hdel myhash field1                      删除 myhash 键中字段名为 field1 的字段
del myhash                          删除键
改  
hincrby myhash field 1                  给field的值加1
查
hget myhash field1                      获取键值为 myhash,字段为 field1 的值
hlen myhash                         获取myhash键的字段数量
hexists myhash field1                   判断 myhash 键中是否存在字段名为 field1 的字段
hmget myhash field1 field2 field3           一次性获取多个字段
hgetall myhash                          返回 myhash 键的所有字段及其值
hkeys myhash                        获取myhash 键中所有字段的名字
hvals myhash                        获取 myhash 键中所有字段的值

1.7.4 list(列表)

增 
lpush mykey a b             若key不存在,创建该键及与其关联的List,依次插入a ,b, 若List类型的key存在,则插入value中
lpushx mykey2 e             若key不存在,此命令无效, 若key存在,则插入value中
linsert mykey before a a1   在 a 的前面插入新元素 a1
linsert mykey after e e2    在e 的后面插入新元素 e2
rpush mykey a b             在链表尾部先插入b,在插入a
rpushx mykey e              若key存在,在尾部插入e, 若key不存在,则无效
rpoplpush mykey mykey2      将mykey的尾部元素弹出,再插入到mykey2 的头部(原子性的操作)
删
del mykey               删除已有键 
lrem mykey 2 a              从头部开始找,按先后顺序,值为a的元素,删除数量为2个,若存在第3个,则不删除
ltrim mykey 0 2             从头开始,索引为0,1,2的3个元素,其余全部删除
改
lset mykey 1 e              从头开始, 将索引为1的元素值,设置为新值 e,若索引越界,则返回错误信息
rpoplpush mykey mykey       将 mykey 中的尾部元素移到其头部
查
lrange mykey 0 -1       取链表中的全部元素,其中0表示第一个元素,-1表示最后一个元素。
lrange mykey 0 2            从头开始,取索引为0,1,2的元素
lrange mykey 0 0            从头开始,取第一个元素,从第0个开始,到第0个结束
lpop mykey                  获取头部元素,并且弹出头部元素,出栈
lindex mykey 6              从头开始,获取索引为6的元素 若下标越界,则返回nil 

1.7.5 set(集合)

增
sadd myset a b c  
若key不存在,创建该键及与其关联的set,依次插入a ,b,若key存在,则插入value中,若a 在myset中已经存在,则插入了 d 和 e 两个新成员。
删
spop myset              尾部的b被移出,事实上b并不是之前插入的第一个或最后一个成员
srem myset a d f        若f不存在, 移出 a、d ,并返回2
改
smove myset myset2 a        将a从 myset 移到 myset2,
查
sismember myset a           判断 a 是否已经存在,返回值为 1 表示存在。
smembers myset          查看set中的内容
scard myset             获取Set 集合中元素的数量
srandmember myset       随机的返回某一成员
sdiff myset1 myset2 myset3      1和2得到一个结果,拿这个集合和3比较,获得每个独有的值
sdiffstore diffkey myset myset2 myset3      3个集和比较,获取独有的元素,并存入diffkey 关联的Set中
sinter myset myset2 myset3              获得3个集合中都有的元素
sinterstore interkey myset myset2 myset3  把交集存入interkey 关联的Set中
sunion myset myset2 myset3              获取3个集合中的成员的并集
sunionstore unionkey myset myset2 myset3  把并集存入unionkey 关联的Set中

1.7.6 sorted set(有序集合)

增
zadd myzset 2 "two" 3 "three"           添加两个分数分别是 2 和 3 的两个成员
删
zrem myzset one two                 删除多个成员变量,返回删除的数量
改
zincrby myzset 2 one                将成员 one 的分数增加 2,并返回该成员更新后的分数
查 
zrange myzset 0 -1 WITHSCORES       返回所有成员和分数,不加WITHSCORES,只返回成员
zrank myzset one                获取成员one在Sorted-Set中的位置索引值。0表示第一个位置
zcard myzset                        获取 myzset 键中成员的数量
zcount myzset 1 2                   获取分数满足表达式 1 <= score <= 2 的成员的数量
zscore myzset three                 获取成员 three 的分数
zrangebyscore myzset  1 2               获取分数满足表达式 1 < score <= 2 的成员
#-inf 表示第一个成员,+inf最后一个成员
#limit限制关键字
#2  3  是索引号
zrangebyscore myzset -inf +inf limit 2 3  返回索引是2和3的成员
zremrangebyscore myzset 1 2         删除分数 1<= score <= 2 的成员,并返回实际删除的数量
zremrangebyrank myzset 0 1              删除位置索引满足表达式 0 <= rank <= 1 的成员
zrevrange myzset 0 -1 WITHSCORES        按位置索引从高到低,获取所有成员和分数
#原始成员:位置索引从小到大
      one  0  
      two  1
#执行顺序:把索引反转
      位置索引:从大到小
      one 1
      two 0
#输出结果: two  
       one
zrevrange myzset 1 3                获取位置索引,为1,2,3的成员
#相反的顺序:从高到低的顺序
zrevrangebyscore myzset 3 0             获取分数 3>=score>=0的成员并以相反的顺序输出
zrevrangebyscore myzset 4 0 limit 1 2    获取索引是1和2的成员,并反转位置索引

1.7.7 消息模式

Redis发布消息通常有两种模式: • 队列模式(queuing) • 发布-订阅模式(publish-subscribe) 任务队列:顾名思义,就是“传递消息的队列”。与任务队列进行交互的实体有两类,一类是生产者(producer),另一类则是消费者(consumer)。生产者将需要处理的任务放入任务队列中,而消费者则不断地从任务独立中读入任务信息并执行。 任务队列的好处: • 松耦合。 生产者和消费者只需按照约定的任务描述格式,进行编写代码。 • 易于扩展。 多消费者模式下,消费者可以分布在多个不同的服务器中,由此降低单台服务器的负载。

1.7.8 Redis中事物锁机制

1.7.8.1 悲观锁

12306买票,我选择了票,不管有没有付钱这张票都是我的,我把它锁上,别人就看不到了

1.7.8.2 乐观锁

类似于商品秒杀,你选择之后,别人还是能看到,被人还是能付钱,谁先付钱是谁的

1.8 redis的主从复制

• 使用异步复制。 • 一个主服务器可以有多个从服务器。 • 从服务器也可以有自己的从服务器。 • 复制功能不会阻塞主服务器。 • 可以通过复制功能来让主服务器免于执行持久化操作,由从服务器去执行持久化操作即可。

1.8.1 以下是关于 Redis 复制功能的几个重要方面:

• Redis 使用异步复制。 从 Redis 2.8 开始, 从服务器会以每秒一次的频率向主服务器报告复制流(replication stream)的处理进度。 • 一个主服务器可以有多个从服务器。 • 不仅主服务器可以有从服务器, 从服务器也可以有自己的从服务器, 多个从服务器之间可以构成一个图状结构。 • 复制功能不会阻塞主服务器: 即使有一个或多个从服务器正在进行初次同步, 主服务器也可以继续处理命令请求。 • 复制功能也不会阻塞从服务器: 只要在 redis.conf 文件中进行了相应的设置, 即使从服务器正在进行初次同步, 服务器也可以使用旧版本的数据集来处理命令查询。 • 不过, 在从服务器删除旧版本数据集并载入新版本数据集的那段时间内, 连接请求会被阻塞。 • 你还可以配置从服务器, 让它在与主服务器之间的连接断开时, 向客户端发送一个错误。 • 复制功能可以单纯地用于数据冗余(data redundancy), 也可以通过让多个从服务器处理只读命令请求来提升扩展性(scalability): 比如说, 繁重的 SORT 命令可以交给附属节点去运行。 • 可以通过复制功能来让主服务器免于执行持久化操作: 只要关闭主服务器的持久化功能, 然后由从服务器去执行持久化操作即可。

1.8.2 关闭主服务器持久化,复制功能数据更安全

• 当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。 否则的话,由于延迟等问题,部署的服务应该要避免自动拉起。 • 为了帮助理解主服务器关闭持久化时自动拉起的危险性,参考一下以下会导致主从服务器数据全部丢失的例子: • 1. 假设节点A为主服务器,并且关闭了持久化。 并且节点B和节点C从节点A复制数据 • 2. 节点A崩溃,然后由自动拉起服务重启了节点A. 由于节点A的持久化被关闭了,所以重启之后没有任何数据 • 3. 节点B和节点C将从节点A复制数据,但是A的数据是空的, 于是就把自身保存的数据副本删除。 • 在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用Sentinel来实现Redis的高可用性,也是非常危险的。 因为主服务器可能拉起得非常快,以至于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。 • 无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动拉起。

1.8.3 主从复制的原理

1. 从服务器向主服务器发送 SYNC 命令。
2. 接到 SYNC 命令的主服务器会调用BGSAVE 命令,创建一个 RDB 文件,并使用缓冲区记录接下来执行的所有写命令。
3. 当主服务器执行完 BGSAVE 命令时,它会向从服务器发送 RDB 文件,而从服务器则会接收并载入这个文件。
4. 主服务器将缓冲区储存的所有写命令发送给从服务器执行。

1.8.4 命令传播

1.8.5 复制的一致性问题

• 在读写分离环境下,客户端向主服务器发送写命令 SET n 10086,主服务器在执行这个写命令之后,向客户端返回回复,并将这个写命令传播给从服务器。 • 接到回复的客户端继续向从服务器发送读命令 GET n ,并且因为网络状态的原因,客户端的 GET命令比主服务器传播的 SET 命令更快到达了从服务器。 • 因为从服务器键 n 的值还未被更新,所以客户端在从服务器读取到的将是一个错误(过期)的 n值。

1.8.1.6 主从复制实战

环境准备: 三台服务器,10.0.0.200(主) 10.0.0.201(备) 10.0.0.202(备),都使用6379这个端口 三台服务器上分别下载安装redis服务

在redis_200 主服务器上
mkdir -p /server/application 
cd !$
wget http://download.redis.io/releases/redis-3.2.9.tar.gz
tar xf redis-3.2.9.tar.gz 
rm -rf redis-3.2.9.tar.gz 
cd /server/application/redis-3.2.9/
make && make install 
ln -s /server/application/redis-3.2.9/ /server/application/redis
echo 'export PATH=/server/application/redis/src:$PATH' >>/root/.bash_profile
mkdir -p /server/application/redis/conf.d/
cat >>/server/application/redis/conf.d/200_6379.conf <<EOF
bind 127.0.0.1 10.0.0.200
port 6379
daemonize yes
pidfile /server/application/redis/log/redis.pid
loglevel notice
logfile "/server/application/redis/log/redis.log"
dbfilename dump.rdb
dir /server/application/redis/data
requirepass 123123
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
slowlog-log-slower-than 10000
slowlog-max-len 128
protected-mode no
EOF
mkdir -p /server/application/redis/data
mkdir -p /server/application/redis/log
redis-server /server/application/redis/conf.d/200_6379.conf
在redis_201从服务器上
mkdir -p /server/application 
cd !$
wget http://download.redis.io/releases/redis-3.2.9.tar.gz
tar xf redis-3.2.9.tar.gz 
rm -rf redis-3.2.9.tar.gz 
cd /server/application/redis-3.2.9/
make && make install 
ln -s /server/application/redis-3.2.9/ /server/application/redis
echo 'export PATH=/server/application/redis/src:$PATH' >>/root/.bash_profile
mkdir -p /server/application/redis/conf.d/
cat >>/server/application/redis/conf.d/201_6379.conf <<EOF
bind 127.0.0.1 10.0.0.201
port 6379
daemonize yes
pidfile /server/application/redis/log/redis.pid
loglevel notice
logfile "/server/application/redis/log/redis.log"
dbfilename dump.rdb
dir /server/application/redis/data
requirepass 123123
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
slowlog-log-slower-than 10000
slowlog-max-len 128
protected-mode no
#在从服务器上配置主服务器的地址和端口
slaveof 10.0.0.200 6379
EOF
mkdir -p /server/application/redis/data
mkdir -p /server/application/redis/log
redis-server /server/application/redis/conf.d/201_6379.conf
在redis_202从服务器上
mkdir -p /server/application 
cd !$
wget http://download.redis.io/releases/redis-3.2.9.tar.gz
tar xf redis-3.2.9.tar.gz 
rm -rf redis-3.2.9.tar.gz 
cd /server/application/redis-3.2.9/
make && make install 
ln -s /server/application/redis-3.2.9/ /server/application/redis
echo 'export PATH=/server/application/redis/src:$PATH' >>/root/.bash_profile
mkdir -p /server/application/redis/conf.d/
cat >>/server/application/redis/conf.d/202_6379.conf <<EOF
bind 127.0.0.1 10.0.0.202
port 6379
daemonize yes
pidfile /server/application/redis/log/redis.pid
loglevel notice
logfile "/server/application/redis/log/redis.log"
dbfilename dump.rdb
dir /server/application/redis/data
requirepass 123123
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
slowlog-log-slower-than 10000
slowlog-max-len 128
protected-mode no
#在从服务器上配置主服务器的地址和端口
slaveof 10.0.0.200 6379
EOF
mkdir -p /server/application/redis/data
mkdir -p /server/application/redis/log
redis-server /server/application/redis/conf.d/202_6379.conf

1.8.1.7 验证:

在两台从服务器上执行命令 redis-cli -h 10.0.0.201 -a 123123 10.0.0.201:6379> info replication

Replication

role:slave
master_host:10.0.0.200
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1534187875
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

[root@redis_202 /]# redis-cli -a 123123 -h 10.0.0.202
10.0.0.202:6379> SLAVEOF 10.0.0.200 6379
OK
10.0.0.202:6379> info replication
# Replication
role:slave
master_host:10.0.0.200
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1534187890
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

sentinel的配置

mkdir -p /server/application 
cd !$
wget http://download.redis.io/releases/redis-3.2.9.tar.gz
tar xf redis-3.2.9.tar.gz 
rm -rf redis-3.2.9.tar.gz 
cd /server/application/redis-3.2.9/
make && make install 
ln -s /server/application/redis-3.2.9/ /server/application/redis
echo 'export PATH=/server/application/redis/src:$PATH' >>/root/.bash_profile
mkdir -p /server/application/redis/conf.d/
cat >>/server/application/redis/conf.d/sentinel.conf <<EOF
port 6380
daemonize yes
dir "/sentinel"
sentinel monitor mymaster 10.0.0.200 6379 1         #1是几个sentinel(哨兵)认为你宕机了,达到这个值就切换切换
sentinel down-after-milliseconds mymaster 3000      #多久联系不上就认为主库宕机了,时间毫秒
sentinel config-epoch mymaster 0
EOF
mkdir -p /sentinel
redis-server /server/application/redis/conf.d/sentinel.conf  --sentinel

未完待续

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏zingpLiu

Django快速入门

Django 是用 Python 写的一个自由和开放源码 web 应用程序框架。 web框架是一套组件,能帮助你更快、更容易地开发web站点。当你开始构建一个w...

1153
来自专栏扎心了老铁

redis性能调优笔记(can not get Resource from jedis pool和jedis connect time out)

对这段时间redis性能调优做一个记录。 1、单进程单线程 redis是单进程单线程实现的,如果你没有特殊的配置,redis内部默认是FIFO排队,即你对red...

7436
来自专栏领域驱动设计DDD实战进阶

微服务实战(八):落地微服务架构到直销系统(服务高可用性)

在微服务架构风格的系统中,如果单个微服务垮掉或地址不可访问,虽然对系统的影响是有限的,但我们也必须采取一定的手段来保证每个微服务尽量可用;并且在大并发的情况下,...

2373
来自专栏向治洪

xmpp即时通讯三

6.1 概述       XMPP包含一个认证流的方法,此方法依靠一个简单认证与安全层(SASL)协议[SASL]的XMPP-specific profile...

2347
来自专栏GreenLeaves

WCF系列教程之WCF服务宿主与WCF服务部署

本文参考自http://www.cnblogs.com/wangweimutou/p/4377062.html,纯属读书笔记,加深记忆。 一、简介 任何一个程序...

2348
来自专栏编程一生

Redis和消息队列使用实战

2563
来自专栏博客园迁移

redis见解

http://blog.csdn.net/zhiguozhu/article/details/50517527 Redis 原生session与redis中的s...

1911
来自专栏上善若水

004-IntelliJ IDEA导出Java 可执行Jar包

保证自己的Java代码是没有问题的,在IDEA里面是可以正常运行的,然后,按下面步骤:

2322
来自专栏Esofar 开发日记

[译]RabbitMQ教程C#版 - 远程过程调用(RPC)

但是如果我们想要运行一个在远程计算机上的函数并等待其结果呢?这将是另外一回事了。这种模式通常被称为 远程过程调用 或 RPC 。

1750
来自专栏Esofar 开发日记

[译]RabbitMQ教程C#版 - 远程过程调用(RPC)

但是如果我们想要运行一个在远程计算机上的函数并等待其结果呢?这将是另外一回事了。这种模式通常被称为 远程过程调用 或 RPC 。

1092

扫码关注云+社区

领取腾讯云代金券