miaosha/docs/redis-good.md
2018-12-20 12:18:43 +08:00

6.9 KiB
Raw Blame History

redis 使用与进阶

有问题或者宝贵意见联系我的QQ,非常希望你的加入!

目标 希望大家仔细研究redis.conf配置文件-本文很多基础的一带而过)

2.redis分布式锁zk分布式锁,lua脚本使用
3.redis持久化策略
4.redis集群
5.redis的简单操练
整理大部分常用的场景与使用,如果有疑问或者你不懂的地方请联系我!

1 redis分布式锁

1.分布式系统单机的使用ReentrantLock或者synchronized代码块来实现 2.共享资源大并发产生 3.同步访问

redis分布式锁解决什么问题

1.一个进程中的多个线程,多个线程并发访问同一个资源的时候,如何解决线程安全问题。
2.一个分布式架构系统中的两个模块同时去访问一个文件对文件进行读写操作
3.多个应用对同一条数据做修改的时候,如何保证数据的安全性
在但一个进程中我们可以用到synchronized、lock之类的同步操作去解决但是对于分布式架构下多进程的情况下
如何做到跨进程的锁。就需要借助一些第三方手段来完成

设计一个分布式所需要解决的问题,分布式锁解决方案(数据库方案)

数据库解决方式创建一个表叫做LOCK表
lock(
  id  int(11)
  methodName  varchar(100),--锁定的方法名称
  memo varchar(1000) 
  modifyTime timestamp
  unique key mn (method)  --唯一约束
)

在执行方法的时候,获取锁的伪代码 或者for update行锁 或者 乐观锁方式也是可以的
try{
exec  insert into lock(methodName,memo) values(method,desc);
return true;
}Catch(DuplicateException e){
return false;
}

释放锁:
delete from lock where methodName=; 

(数据库方案)存在的问题以及思考

1.锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁
2.锁是非阻塞的数据的insert操作一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列
  要想再次获得锁就要再次触发获得锁操作
3.锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁

ZK方案

ZK方案实现之前你要先了解ZK关于他的节点的几个特性

有序节点:假如当前有一个父节点为/lock我们可以在这个父节点下面创建子节点zookeeper提供了一个可选的有序特性
例如我们可以创建子节点“/lock/node-”并且指明有序那么zookeeper在生成子节点时会根据当前的子节点数量自动添加整数序号
也就是说如果是第一个创建的子节点,那么生成的子节点为/lock/node-0000000000下一个节点则为/lock/node-0000000001依次类推

临时节点客户端可以建立一个临时节点在会话结束或者会话超时后zookeeper会自动删除该节点

事件监听在读取数据时我们可以同时对节点设置事件监听当节点数据或结构变化时zookeeper会通知客户端
当前zookeeper有如下四种事件
1节点创建
2节点删除
3节点数据修改
4子节点变更

获取分布式锁的流程  ------- 假设所空间的根节点为/lock

1.客户端连接zookeeper并在/lock下创建临时的且有序的子节点
第一个客户端对应的子节点为/lock/lock-0000000000第二个为/lock/lock-0000000001以此类推

2.--避免羊群效应--客户端获取/lock下的子节点列表判断自己创建的子节点是否为当前子节点列表中序号最小的子节点
如果是则认为获得锁,否则监听刚好在自己之前一位的子节点删除消息,获得子节点变更通知后重复此步骤直至获得锁

3.实行业务代码

4.流程完成后,删除对应的子节点并释放锁  Watch机制
对应分布式开源包Curator

整体流程

Redis分布式锁方案

 Redis 中有许多的命令都可以实现分布式锁,但是比较常用的是SETNX这个命令来实现
 有多种方案代码:
 1.获取锁,释放锁 代码在redismanager 里面 (简单版)

整体流程

整体流程

closeOrder也有 不过是另一种!比较复杂!!
加入时间对比如果当前时间已经大与释放锁的时间
说明已经可以释放这个锁重新在获取锁setget方法可以把之前的锁去掉在重新获取,旧值在于之前的
值比较如果无变化说明这个期间没有人获取或者操作这个redis锁则可以重新获取

整体流程

redis有成熟的框架redission

Redis多路复用机制看不看都行

 linux的内核会把所有外部设备都看作一个文件来操作对一个文件的读写操作会调用内核提供的系统命令
 返回一个 file descriptor文件描述符。对于一个socket的读写也会有响应的描述符称为socketfd(socket 描述符)。
 而IO多路复用是指内核一旦发现进程指定的一个或者多个文件描述符IO条件准备好以后就通知该进程
 IO多路复用又称为事件驱动操作系统提供了一个功能当某个socket可读或者可写的时候它会给一个通知。
 当配合非阻塞socket使用时只有当系统通知我哪个描述符可读了我才去执行read操作可以保证每次read都能读到有效数据。
 操作系统的功能通过select/pool/epoll/kqueue之类的系统调用函数来使用这些函数可以同时监视多个描述符的读写就绪情况
 这样多个描述符的I/O操作都能在一个线程内并发交替完成这就叫I/O多路复用这里的复用指的是同一个线程
 多路复用的优势在于用户可以在一个线程内同时处理多个socket的 io请求。达到同一个线程同时处理多个IO请求的目的。
 而在同步阻塞模型中,必须通过多线程的方式才能达到目的

Redis2.6以后)--lua脚本

1.	减少网络开销在Lua脚本中可以把多个命令放在同一个脚本中运行
2.	原子操作redis会将整个脚本作为一个整体执行中间不会被其他命令插入。换句话说编写脚本的过程中无需担心会出现竞态条件
3.	复用性客户端发送的脚本会永远存储在redis中这意味着其他客户端可以复用这一脚本来完成同样的逻辑