Java架构之Redis企业级开发与运维从入门

介绍
Redis:Remote DIctionary Server(远程字典服务器),是彻底开源免费的,用C语言编写的,遵照BSD协议,
是一个高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一,也被人们称为数据结构服务器。html

优势:java

(1)Redis支持数据的持久化,能够将内存中的数据保持在磁盘中,重启的时候能够再次加载进行使用redis

(2)Redis不只仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储算法

(3)Redis支持数据的备份,即master-slave模式的数据备份数据库

相关应用:centos

(1)内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务数组

(2)取最新N个数据的操做,如:能够将最新的10条评论的ID放在Redis的List集合里面安全

(3)模拟相似于HttpSession这种须要设定过时时间的功能服务器

(4)发布、订阅消息系统数据结构

(5)定时器、计数器

Redis的安装
下载
下载[redis-5.0.0][http://download.redis.io/releases/redis-5.0.0.tar.gz]放到centos系统中

安装
解压redis压缩文件,在解压目录执行make && make install

安装目录查看
查看默认安装目录:usr/local/bin

redis-benchmark:性能测试工具

redis-check-aof:修复有问题的AOF文件

redis-check-dump:修复有问题的dump.rdb文件

redis-cli:客户端,操做入口

redis-sentinel:redis集群使用

redis-server:Redis服务器启动命令

启动服务
(1)修改redis.conf文件将里面的daemonize no 改为 yes,让服务在后台启动

(2)将默认的redis.conf拷贝到本身定义好的一个路径下,好比/myconf

(3)经过命令redis-server /myconf启动服务

(4)redis-cli 链接测试

服务关闭
单实例关闭:redis-cli shutdown

多实例关闭,指定端口关闭:redis-cli -p 6379 shutdown

Redis服务
服务核心
单进程

单进程模型来处理客户端的请求。对读写等事件的响应是经过对epoll函数的包装来作到的。Redis的实际处理速度彻底依靠主进程的执行效率。

epoll是Linux内核为处理大批量文件描述符而做了改进的epoll,是Linux下多路复用IO接口select/poll的加强版本,它能显著提升程序在大量并发链接中只有少许活跃的状况下的系统CPU利用率。

服务端操做
默认16个数据库,相似数组下表从零开始,初始默认使用零号库。

设置数据库的数量,默认数据库为0,可使用SELECT 命令在链接上指定数据库id databases 16。

默认端口是6379

数据库操做

select命令切换数据库:select [index]

dbsize查看当前数据库的key的数量

flushdb:清空当前库

flushall:清空所有库

统一密码管理,16个库都是一样密码,要么都OK要么一个也链接不上

Redis索引都是从零开始

更多操做

http://redisdoc.com/

Redis数据类型
Redis的五大数据类型:

(1)string(字符串)
(2)hash(哈希,相似java里的Map)
(3)list(列表)
(4)set(集合)
(5)zset(sorted set:有序集合)

Redis 键(key)
key值查看:

(1)keys * 显示全部的key
(2)exists key 判断某个key是否存在
(3)move key db 将当前库的key移至db库
(4)expire key 秒钟 为给定的key设置过时时间
(5)ttl key 查看还有多少秒过时,-1表示永不过时,-2表示已过时
(6)type key 查看你的key是什么类型
(7)del key删除key
更多操做:http://redisdoc.com/database/index.html

Redis字符串(String)
string是redis最基本的类型,一个key对应一个value。

string类型是二进制安全的。意思是redis的string能够包含任何数据。好比jpg图片或者序列化的对象 。

string类型是Redis最基本的数据类型,一个redis中字符串value最多能够是512M。

相关操做:
set/get/del/append/strlen 设置/获取/删除/追加/字符串长度
Incr/decr/incrby/decrby 数字操做,必定要是数字才能进行加减
getrange/setrange 返回指定范围内的字符串/指定范围字符串替换
setex(set with expire)键秒值/setnx(set if not exist)
mset/mget/msetnx
getset(先get再set)

全部字符串类型操做:http://redisdoc.com/string/index.html

Redis列表(List)
Redis 列表是简单的字符串列表,按照插入顺序排序。能够添加一个元素导列表的头部(左边)或者尾部(右边)。它的底层实际是个链表。

相关操做:
lpush/rpush/lrange 插入表头/插入表尾/区间值返回
lpop/rpop 移除并返回表头元素/移除并返回表尾元素
lindex 按照索引下标得到元素(从上到下)
llen 长度获取
lrem 移除
ltrim key 开始index 结束index,截取指定范围的值后再赋值给key
rpoplpush 源列表 目的列表
lset key index value
linsert key before/after 值1 值2

全部列表操做:http://redisdoc.com/list/index.html

Redis集合(Set)
Redis的Set是string类型的无序集合。它是经过HashTable实现实现的。

相关操做:

sadd/smembers/sismember
scard,获取集合里面的元素个数
srem key value 删除集合中元素
srandmember key 某个整数(随机出几个数)
spop key 随机出栈
smove key1 key2 在key1里某个值 做用是将key1里的某个值赋给key2
差集:sdiff
交集:sinter
并集:sunion

全部Set集合操做:http://redisdoc.com/set/index.html

Redis哈希(Hash)
相关操做:

hset/hget/hmset/hmget/hgetall/hdel
hlen
hexists key 在key里面的某个值的key
hkeys/hvals
hincrby/hincrbyfloat
hsetnx

全部Hash操做:http://redisdoc.com/hash/index.html

Redis有序集合Zset(sorted set)
相关操做:

zadd/zrange
zrangebyscore key 开始score 结束score
zrem key 某score下对应的value值,做用是删除元素
zcard/zcount key score区间/zrank key values值,做用是得到下标值/zscore key 对应值,得到分数
zrevrank key values值,做用是逆序得到下标值
zrevrange
zrevrangebyscore key 结束score 开始score

全部操做:http://redisdoc.com/sorted_set/index.html

redis配置文件
https://www.cnblogs.com/zhang-ke/p/5981108.html

#配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit
#单位大小写不敏感

###################################GENERAL通用###################################
#包含其它配置文件
include /path/to/local.conf
#是否在后台执行,yes:后台运行;no:不是后台运行
daemonize yes
#redis的进程文件
pidfile /var/run/redis_6379.pid
#指定 redis 只接收来自于该 IP 地址的请求,若是不进行设置,那么将处理全部请求
bind 127.0.0.1
#redis监听的端口号。
port 6379
# 此参数为设置客户端空闲超过timeout,服务端会断开链接,为0则服务端不会主动断开链接,不能小于0。
timeout 0
#指定了服务端日志的级别。级别包括:debug(不少信息,方便开发、测试),verbose(许多有用的信息,可是没有debug级别信息多),notice(适当的日志级别,适合生产环境),warn(只有很是重要的信息)
loglevel notice
#指定了记录日志的文件。空字符串的话,日志会打印到标准输出设备。后台运行的redis标准输出是/dev/null。
logfile /var/log/redis/redis-server.log
#数据库的数量,默认使用的数据库是DB 0。能够经过”SELECT “命令选择一个db
databases 16
#设置tcp的backlog,backlog实际上是一个链接队列,backlog队列总和=未完成三次握手队列 + 已经完成三次握手队列。在高并发环境下你须要一个高backlog值来避免客户端链接问题。注意Linux内核会将这个值减少到/proc/sys/net/core/somaxconn的值,因此须要确认增大somaxconn和tcp_max_syn_backlog两个值来达到想要的效果
tcp-backlog 511
#单位为秒,若是设置为0,则不会进行Keepalive检测,建议设置成60 
tcp-keepalive 60
#是否把日志输出到syslog中
syslog-enabled
#指定syslog里的日志标志
syslog-ident
#指定syslog设备,值能够是USER或LOCAL0-LOCAL7
syslog-facility

###################################SNAPSHOTTING快照###################################
# RDB是整个内存的压缩过的Snapshot
# 快照配置
# 注释掉“save”这一行配置项就可让保存数据库功能失效
# 设置sedis进行数据库镜像的频率。
# 900秒(15分钟)内至少1个key值改变(则进行数据库保存--持久化) 
# 300秒(5分钟)内至少10个key值改变(则进行数据库保存--持久化) 
# 60秒(1分钟)内至少10000个key值改变(则进行数据库保存--持久化)
# 若是想禁用RDB持久化的策略,只要不设置任何save指令,或者给save传入一个空字符串参数也能够
save 900 1
save 300 10
save 60 10000

#当RDB持久化出现错误后,是否依然进行继续进行工做,yes:不能进行工做,no:能够继续进行工做,能够经过info中的rdb_last_bgsave_status了解RDB持久化是否有错误
stop-writes-on-bgsave-error yes
# 对于存储到磁盘中的快照,能够设置是否进行压缩存储。若是是的话,redis会采用LZF算法进行压缩。若是你不想消耗CPU来进行压缩的话,能够设置为关闭此功能
rdbcompression yes
#是否校验rdb文件。从rdb格式的第五个版本开始,在rdb文件的末尾会带上CRC64的校验和。这跟有利于文件的容错性,可是在保存rdb文件的时候,会有大概10%的性能损耗,因此若是你追求高性能,能够关闭该配置。
rdbchecksum yes
#rdb文件的名称
dbfilename dump.rdb
#数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录
dir /var/lib/redis

################################### LIMITS ####################################

# 设置能连上redis的最大客户端链接数量。默认是10000个客户端链接。因为redis不区分链接是客户端链接仍是内部打开文件或者和slave链接等,因此maxclients最小建议设置到32。若是超过了maxclients,redis会给新的链接发送’max number of clients reached’,并关闭链接。
# maxclients 10000
#redis配置的最大内存容量。当内存满了,须要配合maxmemory-policy策略进行处理。注意slave的输出缓冲区是不计算在maxmemory内的。因此为了防止主机内存使用完,建议设置的maxmemory须要更小一些。
# maxmemory <bytes>

#内存容量超过maxmemory后的处理策略。
#volatile-lru:利用LRU算法移除设置过过时时间的key。
#volatile-random:随机移除设置过过时时间的key。
#volatile-ttl:移除即将过时的key,根据最近过时时间来删除(辅以TTL)
#allkeys-lru:利用LRU算法移除任何key。
#allkeys-random:随机移除任何key。
#noeviction:不移除任何key,只是返回一个写错误。
#上面的这些驱逐策略,若是redis没有合适的key驱逐,对于写命令,仍是会返回错误。redis将再也不接收写请求,只接收get请求。写命令包括:set setnx setex append incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby getset mset msetnx exec sort。
# maxmemory-policy noeviction

#lru检测的样本数。使用lru或者ttl淘汰算法,从须要淘汰的列表中随机选择sample个key,选出闲置时间最长的key移除。
# maxmemory-samples 5

############################## APPEND ONLY MODE ###############################
#默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了。可是redis若是中途宕机,会致使可能有几分钟的数据丢失,根据save来策略进行持久化,Append Only File是另外一种持久化方式,能够提供更好的持久化特性。Redis会把每次写入的数据在接收后都写入 appendonly.aof 文件,每次启动时Redis都会先把这个文件的数据读入内存里,先忽略RDB文件。
appendonly yes
#aof文件名
appendfilename "appendonly.aof"

#aof持久化策略的配置
#no表示不执行fsync,由操做系统保证数据同步到磁盘,速度最快。
#always表示每次写入都执行fsync,以保证数据同步到磁盘。
#everysec表示每秒执行一次fsync,可能会致使丢失这1s数据。
appendfsync everysec
# 重写时是否能够运用Appendfsync,用默认no便可,保证数据安全性。
no-appendfsync-on-rewrite no

#设置容许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的状况还要重写
auto-aof-rewrite-min-size 64mb
#aof自动重写配置。当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增加到必定大小的时候Redis可以调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上第二天志重写获得AOF文件大小的二倍(设置为100)时,自动启动新的日志重写过程。
auto-aof-rewrite-percentage 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
redis持久化
RDB
原理
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。

Redis会单首创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程当中,主进程是不进行任何IO操做的,这就确保了极高的性能若是须要进行大规模数据的恢复,且对于数据恢复的完整性不是很是敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。

fork的做用是复制一个与当前进程同样的进程。新进程的全部数据(变量、环境变量、程序计数器等)数值都和原进程一致,可是是一个全新的进程,并做为原进程的子进程。

保存方案
rdb 保存的是dump.rdb文件。

save命令只管保存,其它无论,所有阻塞。

Redis会在后台异步进行快照操做,快照同时还能够响应客户端请求。能够经过lastsave命令获取最后一次成功执行快照的时间。

RDB持久化恢复方案
将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务便可,CONFIG GET dir获取目录,指定配置文件的dir 路径,dir默认当前目录。

优点与劣势
优点:

(1)适合大规模的数据恢复

(2)对数据完整性和一致性要求不高

劣势:

(1)在必定间隔时间作一次备份,因此若是redis意外down掉的话,就会丢失最后一次快照后的全部修改。

(2)fork的时候,内存中的数据被克隆了一份,大体2倍的膨胀性须要考虑

动态中止保存方法:

动态全部中止RDB保存规则的方法:redis-cli config set save “”

AOF(Append Only File)
原理
以日志的形式来记录每一个写操做,将Redis执行过的全部写指令记录下来(读操做不记录),只许追加文件但不能够改写文件,redis启动之初会读取该文件从新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工做。

配置文件
Aof保存的是appendonly.aof文件,能够在redis.conf修改文件名。

修改默认的appendonly no,改成yes

appendonly yes
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
#always表示每次写入都执行fsync,以保证数据同步到磁盘。
# appendfsync always
#everysec表示每秒执行一次fsync,可能会致使丢失这1s数据。
appendfsync everysec
#no表示不执行fsync,由操做系统保证数据同步到磁盘,速度最快。
# appendfsync no
1
2
3
4
5
6
7
8
9
AOF启动/修复/恢复
将有数据的aof文件复制一份保存到对应目录(config get dir),而后重启redis进行加载而恢复数据。

若是AOP文件存在数据异常,可使用redis-check-aof --fix进行修复。

rewrite
AOF采用文件追加方式,文件会愈来愈大为避免出现此种状况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留能够恢复数据的最小指令集.可使用命令bgrewriteaof

重写原理:

AOF文件持续增加而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操做,并无读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点相似。

触发机制:

Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。

AOP优点与劣势
优点:

(1)每修改同步:appendfsync always 同步持久化 每次发生数据变动会被当即记录到磁盘 性能较差但数据完整性比较好.
(2)每秒同步:appendfsync everysec 异步操做,每秒记录 若是一秒内宕机,有数据丢失,但数据丢失小。
(3)不一样步:appendfsync no 从不一样步,性能好。

劣势:

(1)相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
(2)aof运行效率要慢于rdb,每秒同步策略效率较好,不一样步效率和rdb相同

持久化方案总结
若是只但愿数据在服务器运行的时候存在,能够不使用任何持久化方式.

方案对比:

RDB持久化方式可以在指定的时间间隔能对你的数据进行快照存储。
AOF持久化方式记录每次对服务器写的操做,当服务器重启的时候会从新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操做到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大

同时开启两种持久化方式:

在这种状况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,由于在一般状况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
RDB的数据不实时,同时使用二者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
做者建议不要,由于RDB更适合用于备份数据库(AOF在不断变化很差备份),快速重启,并且不会有AOF可能潜在的bug,留着做为一个万一的手段。

Redis事务
简介
能够一次执行多个命令,本质是一组命令的集合。一个事务中的全部命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不准加塞。一个队列中,一次性、顺序性、排他性的执行一系列命令。

操做流程
(1)开启:以MULTI开始一个事务
(2)入队:将多个命令入队到事务中,接到这些命令并不会当即执行,而是放到等待执行的事务队列里面
(3)执行:由EXEC命令触发事务

事务
基本命令
http://redisdoc.com/transaction/index.html

DISCARD:取消事务,放弃执行事务块内的全部命令。
EXEC:执行全部事务块内的命令
MULTI :标记一个事务块的开始。
WATCH :监视一个(或多个) key ,若是在事务执行以前这个(或这些) key 被其余命令所改动,那么事务将被打断。
UNWATCH:取消 WATCH 命令对全部 key 的监视。

执行状况
基本操做
(1)所有正常执行,即事务中的命令所有执行成功

(2)放弃事务,即放弃在事务中的全部操做

(3)所有执行失败(事务中队列中的执行操做,有语法错误)。

(4)部分执行(若队列中命令无语法错误,则所有执行,执行过程报错的不影响其它命令,例如:一个字符串k1=“vvsdf”,执行操做 incr k1不会报语法错误,但会报执行错误)

watch监控
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,因此每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了不少这种锁机制,好比行锁,表锁等,读锁,写锁等,都是在作操做以前先上锁。

乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,因此不会上锁,可是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可使用版本号等机制。乐观锁适用于多读的应用类型,这样能够提升吞吐量,

乐观锁策略:提交版本必须大于记录当前版本才能执行更新。

Watch原理:

Watch指令,相似乐观锁,事务提交时,若是Key的值已被别的客户端改变,好比某个list已被别的客户端push/pop过了,整个事务队列都不会被执行。
经过WATCH命令在事务执行以前监控了多个Keys,假若在WATCH以后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败。

Watch执行流程:

(1)WATCH 监视一个(或多个) key

(2)MULTI标记一个事务块的开始

(3)执行操做

(4)状况一:监控了key,若是key被修改了,后面一个事务的执行失效, WATCH 取消对全部 key 的监视

状况二:执行exec 把MULTI队列中的命令所有执行完成,而且WATCH监控锁也会被取消掉。

特性
单独的隔离操做:事务中的全部命令都会序列化、按顺序地执行。事务在执行的过程当中,不会被其余客户端发送来的命令请求所打断。

没有隔离级别的概念:队列中的命令没有提交以前都不会实际的被执行,由于事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题。

不保证原子性:redis同一个事务中若是有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

Redis的发布订阅
简介
进程间的一种消息通讯模式:发送者(pub)发送消息,订阅者(sub)接收消息。

Redis 客户端能够订阅任意数量的频道。

订阅发布消息图
例:频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系图

 

当有新消息经过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

 

操做命令
http://redisdoc.com/pubsub/index.html

PSUBSCRIBE pattern [pattern …] 订阅一个或多个符合给定模式的频道。
PUBSUB subcommand [argument [argument …]] 查看订阅与发布系统状态。
PUBLISH channel message 将信息发送到指定的频道。
PUNSUBSCRIBE [pattern [pattern …]] 退订全部给定模式的频道。
SUBSCRIBE channel [channel …] 订阅给定的一个或多个频道的信息。
UNSUBSCRIBE [channel [channel …]] 指退订给定的频道。

操做实例:

在redis客服端建立订阅频道channel1:

127.0.0.1:6379[1]> SUBSCRIBE channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "hello channel1" //收到的第一条消息
1) "message"
2) "channel1"
3) "come here" //收到的第二条消息
1
2
3
4
5
6
7
8
9
10
11
从新开启一个redis客服端,而后在同一个频道 redisChat 发布消息,订阅者就能接收到消息。

127.0.0.1:6379[1]> PUBLISH channel1 "hello channel1"
(integer) 1
127.0.0.1:6379[1]> PUBLISH channel1 "come here"
(integer) 1
1
2
3
4
Redis的复制(Master/Slave)
简介
Redis支持简单的主从(master-slave)复制功能,当主Redis服务器更新数据时能将数据自动同步到从Redis服务器 ,Master以写为主,Slave以读为主。

主要用途
读写分离、容灾恢复

配置搭建
原则
配从(库)不配主(库),从库是不能进行修改操做的。

模式
http://redisdoc.com/replication/slaveof.html

每次与master断开以后,都须要从新链接,除非你配置进redis.conf文件

例若有3台redis服务器,分别是A、B、C。

一主二从
以A为主(master)库,B、C为从库。

在B、C上分别执行slaveof 127.0.0.1 6379,而后A库上全部的更新操做都能在B、C中存在。

A:

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=70,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=70,lag=1
.....
127.0.0.1:6379> set k1 v1
OK
1
2
3
4
5
6
7
8
9
B:

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
...
127.0.0.1:6380> get k1
"v1"
1
2
3
4
5
6
7
8
9
10
C:

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
...
127.0.0.1:6381> get k1
"v1"
1
2
3
4
5
6
7
8
9
10
薪火相传
上一个Slave能够是下一个slave的Master,Slave一样能够接收其余slaves的链接和同步请求,那么该slave做为了链条中下一个的master,能够有效减轻master的写压力。
中途变动转向:会清除以前的数据,从新创建拷贝最新的。
A(master)为主库
B做为A库的slave,做为C库的master
C为B库的slave

A:

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=3290,lag=0
127.0.0.1:6379> set k2 v2
OK
1
2
3
4
5
6
7
B:

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
...
slave0:ip=127.0.0.1,port=6381,state=online,offset=3262,lag=1
127.0.0.1:6380> get k2
"v2
1
2
3
4
5
6
7
8
9
10
11
C:

127.0.0.1:6381> slaveof 127.0.0.1 6380
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
...
127.0.0.1:6381> get k2
"v2"
1
2
3
4
5
6
7
8
9
10
反客为主
使当前数据库中止与其余数据库的同步,转成主数据库。

SLAVEOF no one

哨兵模式(sentinel)
介绍
反客为主的自动版,可以后台监控主机是否故障,若是故障了根据投票数自动将从库转换为主库。
例如:当原有的master挂了,剩下的slave会投票选举出新的master,若是以前的master库从新启动了,则会成为同步新选举出来的master的slave从库。
一组sentinel能同时监控多个Master。

步骤
(1)在redis.conf对应目录下新建sentinel.conf文件。而且配置哨兵:
sentinel monitor 自定义被监控redis库 127.0.0.1 6379 1
上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机。
例如:监控A库
sentinel.conf:

sentinel monitor host6379 127.0.0.1 6379 1
1
(2)启动哨兵

redis-sentinel sentinel.conf 
1
复制原理
slave启动成功链接到master后会发送一个sync命令
Master接到命令启动后台的存盘进程,同时收集全部接收到的用于修改数据集命令,
在后台进程执行完毕以后,master将传送整个数据文件到slave,以完成一次彻底同步
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master继续将新的全部收集到的修改命令依次传给slave,完成同步
可是只要是从新链接master,一次彻底同步(全量复制)将被自动执行

例:当slave第一次连上master会全量复制,后面进行的是增量复制

复制缺点
复制延时:

因为全部的写操做都是先在Master上操做,而后同步更新到Slave上,因此从Master同步到Slave机器有必定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增长也会使这个问题更加严重。

Jedis
基础
Jedis是 Redis 官方首选的 Java 客户端开发包。

开发须要的jar包:commons-pool-1.6.jar、jedis-2.1.0.jar

maven:

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
经常使用操做
链接测试
Jedis jedis = new Jedis("192.168.10.206",6379);
System.out.println(jedis.ping());
1
2
基本类型操做
Jedis jedis = new Jedis("192.168.10.206",6379);
//获取 keys * 结果
Set<String> keys = jedis.keys("*");
for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
System.out.println(key);
}
//查看k2是否存在
System.out.println("jedis.exists====>"+jedis.exists("k2"));
//查看k1还有多少秒过时
System.out.println(jedis.ttl("k1"));
//查看k1值
System.out.println(jedis.get("k1"));
//设置k4=k4_redis
jedis.set("k4","k4_redis");
//多个字符串同时设置值
jedis.mset("str1","v1","str2","v2","str3","v3");
//获取多个字符串值
System.out.println(jedis.mget("str1","str2","str3"));

//list设置值 及获取
jedis.lpush("mylist","v1","v2","v3","v4","v5");
List<String> list = jedis.lrange("mylist",0,-1);
for (String element : list) {
System.out.println(element);
}

//set设置值 及获取
jedis.sadd("orders","jd001");
jedis.sadd("orders","jd002");
jedis.sadd("orders","jd003");
Set<String> set1 = jedis.smembers("orders");
for (Iterator iterator = set1.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
System.out.println(string);
}
//set移除值
jedis.srem("orders","jd002");
//hash设值及获取
jedis.hset("hash1","userName","lisi");
System.out.println(jedis.hget("hash1","userName"));

//zset添加值
jedis.zadd("zset01",90d,"v4");
//zset获取所有值
Set<String> s1 = jedis.zrange("zset01",0,-1);
for (Iterator iterator = s1.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
System.out.println(string);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
事务控制
Jedis jedis = new Jedis("127.0.0.1", 6379);
int balance;// 可用余额
int amtToSubtract = 10;// 实刷额度
//watch监控
jedis.watch("balance");
balance = Integer.parseInt(jedis.get("balance"));
if (balance < amtToSubtract) {
//取消watch监控
jedis.unwatch();
System.out.println("modify");
} else {
//开启事务
Transaction transaction = jedis.multi();
transaction.decrBy("balance", amtToSubtract);
transaction.incrBy("debt", amtToSubtract);
//执行并提交事务 watch监控也会取消
transaction.exec();
System.out.println("success");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
主从复制
Jedis jedis_M = new Jedis("127.0.0.1",6379);
Jedis jedis_S = new Jedis("127.0.0.1",6380);
jedis_S.slaveof("127.0.0.1",6379);
1
2
3
Jedis池
获取Jedis实例须要从JedisPool中获取,用完Jedis实例须要返还给JedisPool,若是Jedis在使用过程当中出错,则也须要还给JedisPool

public class JedisPoolUtil {
private static volatile JedisPool jedisPool = null;

private JedisPoolUtil(){}

public static JedisPool getJedisPoolInstance(){
if(null == jedisPool){
synchronized (JedisPoolUtil.class){
if(null == jedisPool){
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxActive(1000);
poolConfig.setMaxIdle(32);
poolConfig.setMaxWait(100*1000);
poolConfig.setTestOnBorrow(true);

jedisPool = new JedisPool(poolConfig,"127.0.0.1",6379);
}
}
}
return jedisPool;
}

public static void release(JedisPool jedisPool,Jedis jedis){
if(null != jedis){
jedisPool.returnResourceObject(jedis);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
JedisPoolConfig配置
JedisPool的配置参数大部分是由JedisPoolConfig的对应项来赋值的。
maxActive:控制一个pool可分配多少个jedis实例,经过pool.getResource()来获取;若是赋值为-1,则表示不限制;若是pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted。
maxIdle:控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
whenExhaustedAction:表示当pool中的jedis实例都被allocated完时,pool要采起的操做;默认有三种。
WHEN_EXHAUSTED_FAIL --> 表示无jedis实例时,直接抛出NoSuchElementException;
WHEN_EXHAUSTED_BLOCK --> 则表示阻塞住,或者达到maxWait时抛出JedisConnectionException;
WHEN_EXHAUSTED_GROW --> 则表示新建一个jedis实例,也就说设置的maxActive无用;
maxWait:表示当borrow一个jedis实例时,最大的等待时间,若是超过等待时间,则直接抛JedisConnectionException;
testOnBorrow:得到一个jedis实例的时候是否检查链接可用性(ping());若是为true,则获得的jedis实例均是可用的;


testOnReturn:return 一个jedis实例给pool时,是否检查链接可用性(ping());


testWhileIdle:若是为true,表示有一个idle object evitor线程对idle object进行扫描,若是validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;


timeBetweenEvictionRunsMillis:表示idle object evitor两次扫描之间要sleep的毫秒数;


numTestsPerEvictionRun:表示idle object evitor每次扫描的最多的对象数;


minEvictableIdleTimeMillis:表示一个对象至少停留在idle状态的最短期,而后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;


softMinEvictableIdleTimeMillis:在minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。若是为-1,evicted不会根据idle time驱逐任何对象。若是minEvictableIdleTimeMillis>0,则此项设置无心义,且只有在timeBetweenEvictionRunsMillis大于0时才有意义;


lifo:borrowObject返回对象时,是采用DEFAULT_LIFO(last in first out,即相似cache的最频繁使用队列),若是为False,则表示FIFO队列;

其中JedisPoolConfig对一些参数的默认设置以下:testWhileIdle=trueminEvictableIdleTimeMills=60000timeBetweenEvictionRunsMillis=30000numTestsPerEvictionRun=-112345678910111213141516171819202122232425262728293031323334353637相关代码:https://download.csdn.net/download/liu289747235/10972716

相关文章
相关标签/搜索