Redis入门到五连绝世
一、Nosql 的简介
主要Nosql数据库:redis,Memcache,Mongdb
1、功能优点
-
易扩展
NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。
数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。
-
大数据量高性能
NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。
一般MySQL使用Query Cache,每次表的更新Cache就失效,是一种大粒度的Cache,在针对web2.0的交互频繁的应用, Cache性能不高。 而NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多了。
-
多样灵活的数据模型
NoSQL无需事先为要存储的数据建立字段, 随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。
2、传统数据库 RDBMS VS NOSQL
- RDBMS
-
高度组织化结构化数据
-
结构化查询语言(SQL)
-
数据和关系都存储在单独的表中
-
数据操纵语言,数据定义语言
-
严格的一致性
-
基础事务
- NOSQL
-
NoSQL 代表着不仅仅是SQL
-
没有声明性查询语言
-
没有预定义的模式
-
键-值对存偏,列存储,文档存储,图形数据库
-
最终一-致性,而非ACID属性
-
非结构化和不可预知的数据
-
CAP定理
-
高性能,高可用性和可伸缩性
3、3V + 3高
4、Nosql数据库四大分类
5、在分布式数据库中CAP原理 CAP + BASE
5.1、CAP 图解:
5.2.、CAP 的 3 进 2
5.3、 BASE 是什么
BASE就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。
BASE其实是下面三个术语的缩写:
- 基本可用(Basically Available)
- 软状态( Soft state)
- 最终一-致(Eventually consistent)
它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。为什么这么说呢,缘由就在于大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另外一一种方式来完成,这里BASE就是解决这个问题的办法;
5.4、分布式系统+集群
分布式系统( distributed system )
由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成。 是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件分布式系统可以应用在在不同的平台,上如: Pc、 工作站、局域网和广域网上等。
简单来讲:
- 分布式: 不同的多台服务器上面部署不同的服务模块(工程),他们之间通过Rpc/Rmi之间通信和调用,对外提供服务和组内协作。
- 集群: 不同的多台服务器上面部署相同的服务模块,通过分布式调度软件进行统一的调度, 对外提供服务和访问。
二、Redis 入门介绍
1、redis是什么
Redis:REmote DIctionary Server(远程字典服务器) ,是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行,并支持持久化的NoSQL数据库,是当前最热门的NoSq|数据库之一,也被人们称为数据结构服务器;
2、Redis三个特点:
-
Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
-
Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
-
Redis支持数据的备份,即master-slave模式的 数据备份
3、主要功能
- 内存存储和持久化: redis支持 异步将内存中的数据写到硬盘上,同时不影响继续服务
- 取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面
- 模拟类似于HttpSession这种需要设定过期时间的功能
- 发布、订阅消息系统
- 定时器、计数器
4、Linix安装
redis中文网:http://www.redis.cn/
教程链接:http://www.cnblogs.com/L-Test/p/9239709.html
1、下载redis-4.0.10
在redis官网(https://redis.io/download)下载redis-4.0.10
2、将安装包上传至Linux服务器
在Linux服务器根目录下创建目录package,并将安装包上传至该目录下;
3、安装依赖包(有的可以不安装)
# 安装这条就好了吧
[root@Cherry /]# yum install -y gcc
[root@Cherry /]# yum install tcl
4、创建安装目录(略)
[root@Cherry /]# mkdir /usr/local/redis
5、解压redis-4.0.10.tar.gz
[root@Cherry /]# cd /package/
[root@Cherry package]# tar -zxvf redis-4.0.10.tar.gz
6、编译
[root@Cherry package]# cd redis-4.0.10
[root@Cherry redis-4.0.10]# make
7、安装
[root@Cherry redis-4.0.10]# make PREFIX=/usr/local/redis install
注意:PREFIX要大写
安装完成后会在/usr/local/redis目录下产生一个bin目录,里面有如下几个文件:
redis-benchmark 性能测试工具
redis-check-aof 检查aof日志的工具
redis-check-rdb 检查rdb日志的工具
redis-cli 客户端
redis-server 服务端
redis.conf 配置文件(如果没有就操作第8步)
8、将redis的配置文件拷到安装目录下(略)
[root@Cherry redis-4.0.10]# cp redis.conf /usr/local/redis/bin/
9、修改redis配置文件,配置redis后台启动
[root@Cherry redis-4.0.10]# cd /usr/local/redis/bin
[root@Cherry bin]# vim /usr/local/redis/bin/redis.conf
注:daemonize no 改为 daemonize yes
默认好像现在就是 yes ,也就是后台静默运行;
vim 安装:yum -y install vim*
vim 在命令行查询格式," :/daemonize " ,n 匹配下一个,N 匹配上一个,文件如果为完全显示,按 j ;
10、将redis加入到开机启动
[root@Cherry bin]# vi /etc/rc.local
在里面添加内容:/usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf
11、启动redis
[root@Cherry bin]# /usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf
#查看是否运行其端口
[root@Cherry bin]# ps -ef|grep redis
12、测试一下
[root@Cherry bin]# ./redis-cli
127.0.0.1:6379> set tomorrow bad # redis中存入键值对
OK
127.0.0.1:6379> get tomorrow # 根据键获取
"bad"
127.0.0.1:6379> exit #退出 redis
13、关闭redis
[root@Cherry bin]# ./redis-cli shutdown
14、修改redis配置文件,redis可以远程连接
[root@Cherry bin]# vi /usr/local/redis/bin/redis.conf
bind 127.0.0.1改为 #bind 127.0.0.1
protected-mode yes 改为 protected-mode no
#requirepass foobared去掉注释,foobared改为自己的密码
15、开放Linux服务器6379端口
如果远程还是连接不上,则需要开放Linux服务器的6379端口
[root@Cherry bin]# vi /etc/sysconfig/iptables
加入端口配置: -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT
保存修改:service iptables save
重启防火墙:service iptables restart
5、Redis启动后杂项讲解
-
单进程
单进程模型来处理客户端的请求。对读写等事件的响应是通过然 epoll 函数的包装来做到的。Redis的实际处理速度完全依靠主进程的执行效率;
Epoll 是 Linux 内核为处理大批量文件描述符而作了改进的epoll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率;、
-
默认16个数据库,类似数组下表从零开始,初始默认使用零号库;**
select 数据库下标(0~15)
**;- Select命令切换数据库
- Dbsize查看当前数据库的key的数量,
keys *
查看当前下标的库所有的 keykeys ?
查看当前下标的库 key值只有一位的 key
- Flushdb:清空当前下标的库;Flushall:清空16个所有的库;
- 通杀全部库 统一“密码管理,16个库都是同样密码,要么都OK要么一个也连接不上
- Redis索引都是从零开始
- 为什么默认端口是6379
三、Redis 数据类型
1、Redis 五大数据类型
-
String (字符串)
string是redis最基本的类型,你可以理解成与Memcached- -模一样 的类型,个 key对应一个value
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象。
string类型是Redis最基本的数据类型,一个redis中字符串value最多可以是512M(变态级别)
-
Hash (哈希,炎似java里的Map)
Redis hash是一个鍵値対集合。
Redis hash是一个 string 类型的 field 和 value 的映射表, hash特別造合用于存偖対象。
类似 Java 里面的Map< String,Object>
-
List (列表)
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)
它的底层实际是个链表
-
Set (集合)
Redis的Set是string类型的无序集合。它是通过HashTable实现实现的
-
Zset(sorted set: 有序集合)
Redis zset和set一样也是string类型元素的集合, 且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。
redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但 分数(score)却可以重复。
2、Redis 操作指令
连接:http://redisdoc.com/
3、Redis 键(key)
key:存放的key的名字,db:数据库下标
-
单值单 value:
type key : 查看当前key的类型;
del key :删除指定的 key;
4、Redis 字符串(String)
-
常用:
-
案例:
set k1 1 # 设置key为 k1,value为 1 的 String 类型 get k1 # 根据 key 值获取 value del k1 # 根据 key 值删除 append k1 2 # 在指定 key 的 value 后面进行字符串的添加,value="12" strlen k1 # 查看指定 key 的 value 的长度 #下面的只有字符串是纯数字才能操作 incr k1 # 指定 key 的 value 值进行加1,,value=13 decr k1 # 减1 incrby k1 5 # 指定具体增加 5 decrby k1 2 # 指定具体减少 2 set k2 abc1234 getrange k2 0 3 # 截取指定下标范围类的字符串,value="abc1";0 -1 范围就是取全部字符 setrange k2 1 wang # 从指定的下标处,用指定的值覆盖掉原来的,value="awang34" ,原值:abc1234 setex k3 20 456a # 设置key=k3,value="456a",有效时间为20秒 ttl k3 # 返回当前 k3 还剩几秒有效时间,-2则表示过期,-1表示永不过期 setnx k3 123 # 数据库存在当前key,则不会创建,不存在则创建当前设置 mset k4 v4 k5 v5 # 多个一起设置 k4:v4 ,k5:v5 mget k4 k5 # 同时获取k4,k5 的 value msetnx k5 v78 k6 v6 # 多个key同时数据库不存在,则才能存入,部分不存在不行
5、Redis 列表(List)
-
单值多value :
-
案例:
# list 集合就像栈,先装进去的,只能后取出来,先进后出 lpush l1 1 2 3 4 5 # 设置 key=l1 ,value=[1,2,3,4,5] 的集合List(左边开始装) lrange l1 0 -1 # 取出 l1 的所有值,取出顺序:5 4 3 2 1 rpush l2 1 2 3 4 5 # 同上,从右边开始装 lrange l2 0 -1 # 取出 l2 的所有值,取出顺序:1 2 3 4 5 # 此时 l1 的集合顺序: 5 4 3 2 1 lpop l1 # 从左边出栈,去除1个,去除的是 5 rpop l1 # 从右边出栈,去除1个,去除的是 1 lrange l1 0 -1 # 取出顺序:4 3 2 lindex l1 1 # 从上往下(左->右)按下标取,去除的值为 3 llen l1 # 获取 l1 的长度,此时长度为 3 lpush l3 1 2 2 2 3 3 4 5 # 从左开始往下存 lrem l3 3 2 # 去除指定 l3 中的 3个2 ,l3结果: 5 4 3 3 1 ltrim l3 0 2 # 从l3中截取指定下标的数据,再赋值给 l3,l3结果: 5 4 3 rpoplpush l1 l3 # l1 的右边最后一个出栈,再将其压栈进l3 LRANGE l1 0 -1 # l1 取出顺序为:4 3 LRANGE l3 0 -1 # l1 取出顺序为:2 5 4 3 lset l1 1 x # l1 的下标1位置原来的值替换为 x ,此时 l1: 4 x linsert l1 before x java # 在 l1 的 x 值的位置之前插入 java, 此时 l1: 4 java x linsert l1 after x oracle # 在 l1 的 x 值的位置之后插入 oracle, 此时 l1: 4 java x oracle sAdd key1 member1 #添加一个VALUE到SET容器中,如果这个key已经存在于SET中,那么返回FLASE。
-
性能总结:
- 它是一个字符串链表,left、right都可以插入添加;
- 如果键不存在,创建新的链表;
- 如果键已存在,新增内容;
- 如果值全移除,对应的键也就消失了;
- 链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了;
6、Redis 集合(Set)
-
单值多 value:
-
案例:
sadd s1 1 1 2 3 3 # 添加 set 集合,重复的数字不会添加 smembers s1 # 查询 s1 ,返回结果:1 2 3 sismember s1 1 # 判断 s1 中是否有 1 ,存在便会返回 scard s1 # 获取 s1 中元素的个数 srem s1 3 # 删除 s1 中指定的元素 3 srandmember s1 3 # 从 s1 中随机抽取 3 个元素 spop s1 # 随机出栈,s1 中随机出栈一个元素 smove s1 s2 2 # 将 s1 中的元素 2 移入 s2 中 del s1 # 删除 s1 # 重新添加 s1 ,s2 sadd s1 1 2 3 4 5 sadd s2 1 2 3 a b sdiff s1 s2 # 差集,返回结果: 4 5 (在 s1 中,不在 s2 中) sinter s1 s2 # 交集,返回结果: 1 2 3 sunion s1 s2 # 并集,返回结果: 5 b 4 a 3 2 1
7、Redis 哈希(Hash)
-
KV 模式不变,但 V 是一个键值对:
-
案例:
# kuey=user,value=name zhangsan,果然hash存储对象 hset user name zhangsan # 1个属性值 hget user name #获取的方式,需要指明key之外,还要进一步指明value中键值对的key hmset user age 12 sex nan #多个值存储 3个属性值 hmget user age sex #多值获取 hgetall user # 打印key中保存的所有信息,对象的toString hdel user sex # 删除 user 中的 sex 属性 2个属性值 hlen user #判断 user 中有几个属性值 打印 2 hexists user name # 判断 name 属性是否存在,存在返回1,不存在返回0 hkeys user # 遍历打印 user 中的 value 中键值对的key(属性名) hvals user # 遍历打印 user 中的 value 中键值对的value(属性值) hincrby user age 5 # 将user中的 age 属性值添加指定的 5 ,属性值是数字的才能使用此函数 hsetnx user score 92.5 # 不存在指定的属性则添加,添加成绩为 92.5 hincrbyfloat user score 2.5 # 指定添加小数
8、Redis 集合 Zset(Sorted set)
-
解析:
- 在set基砒上,加一个score值。之前set是k1 v1 v2 v3, 现在zset是k1 score1 L1 score2 v2
- 在set基砒上,加一个score值。之前set是k1 v1 v2 v3, 现在zset是k1 score1 L1 score2 v2
-
案例:
zadd z1 70 v1 80 v2 90 v3 100 v4 #存放key=z1,并在每个值前给定一个分数 zrange z1 0 -1 # 获取的是在 z1 中所有的value, 结果:v1 v2 v3 v4 zrange z1 0 -1 withscores # 带分数打印:v1 70 v2 20 .... zrangebyscore z1 70 90 # 打印分数在70~90的value:v1 v2 v3 zrangebyscore z1 70 (90 # (:表示限制,不包含,则打印: v1 v2 zrangebyscore z1 70 90 limit 1 2 # limit返回结果的下标 1 开始,取 2 个,打印:v2 v3 zrem z1 v4 # 删除 z1 中指定的 value,同时他的分数也会被删除 zcard z1 # 统计 z1 中的 value 值 zrank z1 v1 # 获得 z1 中 v1 的下标 zscore z1 v2 # 获得 z1 中 v2 的设置的分数 zrevrank z1 v3 # 逆序获得 z1 中 v3 的下标,从下往上会数 zrevrange z1 0 -1 # 逆序查询所有打印结果集 zrevrangebyscore z1 80 70 # 逆序打印 70~80 的 value
四、Redis 配置文件 redis.conf
1、Units 单位
- 配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit
- 对大小写不敏感
# Redis configuration file example
# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
2、INCLUDE 包含
- 和我们的Struts2配置文件类似,可以通辻includes包含, redis.conf 可以作为总闸,包含其他
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include /path/to/local.conf
# include /path/to/other.conf
3、 GENERAL 通用
pidfile /var/run/redis.pid # 指定的进程管道 id 文件
daemonize yes # 开启后台静默运行
port 6379 # 默认端口 6379
tcp-backlog:
设置tcp的backlog,backlog其实是一个连接队列,backlog队列总和= 未完成三次握手队列+已经完成三次握手队列。
在高并发环境下你需要一一个高backlog值来避免慢客户端连接问题。注意Linux内核会将这个值减小到/ proc/sys/ net/core/somaxconn的值,所以需要确认增大somaxconn和tcp_ max_ syn_ backlog两个值,来达到想要的效果
tcp-backlog 511 # 不懂保持默认即可
timeout 0 #绑定的 IP , 端口等,默认本机
#单位为秒,如果设置为0,则不会进行Keepalive检测,建议设置成60
tcp-keepalive 0 # 空闲多少秒后关闭,0 表示不关闭
loglevel notice # 日志级别,4种,debug,verbose,notice, warning
logfile "" # 日志名,没指定会控制台输出...
# syslog-enabled no # 是否把日志输出到syslog中
# syslog-ident redis # 指定 syslog 中的日志标志
# syslog-facility local0 # 指定syslog设备,值可以是USER或LOCALO-LOCAL7
databases 16 # 默认 16 个库
4、SNAPSHOTTING 快照
-
Save
# 保存级别互为补充,满足任何一个条件就保存 save 900 1 # 900秒钟修改过 1 次则保存快照 save 300 10 # 300秒钟修改过 10 次则保存快照 save 60 10000 # 60秒钟修改过 10000 次则保存快照 # 如果想禁用RDB持久化的策略,只要不没置任何save指令,或者給save伎入一-个空字符串参数也可以; save "" # 手动立即保存,输入 save 即可 127.0.0.1:6379> save dbfilename dump.rdb # 系统默认读取 dump.rdb 文件 # 出错的实收进行等待处理,如果配置成 no ,表示你不在乎数据不一致或者有其他手段发现和控制 stop-writes-on-bgsave-error yes #rdbcompression:对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,可以设置为 no rdbcompression yes
7、SECURITY 安全
-
访问密码的查看,设置和取消
-
redis.conf 文件配置了
dir ./
生成信息就会保存在启动 redis-server 服务端的路径下;127.0.0.1:6379> config get requirepass #获取其安全,课件密码为空 1) "requirepass" 2) "" 127.0.0.1:6379> config get dir # 当前启动路径 1) "dir" 2) "/usr/local/redis/bin" 127.0.0.1:6379> 127.0.0.1:6379> ping # 连接上没有设置密码时 PONG # 此返回表示连接成功 127.0.0.1:6379> config set requirepass "123456" # 设置密码为 123456 OK 127.0.0.1:6379> ping # 再次 ping 无法连接 (error) NOAUTH Authentication required. 127.0.0.1:6379> auth 123456 # 现在每次使用之前需要输入密码验证 OK 127.0.0.1:6379> ping PONG 127.0.0.1:6379> config set requirepass "" # 改回默认没有密码的状态 OK 127.0.0.1:6379> ping PONG
8、LIMITS 限制
# maxclients 10000 # 默认10000个客户端可同时连接
# maxmemory <bytes> # 设置内存的大小
# maxmemory-policy noeviction # 内存的过期策略,默认永不过期
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key according to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
(1) volatile-lru: 使用LRU算法移除key,只对设置了过期时间的键
(2) allkeys-Iru: 使用LRU算法移除key
(3) volatile-random: 在过期集合中移除随机的key,只对设置了过期时间的键
(4) allkeys-random: 移除随机的key
(5) volatile-ttl: 移除那些TTL值最小的key,即那些最近要过期的key
(6) noeviction: 不进行移除。针对写操作,只是返回错误信息
# maxmemory-samples 5 # 默认5个
设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,redis默认会检查这么多个key并选择其中LRU的那个,所以你可以设置样本的大小;
9、APPEND ONLY MODE 追加
-
aof 的开启
# 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no appendonly no appendfilename appendonly.aof # 指定更新日志文件名,默认为appendonly.aof
-
Appendfsync 保存策略
-
Always:同步持久化每次发生数据变更会被立即记录到磁盘,性能较差,但数据完整性比较好
-
Everysec: 出厂默认推荐,异步操作,每秒记录,如果一秒内宕机,有数据丢失
-
No
-
-
No-appendfsync-on-rewrite:重写时是否可以运用 Appendfsync,用默认no即可,保证数据安全性。
-
Auto-aof-rewrite-min-size:设置重写的基准值
-
Autoraof-rewrite-percentage:设置重写的基准值
五、Redis 持久化
简述:rdb aof ;
1、RDB(Redis DataBase )介绍:
-
rdb 是什么?
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
Redis会单独创建(fork) 一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何 IO 操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
-
Fork 的作用:
Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程;
-
Rdb 保存的是 dump.rdb 文件:
-
RDB是整个内存的压缩过的Snapshot, RDB的数据结构,可以配置复合的快照触发条件,快照保存配置设置(redis.conf),这个也是补充第四段没有讲到的内容;
# 保存级别互为补充,满足任何一个条件就保存 save 900 1 # 900秒钟修改过 1 次则保存快照 save 300 10 # 300秒钟修改过 10 次则保存快照 save 60 10000 # 60秒钟修改过 10000 次则保存快照 dbfilename dump.rdb # 系统默认读取 dump.rdb 文件
-
如何触发 Rdb
-
配置文件中默认的快照配置(Save 配置),冷拷贝后重新使用,可以cp dump.rdb dump_ new.rdb ;
-
命令save或者是bgsave ;
- Save: save时只管保存,其它不管,全部阻塞;
- BGSAVE: Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求。可以通过lastsave命令获取最后一次成功执行快照的时间;
-
执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义;
-
-
如何恢复
将备份文件(dump.rdb)移动到redis安装目录并启动服务即可,
CONFIG GET dir
获取启动目录; -
优势
-
适合大规模的数据恢复
-
对数据的完整性和一致性要求不高
-
-
劣势
在一定间隔时间做一-次备份,所以如果redis意外down掉的话,就会丢失最后一-次快照后的所有修改;
Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑;
- 小总结:
2、AOF(Append Only File)介绍:
-
AOF 是什么:
以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作 ;
-
AOF 开启
# 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no appendonly no appendfilename appendonly.aof # 指定更新日志文件名,默认为appendonly.aof
-
Appendfsync 保存策略
-
Always:同步持久化每次发生数据变更会被立即记录到磁盘,性能较差,但数据完整性比较好
-
Everysec: 出厂默认推荐,异步操作,每秒记录,如果一秒内宕机,有数据丢失
-
No
-
-
AOF 启动/修复/恢复
- 正常恢复
- 启动:设置Yes,修改默认的appendonly no, 改为 yes
- 将有数据的aof文件复制一份保存到对应目录(configgetdir)
- 恢复: 重启redis然后重新加载
- 异常恢复
- 启动:设置Yes
- 备份被写坏的AOF文件
- 修复:Redis-check-aof --fix进行修复
- 恢复:重启redis然后重新加载
【注】:如果开启了appendonly,则当前启动目录下会同时存在 appendonly.aof ,dump.rdb 文件,而在此启动 Redis服务端,则是首先读取的是 appendonly.aof ,如果此文件报错服务端是不能启动的,故要排除掉appendonly.aof 中系统无法识别的额内容:
- 正常恢复
-
rewrite 是什么 ?
AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof ;
-
重写原理
AOF文件持续增长而过大时,会fork出-一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件, 这点和快照有点类似;
-
触发机制
- Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发;
auto-aof-rewrite-percentage 100 # 百分之百即1倍 auto-aof-rewrite-min-size 64mb # 64M
- No-appendfsync-on-rewrite:重写时是否可以运用 Appendfsync,用默认no即可,保证数据安全性。
- Auto-aof-rewrite-min-size:设置重写的基准值
- Autoraof-rewrite-percentage:设置重写的基准值
-
优势
- 每秒同步:appendfsync always同步持久化每次发生数据变更会被立即记录到磁盘性能较差但数据完整性比较好
- 每修改同步:appendfsync everysec 异步操作,每秒记录 如果一秒内宕机,有数据丢失
- 不同步:appendfsync no 从不同步
-
劣势
- 相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
- Aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同
-
小总结
3、总结
性能建议:
- 因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。
- 如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。
- 如果不Enable AOF,仅靠Master-Slave Replication实现高可用性也可以。能省掉一大笔IO也减少 了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉, 会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构。
六、Redis 事务
1、事务是什么
可以一次执行多个命令,本质是一-组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行执行而不会被其它命令插入,不许加塞;
2、 能干嘛
一个队列中,一次性、顺序性、排他性的执行一系列命令;
3、怎么玩
-
常用命令
-
DISCARD :取消事务,放弃执行事务块内的所有命令。
-
EXEC:执行所有事务块内的命令。
-
MULTI :标记一个事务块的开始。
-
UNWATCH:取消WATCH命令对所有key的监视。
-
WATCH key [key …] :监视-一个(或多个)key , 如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断。
-
-
Case1:正常执行
# 如果把一个事务比作一次超市购物,则开启事务后,未提交之前,则所有的操作都是记录保存在队列中,等待逐条执行,队列就理解为购物车; 127.0.0.1:6379> multi # 开启事务 OK 127.0.0.1:6379> set k1 v1 # 购物车队列存放第一条数据 QUEUED 127.0.0.1:6379> set k2 v2 # 第二条操作 QUEUED 127.0.0.1:6379> get k1 # 第三条操作 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> exec # 执行事务,收银柜台结账,队列先进先出,打印逐个单据如下 1) OK 2) OK 3) "v1" 4) OK
-
Case2:放弃事务
127.0.0.1:6379> multi # 开启事务 OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> discard # 放弃此事务,不会被执行 OK
-
Case3:全体连坐
127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> set k5 v5 QUEUED 127.0.0.1:6379> set45 # 添加事务时,此条命令错误 (error) ERR unknown command 'set45' 127.0.0.1:6379> set k6 v6 # 事务队列还能添加 QUEUED 127.0.0.1:6379> exec # 执行报错 (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get k5 # 获取 k5,发现添加失败,一损俱损 (nil)
-
Case4:冤头债主
127.0.0.1:6379> multi # 开启事务 OK 127.0.0.1:6379> set k1 aa QUEUED 127.0.0.1:6379> incr k1 # k1的值自增1,命令没有报错,但执行肯定报错 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> exec # 对于事务来说,其他执行成功,其中一条出错 1) OK 2) (error) ERR value is not an integer or out of range # 此自增操作报错 3) OK 4) "22"
-
Case5: watch 监控
-
悲观锁
悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁;
-
乐观锁
乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量;
乐观锁策略:提交版本必须大于记录当前版本才能执行更新;
-
CAS(Check And Set)
-
初始化信用卡可用余额和欠额为例:
-
无加塞篡改,先监控再开启multi,保证两笔金额变动在同一个事务内
127.0.0.1:6379> set balance 100 #添加信用卡信用余额 OK 127.0.0.1:6379> set debt 0 #添加欠额 OK 127.0.0.1:6379> watch balance # 对余额添加监听 OK 127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> decrby balance 20 # 花掉20,余额减20 QUEUED 127.0.0.1:6379> incrby debt 20 # 欠额增加 20 QUEUED 127.0.0.1:6379> exec # 执行成功 1) (integer) 80 2) (integer) 20
-
有加塞篡改
同上,在事务还没有 exec 执行之前,这时出现另外一个客户端对 balance 进行了修改,则数据库保存的 balance 的版本比你之前监听的版本就要高(最近的版本高),你再提交就会报错,无法提交,所有可以输入
unwatch
取消监听,然后再watch
balance,同上操作,直到操作成功; -
unwatch:一旦执行了exec之前加的监控锁都会被取消掉了;
-
总结:
-
Watch指令, 类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行;
-
通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败 ;
-
-
4、3 阶段
-
开启:以MULTI开始一个事务
-
入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
-
执行:由EXEC命令触发事务
5、3 特性
- 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
- 不保证原子性:redis同一个事务中如果有一条命令执行(执行报错,加入队列时并未报错,冤头债主)失败,其后的命令仍然会被执行,没有回滚。
七、Redis 的发布订阅
1、是什么
进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
2、命令
-
PSUBSCRIBE patterm [pattem …] : 订阅一个或多个符合给定模式的频道。
-
PUBSUB subcommand [argument [argument …]] :查看订阅与发布系统状态
-
PUBLISH channel message :将信息发送到指定的频道。
-
PUNSUBSCRIBE [pattem [patterm …]] :退订所有给定模式的频道。
-
SUBSCRIBE channel [channel …] :订阅给定的一个或多个频道的信息。
-
UNSUBSCRIBE [channel [channel …] :指退订给定的频道。
3、案例
先订阅后发布后才能收到消息
-
可以一次性订阅多个,SUBSCRIBE c1 c2 c3 ;消息发布,PUBLISH c2 hello-redis
#首先开redis客户端r1,订阅频道 c1,c2,c3 127.0.0.1:6379> subscribe c1 c2 c3 # 订阅频道 Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "c1" 3) (integer) 1 1) "subscribe" 2) "c2" 3) (integer) 2 1) "subscribe" 2) "c3" 3) (integer) 3 # 另开第二个客户端 r2 ,直接发布消息 127.0.0.1:6379> publish c2 hello-redis # 指定给频道 c2 发布消息 (integer) 1 # 客户端 r1 接收到消息,接着打印人如下: 601) "message" 2) "c2" 3) "hello-redis"
-
订阅多个,通配符, PSUBSCRIBE new* 收取消息, PUBL ISH new1 redis2015
操作同上,只是 r2 客户端发送消息时指定频道为 new前缀,后面内容通配就行;
八、 Redis 的复制(Master/Stave)
1、是什么
行话:也就是我们所说的主从复制,主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave以读 为主;
2、能干嘛
主要功能是读写分离,容灾恢复;
3、怎么玩
-
配从(库)不配主(库)
- 对于配置都是在从库上进行操作,主库不动。
-
从库配置: slaveof主库IP主库端口。
- 每次与master断开之后,都需要重新连接,除非你配置进 redis. conf 文件
- Info replicationt
-
修改配置文件细节操作。
-
拷贝多个 redis.conf 文件
# 利用 cp 命令将 redis.conf 配置文件拷贝三份 cp redis-4.0.10/redis.config myredis/redis4379.conf cp redis-4.0.10/redis.config myredis/redis4380.conf cp redis-4.0.10/redis.config myredis/redis4381.conf # 分别对三份文件操作如下 1. 开启后台运行 daemonize yes 2. Pid 文件名字 pidfile /var/run/redis6379.pid 3. 指定端口 port 6379 4. Log 文件名字 logfile "6379.log" 5. Dump.rdb 名字 dbfilename dump6379.rdb
-
-
常用3招
-
一主二仆
# 默认一开启都是主机 127.0.0.1:6379> info replication # 6379 查看相关信息 # Replication role:master # master 主机的意思 connected_slaves:0 # 后面没有从机 master_repl_offset:0 repl_backlog_active:0 # 激活状态为 0,没有激活 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0 127.0.0.1:6379> set v1 k1 #设置一个 v1 OK # 设置从机 (连接指定的端口 redis-cli -p 6380) 127.0.0.1:6380> slaveof 127.0.0.1 6379 #将自己设置为从机,连接6379端口主机 OK 127.0.0.1:6380> info replication # 6380 查看自身相关信息 # Replication role:slave # slave 从机的意思 master_host:127.0.0.1 # 连接的主机地址 master_port:6379 # 连接的主机的端口 master_link_status:up # up 正在连接中 master_last_io_seconds_ago:8 master_sync_in_progress:0 slave_repl_offset:169 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 127.0.0.1:6380> get v1 # 可以拿到主机6379设置的 v1 "k1" --主从搭建完成后,不管主机是搭建之前设置的数据,还是之后,从机会将主机所有数据复制过来 # 再次查看主机的信息 127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 # 后面跟了两个从机6380,6381 slave0:ip=127.0.0.1,port=6380,state=online,offset=57,lag=0 slave1:ip=127.0.0.1,port=6381,state=online,offset=57,lag=1 master_repl_offset:57 repl_backlog_active:1 # 激活状态为1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:56 # 所谓读写分离,从机是不能进行写操作的,6380从机写入报错如下 127.0.0.1:6380> set v2 22 (error) READONLY You can't write against a read only slave. --此基础班配置,如果主机6379挂掉了,6380,6381两个从机依然是从机,不会进行上位操作 --若主机又恢复了过来,主机写如数据,从机依然还是可以复制获取到的 --若从机6380挂了,从机6381不受影响,主机6379的从机数减一 --若从机6380再次重启恢复,它就是 master 主机的身份,和主机6379没有半毛关系了 除非:每次与master断开之后,都需要重新连接,除非你配置进 redis.conf 文件
-
薪火相传。
-
上一个 Slave 可以是‘下一个 slave 的 Master,Slave 同样可以接收其他 slaves 的连接和同步请求,那么该 slave 作为了链条中下一个的 maste r,可以有效减轻 master 的写压力,
-
中途变更转向:会清除之前的数据,重新建立拷贝最新的;
-
Slaveof 新主库IP新主库端口;
# 主机6379 ,从机6380 连接6379 ,从机6381 连接6380 # 主机写入 set 的数据,6380,6381都可以复制获取到 127.0.0.1:6380> info replication # 6380 查看自身消息 # Replication role:slave # 名义上还是一个从机,则自身是不能进行set写操作的 master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:5 master_sync_in_progress:0 slave_repl_offset:4131 slave_priority:100 slave_read_only:1 connected_slaves:1 # 自身也跟随了一个从机,下面是从机6381的信息 slave0:ip=127.0.0.1,port=6381,state=online,offset=71,lag=0 master_repl_offset:71 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:70
-
-
反客为主。
--sSLAVEOF no one:使当前数据库停止与其他数据库的同步,转成主数据库! # 大前提,主机6379,从机6380,6381都跟着6379混 # 主机6379挂掉后,手动设置新的主机 6380 127.0.0.1:6380> slaveof no one OK # 从机6381 手动更改跟着 6380 混 127.0.0.1:6380> slaveof 127.0.0.1 6381 OK # 则6380,6381就单独组合成主从复制,6379重启回来已经没有半毛关系
-
4、复制原理
-
Slave后幼成功達接到master后会安送一个sync命令。
-
Master 接到命令启动后台的存盘进程,同吋收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master 将传送整个数据文件到 slave,以完成一-次完全同歩。
-
全量复制:而slave 服务在接收到数据庠文件数据,将其存盘并加載到内存中。
-
増量复制:Master 継续将新的所有收集到的修改命令依次传给 slave ,完成同歩,但是只要是重新连接master,一次完全同歩(全量复制) 将被自动执行 。
5、哨兵模式( sentinel)
-
是什么?
反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库 ;
-
怎么玩?
-
调整结构,6379带着80、 81
-
自定义的 /myredis 目录下新建 sentinel.conf 文件,名字绝不能错。
touch sentinel.conf
-
配置哨兵,填写内容
-
sentinel monitor 被监控数据库名字 (自己起名字) 127.0.0.1 6379 1
# host6379 是自定义的名字,1 表示主机挂掉后,谁的票数多于1票,谁就是新的主机 sentinel monitor host6379 127.0.0.1 6379 1
-
上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多的成为主机
-
-
启动哨兵
# 上述目录依照各自的实际情况配置,可能目录不同 redis-sentinel myredis/sentinel.conf # 启动哨兵命令
-
正常主从演示
- 6379 作为 master 主机,6380,6381跟随6379作为从机
- 原有的 6379 master挂了
- 从机中投票新选 master
- 重新主从继续开工,info replication查查看
- 如果之前的 6379 master重启回来,就会作为新选出的 master 的从机,不再是主机。
-
-
一组 sentine 能同时监控多个Master
6、复制的缺点
由于所有的写操作都是先在Master 上操作,然后同步更新到 Slave 上,所以从 Master 同步到 Slave 机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave 机器数量的增加也会使这个问题更加严重。
九、Redis 的 Java 客户端 Jedis
-
五种类型操作( TestAPI.java )
-
事务 ( TestTX.java )
-
watch 乐观锁事务 ( TestTransactionLock.java )
-
主从复制 ( TestMS.java )
-
jedis连接池 ( JedisPoolUtil.java,TestPool.java )
- 获取Jedis实例需要从JedisPool中获取
- 用完Jedis实例需要返还给JedisPool
收到的用于修改数据集命令,在后台进程执行完毕之后,master 将传送整个数据文件到 slave,以完成一-次完全同歩。
-
全量复制:而slave 服务在接收到数据庠文件数据,将其存盘并加載到内存中。
-
増量复制:Master 継续将新的所有收集到的修改命令依次传给 slave ,完成同歩,但是只要是重新连接master,一次完全同歩(全量复制) 将被自动执行 。
5、哨兵模式( sentinel)
-
是什么?
反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库 ;
-
怎么玩?
-
调整结构,6379带着80、 81
-
自定义的 /myredis 目录下新建 sentinel.conf 文件,名字绝不能错。
touch sentinel.conf
-
配置哨兵,填写内容
-
sentinel monitor 被监控数据库名字 (自己起名字) 127.0.0.1 6379 1
# host6379 是自定义的名字,1 表示主机挂掉后,谁的票数多于1票,谁就是新的主机 sentinel monitor host6379 127.0.0.1 6379 1
-
上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多的成为主机
-
-
启动哨兵
# 上述目录依照各自的实际情况配置,可能目录不同 redis-sentinel myredis/sentinel.conf # 启动哨兵命令
-
正常主从演示
- 6379 作为 master 主机,6380,6381跟随6379作为从机
- 原有的 6379 master挂了
- 从机中投票新选 master
- 重新主从继续开工,info replication查查看
- 如果之前的 6379 master重启回来,就会作为新选出的 master 的从机,不再是主机。
-
-
一组 sentine 能同时监控多个Master
6、复制的缺点
由于所有的写操作都是先在Master 上操作,然后同步更新到 Slave 上,所以从 Master 同步到 Slave 机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave 机器数量的增加也会使这个问题更加严重。
九、Redis 的 Java 客户端 Jedis
- 五种类型操作( TestAPI.java )
- 事务 ( TestTX.java )
- watch 乐观锁事务 ( TestTransactionLock.java )
- 主从复制 ( TestMS.java )
- jedis连接池 ( JedisPoolUtil.java,TestPool.java )
- 获取Jedis实例需要从JedisPool中获取
- 用完Jedis实例需要返还给JedisPool
- 如果Jedis在使用过程中出错,则也需要还给JedisPool