Redis的使用
Redis的使用
制作人:全心全意
Redis简介
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
Redis的数据操作都是在内存中进行的,Redis也会将数据写入磁盘,但仅仅是为了下次访问时,可以访问到数据(冗余)
官方站点:https://redis.io/
默认端口号:6379
Rdis与Memcached的优势对比
Redis:
丰富的存储形式
Strings(字符串),Hashs(哈希),Lists(列表),Sets(集合),Sorted Sets(有序集合),Bitmaps,HyperLogLogs等
内建replication及cluster(自己支持复制和集群)
就地更新(in-place update)操作(直接在内存中更新)
支持持久化(磁盘),避免雪崩效应
Memcached:
多线程,善用多核CPU,更少的阻塞操作
更少的内存开销
更小的内存分配压力
可能有更少的内存碎片
数据库的分类
RDBMS(关系型数据库)
Oracle,DB2,postgreSQL,MySQL,SQL Server,......
NoSQL(非关系型数据库)
Cassandra,HBase,Memcached,MongoDB,Redis,......
NoSQL的分类:
key-value NoSQL(键值存储)
Memcached,Redis,......
Colume family NoSQL(列式存储)
Cassandra,HBase,......
Documen NoSQL(文档存储)
MongoDB,......
Graph NoSQL(图式存储)
Neo4j,......
NewSQL(对各种新的可扩展/高性能数据库的简称,这类数据库不仅具有NoSQL对海量数据的存储管理能力,还保持了传统数据库支持ACID和SQL等特性)
Aerospike,FoundationDB,RethinkDB,......
Redis组件的介绍
redis-server:redis的服务端
[/path/redis.conf]:可选,redis的配置文件
--port:服务端口号
--slaveof:指定从服务器
redis-cli:redis的客户端
-h:指定连接redis的地址
-p:指定端口号
redis-benchmark:redis性能压力测试工具
redis-check-dump & redis-check-aof:两个检查redis持久化是否出现错误
Redis的操纵命令
切换命名空间
#Redis默认可以建立16个库(命名空间),每个库中的key是不可以重复的 #命名空间的取值为0-15,默认在0 select 1
数据类型
Strings(@string)
添加数据
用法:set key value [EX seconds] [NX|XX]
EX:指定过期时间,单位为秒
NX:如果指定的key不存在才进行添加
XX:如果指定的key存在才进行添加
#添加name的值,针对相同的key使用可以更改值 127.0.0.1:6379> set name zhangsan OK #获取name的值 127.0.0.1:6379> get name "zhangsan" #针对指定的key追加内容 127.0.0.1:6379> append name list (integer) 12 127.0.0.1:6379> get name "zhangsanlist" #获取指定key的值的字符串长度 127.0.0.1:6379> strlen name (integer) 12
Integers
127.0.0.1:6379> set count 0 OK #对指定key的值+1 127.0.0.1:6379> incr count (integer) 1 #对指定key的值-1 127.0.0.1:6379> decr count (integer) 0
#判断指定的key是否存在 127.0.0.1:6379> exists name (integer) 1 127.0.0.1:6379> exists name1 (integer) 0
Lists(@list)
#创建列表,向列表插入值即可创建列表 #从列表左侧开始插入值 127.0.0.1:6379> lpush ll nihao (integer) 1 127.0.0.1:6379> lpush ll word (integer) 2 #从列表右侧开始插入值 127.0.0.1:6379> rpush ll my (integer) 3 #获取指定列表指定索引位置的值 127.0.0.1:6379> LINDEX ll 0 "word" #修改指定索引位置的值 127.0.0.1:6379> lset ll 2 wode OK 127.0.0.1:6379> lindex ll 2 "wode" #从列表右侧弹出值,lpop从左侧弹 127.0.0.1:6379> rpop ll "wode" #获取列表中值的个数 127.0.0.1:6379> llen ll (integer) 2
Sets(@set)
#创建集合 127.0.0.1:6379> sadd s1 zhangsan list (integer) 2 127.0.0.1:6379> sadd s2 list wangwu (integer) 2 #求多个集合的交集 127.0.0.1:6379> sinter s1 s2 1) "list" #求多个集合的并集,会自动去重 127.0.0.1:6379> SUNION s1 s2 1) "wangwu" 2) "zhangsan" 3) "list" #获取集合中值的个数 127.0.0.1:6379> SCARD s1 (integer) 2 #弹出集合中的一个值 127.0.0.1:6379> spop s1 "zhangsan" #判断指定元素是否在指定集合中 127.0.0.1:6379> SISMEMBER s1 zhangsan (integer) 0 127.0.0.1:6379> SISMEMBER s1 list (integer) 1
Sorted Sets(@sorted_set)
#创建有序集合 127.0.0.1:6379> zadd z1 1 zhao 2 qian 3 sun 4 li (integer) 4 #获取有序集合元素个数 127.0.0.1:6379> ZCARD z1 (integer) 4 #获取指定元素对应的索引号 127.0.0.1:6379> ZRANK z1 li (integer) 3 #获取指定元素对应的位置(创建时指定的位置) 127.0.0.1:6379> ZSCORE z1 qian "2" #获取指定索引范围的元素 127.0.0.1:6379> ZRANGE z1 0 3 1) "zhao" 2) "qian" 3) "sun" 4) "li"
Hashs(@hash)
#创建hash #多次使用hset可以添加新的元素 127.0.0.1:6379> hset h1 a zhao (integer) 1 127.0.0.1:6379> hset h1 b qian (integer) 1 #获取指定hash中指定key的元素 127.0.0.1:6379> hget h1 a "zhao" 127.0.0.1:6379> hget h1 b "qian" #删除hash中指定key的元素 127.0.0.1:6379> HDEL h1 b (integer) 1 #获取hash中所有的key 127.0.0.1:6379> hkeys h1 1) "a" #获取hash中所有的值 127.0.0.1:6379> HVALS h1 1) "zhao" #获取hash中键值对的个数 127.0.0.1:6379> HLEN h1 (integer) 1
通用命令
事务:redis中通过MULTI,EXEC,WATCH等命令实现事务功能。(redis中的事务:将多个命令请求打包成一个操作,而后一次性的、按顺序的执行多个命令,并且在事务执行期间服务器不会中断事务,而去执行其它客户端的请求,它会将事务中的所有命令执行完毕,再去处理其它请求)。redis不支持回滚操作,如果10条命令中,第5条有错误,1-4条不会回滚,6-10条继续运行。redis事务队列会检查命令的语法问题,错误的语法命令无法加入队列。
#开始事务 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set ip 192.168.1.1 QUEUED #不返回,命令加入队列 127.0.0.1:6379> get ip QUEUED 127.0.0.1:6379> set port 8080 QUEUED 127.0.0.1:6379> get port QUEUED #提交事务,返回所有结果 127.0.0.1:6379> exec 1) OK 2) "192.168.1.1" 3) OK 4) "8080"
WATCH:乐观锁(在EXEC命令执行之前,用于监视指定数量的键,如果监视的任何一个键的数据发生了改变,则服务器拒绝执行事务)
127.0.0.1:6379> WATCH ip OK #WATCH之后,exec之前,ip的值发生了改变 127.0.0.1:6379> set ip 125 OK 127.0.0.1:6379> get ip "125" #在事务内是可以修改的,因为exec执行后才执行命令 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set ip 128 QUEUED 127.0.0.1:6379> get ip QUEUED 127.0.0.1:6379> exec (nil) #ip的值发生改变,服务器拒绝执行事务
连接(Connection)相关的命令
AUTH:用于密码认证
PING:用于测试服务器是否在线,在线返回PONG
ECHO:回显命令
SELECT:切换所在的库
QUIT:退出命令
服务(Server)相关的命令
CLIENT GETNAME:获取当前客户端的连接名
CLIENT KILL:关闭指定信息对应的连接
用法:CLIENT KILL [ip:port]
CLIENT SETNAME:设置客户端的连接名
INFO:获取当前系统的配置信息
用法:INFO [某部分的配置信息(如:cpu)]
CONFIG GET:获取指定参数的配置信息(配置文件)
CONFIG RESETSTAT:重置系统的配置信息
CONFIG SET:redis的大多数配置可以使用该命令在运行时修改,修改后在临时生效
用法:CONFIG SET 配置参数 配置值
CONFIG REWRITE:将CONFIG SET修改的配置写入配置文件,永久生效
DBSIZE:统计当前库中所有键的数量
FLUSHDB:清空当前库
FLUSHALL:清空所有库
MONITOR:实时监控接收到的请求
SHUTDOWN:将所有数据从内存同步到磁盘后,安全关闭
用法:SHUTDOWN [NOSAVE|SAVE]
NOSAVE:关闭时不做安全同步
SAVE:关闭时做安全同步
TIME:返回当前服务时间
持久化相关:
BGSAVE
SAVE
LASTSAVE:获取最后一次将数据保存在磁盘上的时间戳
主从相关:
SLAVEOF
Redis启用密码认证
#启用requirepass [root@localhost ~]# vi /etc/redis.conf requirepass 123456 [root@localhost ~]# systemctl restart redis #=====测试========= [root@localhost ~]# redis-cli 127.0.0.1:6379> select 1 (error) NOAUTH Authentication required. 127.0.0.1:6379> AUTH 123456 #使用密码进行认证 OK 127.0.0.1:6379> select 1 OK 127.0.0.1:6379[1]>
Redis的发布与订阅
频道:消息队列
SUBSCRIBE:订阅一个或多个频道
用法:SUBSCRIBE 频道名 ...
SUBSCRIBE:模式订阅频道(可使用正则表达式匹配频道)
PUBLISH:向频道发布消息
UNSUBSCRIBE:退订此前订阅的频道
#订阅news和logs频道 127.0.0.1:6379> SUBSCRIBE news logs Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "news" 3) (integer) 1 1) "subscribe" 2) "logs" 3) (integer) 2 #使用另一个客户端 127.0.0.1:6379> PUBLISH news 123 (integer) 1 127.0.0.1:6379> PUBLISH logs 123 (integer) 1 #订阅的消息队列上显示内容如下 1) "message" 2) "news" 3) "123" 1) "message" 2) "logs" 3) "123"
Redis的持久化
Redis持久化的两种模式:
RDB:snapshot,存下的数据时二进制格式,默认的模式。按事先定制的策略,周期性的将数据保存至磁盘,数据文件默认为dump.rdb(缺点:每次都相当于完整备份,数据量大的话会进行大量的IO操作,在间隔期的操作数据会丢失)
客户端可以通过save或bgsave命令启动RGB保存机制
save命令(同步)在主线程中保存快照,在执行过程中,所有客户端请求都将被阻塞
bgsave命令(异步)执行后自动在后台使用子进程实现保存,客户端请求不会被阻塞
AOF:Append Only File,将redis的每一个写操作命令以附加的方式附加到指定文件的尾部(缺点:文件越来越大)redis能够合并重写(只留最新的写操作)AOF持久化文件,可以使用BGREWRITEAOF命令来实现。当redis重启后,可通过重新执行文件中的命令在内存重建数据库。
BGREWRITEAOF:AOF文件的重写,redis使用类似快照类似的方式,不会读取正在使用的AOF文件,而通过将内存中的数据以命令的方式保存到临时文件中,最后替换原来的AOF文件
AOF重写过程:
redis主进程通过fork创建子进程
子进程根据redis内存中的数据创建数据库重建命令序列于临时文件中
父进程继续接收客户端请求,并把这些请求操作继续追加至原来的AOF文件,额外新的请求还会被放置在一个缓存队列中
子进程重写完成,通知父进程,父进程将缓存队列中的命令写到临时文件中
父进程将临时文件替换老的AOF文件
RGB配置说明:
SAVE 900 1 #在过去的900秒钟有一个键发生了变化,保存快照
SAVE 300 10 #在过去的300秒钟有10个键发生了变化,保存快照
SAVE 60 10000 #在过去的60秒钟有10000个键发生了变化,保存快照
#-----------------------------------------------
SAVE "" #表示关闭RGB持久化
stop-writes-on-bgsave-error:在进行快照备份时,一旦发生错误,是否停止写操作
rdbcompression:RGB文件是否进行压缩(压缩会使用cpu,不压缩占用较大的磁盘)
rdbchecksum:是否对RGB文件做校验码检测(启动时对RGB文件进行检查是否产生了错误,会导致启动时间变长)
dbfilename:指定RGB文件的文件名
dir:RGB文件保存位置
AOF配置说明:
appendonly:是否启动AOF持久化,默认是关闭的
appendfilename:AOF文件的存放位置
appendfsync:
always:redis收到写操作后,立即追加到AOF文件中
everysec:每秒钟往AOF文件中追加一次,推荐使用
no:redis不主动发起追加操作,由系统内核自行决定写入,不建议使用
no-appendfsync-on-rewrite:在执行期间,新的写操作写入AOF文件,是否等待磁盘同步
auto-aof-rewrite-percentage:当前AOF文件大小已经是上次重写的2倍大小,自动重写AOF文件(默认值为100,表示增长率达到100%)
auto-aof-rewrite-min-size:指定重写AOF文件数据量的最小值,默认为64mb。(当达到2倍大小,没达到最小值也不会进行重写)
注:两种持久化模式都开启,BGSAVE和BGREWRITEAOF不会同时执行(执行完当前执行的命令,才会执行另一条);恢复数据时,redis优先使用AOF持久化
Redis的主从复制
特点:
一个Master可以有多个Slave
支持链式复制(Slave还可以做master)
Master以非阻塞方式同步数据到Slave
#建议将slave设置为只读,不要进行写操作
bug:使用主从同步时,配置文件中监听地址bind最好设置在同一网段,不要使用127.0.0.1或都使用0.0.0.0
配置说明:
slaveof:作为从服务器指定主服务器的地址和端口
slave-serve-stale-data:当主服务器连不上,有用户来获取数据,是否将数据返回给用户
slave-read-only:是否将从服务器设置为只读,不允许进行写操作
slave-priority:指定slave的优先级,优先级高的优先同步
min-slaves-to-write:指定从服务器最少的工作数量,若少于该数量,主服务器禁止写操作
min-slaves-max-lag :指定从服务器和主服务的延迟(同步时间差)不能超过的秒数,超过该时间,主服务器禁止写操作
masterauth:若主服务器使用密码认证,指定主服务的密码
示例:
#使用交互工具 127.0.0.1:6379> SLAVEOF 172.16.1.145 6379 #========================= #编辑配置文件 vi /etc/redis.conf slaveof 172.16.1.145 6379
Redis的高可用
sentinel:使用流言协议判断主服务器是否出现故障,使用投票协议决定是否进行故障迁移以及选择哪一个服务器成为新的主服务器
用于管理多个redis实现高可用(HA)
监控主从的运行状态(仅监控主服务器,从服务器通过主服务器获取)
通知用户工作的主节点
自动故障转移
启动命令:
redis-sentinel 配置文件
redis-server 配置文件 --sentinel
配置文件为sentinel专用的配置文件
服务启动流程
服务器自身初始化,运行redis-server中专用于sentinel功能的代码
初始化sentinel的状态,根据给定的配置文件,初始化监控的master服务器列表
创建连向master的连接
专用配置文件:/etc/redis-sentinel.conf
port:监听端口(默认为26379)
sentinel monitor:主节点的监听(可以使用多次)
示例:sentinel monitor mymaster(主机名) 127.0.0.1(IP地址) 6379(端口号) 2(法定票数)
法定票数应该设置大于sentinel 服务器个数的半数(一半),最好使用基数
sentinel down-after-milliseconds:sentinel认为主服务器离线,至少需要经过的秒数(默认单位为毫秒)
示例:sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs:指定在执行故障转移时,最多可以有多少个从服务器对新的主服务器同时发起同步请求
示例:sentinel parallel-syncs mymaster 1
sentinel failover-timeout:指定故障转移的超时时间,当主服务器离线,从服务器要连向新的主服务器的时间
示例:sentinel failover-timeout mymaster 180000
主观下线:一个sentinel实例判断出某节点下线
客观下线:多个sentinel协商后判断出某节点下线
在sentinel集群中,每个sentinel以每秒钟一次的频率向已知的主从节点和sentinel发送PING命令,如果在有效时间后节点没有回应,就认为该节点主观下线
专用命令:
SENTINEL masters:列出所有监控的主节点
SENTINEL slaves 主节点名称:列出该主节点下的从节点
SENEINEL get-master-addr-by-name 主节点名称:根据主节点名称获取主节点地址
SENEINEL reset:重置所有的名字
SENEINEL failover 主节点名称:手动强制发起故障转移
Redis的分布式
Clustering:分布式数据库,通过分片机制进行数据分布,clustering内的每个节点仅持有数据库的一部分数据(redis默认是独立的,加入clustering集群就称为其中的节点,clustering的每一个节点都可以接收客户端请求,假如有10000条数据,4个节点,每个节点持有2500个key的数据,还会持有全局元数据(键值映射))
Redis的分布式工具
Twemproxy(Twitter研发)(不建议使用)
代理分片机制
优点:
非常稳定,企业级方案
缺点:
单点故障
需要依赖第三方软件,如keepalived
无法平滑地横向扩展
没有后台界面
代理分片机制引入更多的来回次数并提高延迟
单核模式,无法充分利用多核,除非多实例
Twitter官方内部不再继续使用Twemproxy
Codir(豌豆荚研发)(个人建议使用)
代理分片机制
2014年11月开源
基于GO以及C语言开发
优点:
非常稳定,企业级方案
数据自动平衡
高性能(较Twemproxy快1倍)
善用多核CPU
简单:没有paxos类的协调机制,没有主从复制
有后台界面
缺点:
代理分片机制引入更多的来回次数并提高延迟
需要第三方软件支持协调机制(zookeeper以及ted)
不支持主从复制,需要另外实现
Codis采用了Proxy的方案,所以必然会带来单机性能的损失(经测试,在不开pipeline的情况下,大概会损失40%左右的性能)
Redis Clusten(官方)
官方实现
需要Rdis3.0或更高的版本
优点:
无中心的P2P Gossip分散式模式
更少的来回次数并降低延迟
自动于多个redis节点进行分片
不需要第三方软件支持协调机制
缺点:
需要时间来验证其稳定性
没有后台界面
需要智能客户端
Redis客户端必须支持Redis Cluster架构
较Codis有更多的维护升级成本
Cerberus(芒果TV研发)
优点:
数据自动平衡
本身实现了Redis的Smart Client
支持读写分离
缺点:
依赖Redis3.0或更高版本
代理分片机制引入更多的来回次数并增大延迟
需要时间验证其稳定性
没有后台界面