redis:事务(Multi、Exec、discard),持久化(RDB,AOF),主从复制,集群

redis事务

定义

Redis事务是一个单独的隔离操作:
	事务中的所有命令都会序列化、按顺序地执行。
	事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

  Redis事务的主要作用就是串联多个命令防止别的命令插队

Multi、Exec、discard

从输入Multi命令开始,输入的命令都会依次进入命令队列中,
但不会执行,至到输入Exec后,
Redis会将之前的命令队列中的命令依次执行。
组队的过程中可以通过discard来放弃组队。  

事务的错误处理

组队中某个命令出现了报告错误,(就是语法错误)
执行时整个的所有队列会都会被取消。
如果执行阶段某个命令报出了错误,(就是运行时错误)
则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

事务冲突的问题

想想一个场景:
	有很多人有你的账户,同时去参加双十一抢购
	一个请求想给金额减8000
	一个请求想给金额减5000
	一个请求想给金额减1000

在这里插入图片描述

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

乐观锁(Optimistic Lock), 顾名思义,就是很乐观,
	每次去拿数据的时候都认为别人不会修改,所以不会上锁,
	但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,
	可以使用版本号等机制。乐观锁适用于多读的应用类型,
	这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

在这里插入图片描述

WATCH key [key ...]
	在执行multi之前,先执行watch key1 [key2],
	可以监视一个(或多个) key ,
	如果在事务执行之前这个(或这些) key 被其他命令所改动,
	那么事务将被打断。

unwatch
	取消 WATCH 命令对所有 key 的监视。
	如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令
	先被执行了的话,那么就不需要再执行 UNWATCH 了。

三特性

单独的隔离操作 
	事务中的所有命令都会序列化、按顺序地执行。
	事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 

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

不保证原子性 
	Redis同一个事务中如果有一条命令执行失败,
	其后的命令仍然会被执行,没有回滚 

秒杀例子练习

模拟高并发的情况,使用工具ab
再Linux里面需要输入yum install httpd-tools进行安装

使用:
ab -n 1000 -c 200 -p jane/temp/postfile  -T "application/x-www-form-urlencoded" 10.235.141.6:8080/redis/SecKillServlet
-n  后面是请求数
-c 后面是并发数
-p 是指定的请求数据文件,就是请求的时候需要携带的参数
后面就是测试的请求路径
请求数据文件写prodid=0101&
	后面的&代表结束或者拼接数据
现在就是面临三个问题:
	超卖问题
	连接超时问题
	库存遗留问题

超卖问题:
	就是请求是并发的,有可能都获取到库存都有的,
	所以都将库存进行减一,所以就出现超卖问题
	我们加上事务就可以解决一点点,还要结合监视
	我们可以监视库存这个键,如果有200个并发访问
	然后都加入到事务中,如果有一个修改了库存,
	其他的人都不能执行事务了,都进行撤回

	但是这样出现了新的问题,库存遗留问题,就比如有200个并发
	但是这两百个人只能有一个能秒杀成功,其他的的都是秒杀失败
	那么就有可能最后还有200个人,200个人一起并发,库存还有50,但是最后只能卖出1,剩下49个剩余的
	
	那么得使用Lua脚本进行解决
	还有连接超时用个线程池来解决,
	因为请求太多,并发高,有些请求等着等着就超时了
Lua是一个小巧的脚本语言,Lua脚本可以很容易的被C/C++代码调用,
也可以反过来调用C/C++的函数,Lua并没有提供强大的库,
一个完整的Lua解释器不过200k,
所以Lua不适合作为开发独立应用程序的语言,
而是作为嵌入式脚本语言。

很多应用程序、游戏使用LUA作为自己的嵌入式脚本语言,
以此来实现可配置性、可扩展性。
这其中包括魔兽争霸地图、魔兽世界、博德之门、愤怒的小鸟等
众多游戏插件或外挂。

Lua脚本在redis的优势
	将复杂的或者多步的redis操作,写为一个脚本,
	一次提交给redis执行,减少反复连接redis的次数。提升性能。
	
	LUA脚本是类似redis事务,有一定的原子性,
	不会被其他命令插队,可以完成一些redis事务性的操作。
	但是redis的lua脚本功能只有在2.6以后的版本才可以使用

redis持久化

Redis 提供了2个不同形式的持久化方式。
	RDB (Redis DataBase)
	AOF (Append Of File)

RDB

	在指定的时间间隔内将内存中的数据集快照写入磁盘,
	也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。

	备份是如何执行的
		Redis会单独创建(fork)一个子进程来进行持久化,
		会先将数据写入到一个临时文件中,待持久化过程都结束了,
		再用这个临时文件替换上次持久化好的文件。
		整个过程中,主进程是不进行任何IO操作的,
		这就确保了极高的性能如果需要进行大规模数据的恢复,
		且对于数据恢复的完整性不是非常敏感,
		那RDB方式要比AOF方式更加的高效。
		RDB的缺点是最后一次持久化后的数据可能丢失。
		 因为RDB持久化是按照持久化策略进行持久化的,比如什么
		 在100秒内修改了10次就进行持久化,但是最后一次持久化后
		 在100秒内修改了2,不满足策略,现在这时候不正常关机
		 (正常的redis关掉是会进行持久化的),最后的数据就会丢失
关于fork
	在Linux程序中,fork()会产生一个和父进程完全相同的子进程,
	但子进程在此后多会exec系统调用,出于效率考虑,
	Linux中引入了“写时复制技术”,
	一般情况父进程和子进程会共用同一段物理内存,
	只有进程空间的各段的内容要发生变化时,
	才会将父进程的内容复制一份给子进程。
对应配置文件的配置项
RDB保存的文件
	在redis.conf中配置文件名称,默认是dump.rdb,
	默认配置的是:dbfilename dump.rdb

rdb文件的保存路径,默认是redis启动时命令行所在的目录下
	默认配置:dir ./

rdb的保存策略
	比如:
		save 900 1
		save 300 10
		save 60 10000
	对应900秒内修改一次进行持久化
	300秒内修改10次进行持久化
	60秒内修改10000进行持久化

手动保存快照
	命令save: 只管保存,其它不管,全部阻塞
	save vs bgsave

stop-writes-on-bgsave-error yes
	当Redis无法写入磁盘的话,直接关掉Redis的写操作

rdbcompression yes
	进行rdb保存时,将文件压缩

rdbchecksum yes
	在存储快照后,还可以让Redis使用CRC64算法来进行数据校验,
	但是这样做会增加大约10%的性能消耗,
	如果希望获取到最大的性能提升,可以关闭此功能
rdb的恢复
关闭Redis
先把备份的文件拷贝到工作目录下
启动Redis, 备份数据会直接加载
rdb的优点
	节省磁盘空间
	恢复速度快
	rdb保存的是数据,aof保存的是指令

rdb的缺点
	虽然Redis在fork时使用了写时拷贝技术,
	但是如果数据庞大时还是比较消耗性能。
	在备份周期在一定间隔时间做一次备份,
	所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。

AOF

以日志的形式来记录每个写操作,
将Redis执行过的所有写指令记录下来(读操作不记录),
只许追加文件但不可以改写文件,
Redis启动之初会读取该文件重新构建数据,
换言之,Redis重启的话就根据日志文件的内容将写指令
从前到后执行一次以完成数据的恢复工作。
AOF默认不开启,需要手动在配置文件中配置
	就是在配置文件里面修改成appendonly yes
	
可以在redis.conf中配置文件名称,默认为 appendonly.aof 
	默认是:appendfilename "appendonly.aof
	
AOF文件的保存路径,同RDB的路径一致。
AOF和RDB同时开启,redis听aof的
AOF文件故障备份
	AOF的备份机制和性能虽然和RDB不同, 
	但是备份和恢复的操作同RDB一样,都是拷贝备份文件,
	需要恢复时再拷贝到Redis工作目录下,启动系统即加载。

如遇到AOF文件损坏,可通过
     redis-check-aof  --fix  appendonly.aof   进行恢复

AOF同步频率设置
	始终同步,每次Redis的写入都会立刻记入日志 对应配置:appendfsync always
 	每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。对应配置:appendfsync everysec
	把不主动进行同步,把同步时机交给操作系统。 对应配置:appendfsync no
Rewrite
	AOF采用文件追加方式,文件会越来越大为避免出现此种情况,
	新增了重写机制,当AOF文件的大小超过所设定的阈值时,
	Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.
	可以使用命令bgrewriteaof。
	就是如果你设置set a a,然后set a b,然后set a c
	最后保存的指令就是set a c

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

	何时重写
		重写虽然可以节约大量磁盘空间,减少恢复时间。
		但是每次重写还是有一定的负担的,
		因此设定Redis要满足一定条件才会进行重写。
		系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,
		设为base_size,
		如果Redis的AOF当前大小>= base_size +base_size*100% (默认)
		且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写。

在这里插入图片描述

AOF的优点
	备份机制更稳健,丢失数据概率更低。
	可读的日志文本,通过操作AOF稳健,可以处理误操作。
AOF的缺点
	比起RDB占用更多的磁盘空间。
	恢复备份速度要慢。
	每次读写都同步的话,有一定的性能压力。
	存在个别Bug,造成恢复不能。
用哪个好
	官方推荐两个都启用。
	如果对数据不敏感,可以选单独用RDB。
	不建议单独用 AOF,因为可能会出现Bug。
	如果只是做纯内存缓存,可以都不用。

Redis的主从复制

主从复制,就是主机数据更新后根据配置和策略,
自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主
用处
	读写分离,性能扩展
	容灾快速恢复

在这里插入图片描述

配从(服务器)不配主(服务器):
	拷贝多个redis.conf文件include,就是将一些一样的配置集中起来
	开启daemonize yes,开启后台运行
	Pid文件名字pidfile 
	指定端口port,端口号不能冲突
	Log文件名字
	Dump.rdb名字dbfilename,让它和主服务的文件名不一样 
	Appendonly 关掉或者换名字

info replication
	打印主从复制的相关信息

在从服务器里面配置下面这个命令就行了
slaveof  <ip>  <port>  
	成为某个实例的从服务器

上面在命令行里面配置是临时的,就是保存在内存里面的,
如果想长久配置,得在配置文件里面配置才行
slaveof <masterip> <masterport>
细节:
	1.如果一个从服务器掉线了,然后主服务器又写了很多,然后从服务器过段时间
		开启,然后从服务器要成为主服务器的从服务器,这样后,主服务器的
		所有的数据从服务器都有,包括它掉线的数据
	
	2.主机shutdown后情况如何?从机是上位还是原地待命
		原地待命

复制原理

 每次从机联通后,都会给主机发送sync指令
 主机立刻进行存盘操作,发送RDB文件,给从机
 从机收到RDB文件后,进行全盘加载
 之后每次主机的写操作,都会立刻发送给从机,从机执行相同的命令

薪火相传

上一个slave可以是下一个slave的Master,
slave同样可以接收其他slaves的连接和同步请求,
那么该slave作为了链条中下一个的master, 
可以有效减轻master的写压力,去中心化降低风险。
用 slaveof  <ip>  <port>
中途变更转向:会清除之前的数据,重新建立拷贝最新的
风险是一旦某个slave宕机,后面的slave都没法备份
如果最上面的主服务器掉线,中间那个从服务器可以使用slaveof no one
命令来变成主服务区,然后又可以进行写的操作,就是下面的反客为主

在这里插入图片描述

反客为主

 当一个master宕机后,后面的slave可以立刻升为master,
 其后面的slave不用做任何修改。。
用 slaveof  no one  将从机变为主机。

哨兵模式(sentinel)

反客为主的自动版,能够后台监控主机是否故障,
如果故障了根据投票数自动将从库转换为主库.
配置哨兵
	调整为一主二仆三哨兵模式
	自定义的/myredis目录下新建sentinel.conf文件
	在配置文件中填写内容:
		sentinel  monitor  mymaster  127.0.0.1  6379  1
		其中mymaster为监控对象起的服务器名称, 
		1 为 至少有多少个哨兵同意迁移的数量。 

启动哨兵
	执行redis-sentinel  /myredis/sentinel.conf 

故障恢复

新主登基
	从下线的主服务的所有从服务里面挑选一个从,
	将其转成主服务服务
	选择条件依次为:
	1、选择优先级靠前的
	2、选择偏移量最大的
	3、选择runid最小的从服务
		优先级在redis.conf中slave-priority 100
		偏移量是指获得原主数据最多的
		每个redis实例启动后都会随机生成一个40位的runid
群仆俯首
	挑选出新的主服务之后,sentinel 向原主服务的
	从服务发送 slaveof 新主服务 的命令,复制新master
旧主俯首
	当已下线的服务重新上线时,sentinel会向其发送slaveof命令,
	让其成为新主的从

redis集群

解决redis的内存问题
Redis 集群实现了对Redis的水平扩容,即启动N个redis节点,
将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。

Redis 集群通过分区(partition)来提供一定程度的可用性(availability):
即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。

安装ruby环境

执行yum install ruby
执行yum install rubygems

集群

制作6个实例,6379,6380,6381,6389,6390,6391
		拷贝多个redis.conf文件
		开启daemonize yes
		Pid文件名字
		指定端口
		Log文件名字
		Dump.rdb名字
		Appendonly 关掉或者换名字

在每个实例里面还需要配置
	cluster-enabled yes    打开集群模式
	cluster-config-file  nodes-6379.conf  设定节点配置文件名
	cluster-node-timeout 15000   设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换。

组合之前,请确保所有redis实例启动后,nodes-xxxx.conf文件都生成正常。
合体:
	1	cd  /opt/redis-3.2.5/src
	2	./redis-trib.rb create --replicas 1 192.168.1.100:6379 192.168.1.100:6380 192.168.1.100:6381 192.168.1.100:6389 192.168.1.100:6390 192.168.1.100:6391

通过 cluster nodes 命令查看集群信息
一个集群至少要有三个主节点。
	选项 --replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
	分配原则尽量保证每个主数据库运行在不同的IP地址,
		每个从库和主库不在一个IP地址上。

什么是slots
	一个 Redis 集群包含 16384 个插槽(hash slot), 
	数据库中的每个键都属于这 16384 个插槽的其中一个, 
	集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 
	其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。

集群中的每个节点负责处理一部分插槽。 
举个例子, 如果一个集群可以有主节点, 其中:
        节点 A 负责处理 0 号至 5500 号插槽。
        节点 B 负责处理 5501 号至 11000 号插槽。
        节点 C 负责处理 11001 号至 16383 号插槽。
在集群中录入值
在redis-cli每次录入、查询键值,redis都会计算出该key应该送往的插槽,
如果不是该客户端对应服务器的插槽,redis会报错,
并告知应前往的redis实例地址和端口。

redis-cli客户端提供了 –c 参数实现自动重定向。
     如 redis-cli  -c –p 6379 登入后,再录入、查询键值对可以自动重定向。

不在一个slot下的键值,是不能使用mget,mset等多键操作。

可以通过{}来定义组的概念,从而使key中{}内相同内容的键值对放到一个slot中去。

查询集群中的值
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。

CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。  

CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。

故障恢复
如果主节点下线?从节点能否自动升为主节点?
	可以的

主节点恢复后,主从关系会如何?
	变为从节点

如果所有某一段插槽的主从节点都宕掉,redis服务是否还能继续?
	不能继续
集群的Jedis开发
public class JedisClusterTest {

  public static void main(String[] args) {
 
     Set<HostAndPort> set =new HashSet<HostAndPort>();
     set.add(new HostAndPort("192.168.1.100",6379));
     JedisCluster jedisCluster=new JedisCluster(set);

     jedisCluster.set("k1", "v1");
     System.out.println(jedisCluster.get("k1"));
  }
}
Redis 集群提供了以下好处:
	实现扩容
	分摊压力
	无中心配置相对简单

Redis 集群的不足:
	多键操作是不被支持的 
	多键的Redis事务是不被支持的。lua脚本不被支持。
	由于集群方案出现较晚,很多公司已经采用了其他的集群方案,
		而代理或者客户端分片的方案想要迁移至redis cluster,
		需要整体迁移而不是逐步过渡,复杂度较大。
		
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReflectMirroring

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值