分布式锁:

  Redis可以实现分布式锁,只是讨论Redis的实现思路,相对来说,Zookeeper实现分布式锁可能更加可靠

为什么使用分布式锁:

  单机环境下只存在多线程,通过同步操作就可以实现对并发环境的安全操作,但是多机环境就变成多进程、多线程,这时候同步、加锁已经无

法保证原子性

实现分布式可靠性的条件:

  1、互斥性。在任意时刻,只有一个客户端能持有锁

  2、不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁

  3、具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁

  4、加锁和解锁必须是同一个客户端

实现分布式锁的方式:

  1、基于DB的唯一索引。

  2、基于ZK的临时有序节点。

  3、基于Redis的NX、EX参数。

代码实现:

public static final String LOCK_SUCCESS = "OK";//加锁成功

public static final String SET_IF_NOT_EXIST = "NX";

public static final String SET_WITH_EXPIRE_TIME = "PX";

public static final Long RELEASE_SUCCESS = 1L;
public class RedisUtils {

    @Autowired
JedisPool jedisPool; /**
* 尝试获取分布式锁
* @param lockKey
* @param requestId
* @param expireTime
* @return
*/
public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(lockKey, requestId, RedisConstant.SET_IF_NOT_EXIST, RedisConstant.SET_WITH_EXPIRE_TIME, expireTime);
if (StringUtils.equals(result, RedisConstant.LOCK_SUCCESS))
return true;
return false;
} /**
* 释放分布式锁
* @param jedis
* @param lockKey
* @param requestId
* @return
*/
public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RedisConstant.RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}

加锁:

  lockKey:唯一的key

  requestId:每个客户端的唯一ID

  NX:保证key不存在才会set

  PX:key具有过期时间

  expireTime:key的具体过期时间

解锁:
  通过lua代码传到jedis.eval()方法里,并使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId。eval()方法是将Lua代码交给Redis服务

端执行。

  首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)。那么为什么要使用Lua语言来实现呢?因为要确保上述

操作是原子性的。

  以上只是针对单机部署Redis,如果Redis是多机部署的,可以采用Redisson实现分布式锁

PS:上面的set方法需要RedisV2.6+支持

无法避免的问题:

  如在 key 超时之后业务并没有执行完毕但却自动释放锁了,这样就会导致并发问题。

  就算 Redis 是集群部署的,如果每个节点都只是 master 没有 slave,那么 master 宕机时该节点上的所有 key 在那一时刻都相当于是释放

锁了,这样也会出现并发问题。就算是有 slave 节点,但如果在数据同步到 salve 之前 master 宕机也是会出现上面的问题。

  Redis分布式锁内容参考:https://xiaozhuanlan.com/topic/4672859130https://redis.io/topics/distlock

基于Redis实现分布式ID:

  因为Redis是单线程的,所以可以用来生成全部唯一ID,通过incr、incrby实现

  生产环境可能是Redis集群,假如有5个Redis实例,每个Redis的初始值是1,2,3,4,5,然后增长都是5

各个Redis生成的ID为:

A:1,6,11,16,21
B:2,7,12,17,22
C:3,8,13,18,23
D:4,9,14,19,24
E:5,10,15,20,25

这样的话,无论请求打到那个Redis上面,都可以获得不同的ID

优点:

  1、不依赖于数据库,灵活方便,且性能优于数据库。

  2、数字ID天然排序,对分页或者需要排序的结果很有帮助。

缺点:

  1、如果系统里没有Redis,就比较操蛋了

  2、编码、配置工作量大一点

分布式ID推荐一篇文章:https://blog.csdn.net/hengyunabc/article/details/44244951

流水号:

  Redis同样可以生成每天的流水号,日期+自增长序号,进行incr

面试题:如何从Redis查询出前缀为id的key?

  首先这个问题应该要明确数据量,如果数据量很小,可以直接使用keys id*,keys命令直接返回所有的key,如果是海量数据,keys命令肯定

不行了,所以要跟面试官明确这个问题。海量数据环境下,例如1亿条数据,可以使用scan命令

scan是基于游标的迭代器,每次使用都要基于上一次的游标延续之前的迭代过程

格式:scan cursor [MATCH pattern] [COUNT count]

cursor以0开始,到0结束,scan 0 match id* count 10,从0开始,匹配以id开头的key,每次返回10条

返回结果有两部分:

1) "0"
2) 1) "id1"
2) "id2"
.......

  1)为返回的游标,返回0证明迭代结束。这里希望返回10条,并不是一定返回10条,可能只是返回5条数据(一次返回的数量不可控,大概率符合

count),如果返回cursor不是0,证明迭代没有结束,可以继续查询,知道返回cursor为0,效率低于keys,但是不会阻塞Redis

PS:scan返回的游标可能后一次比前一次更小,所以可能会出现重复数据,需要外部程序进行去重

Redis系列(二)--分布式锁、分布式ID简单实现及思路的更多相关文章

  1. Redis系列(二):Redis的数据类型及命令操作

    原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...

  2. Redis 分布式锁 - 分布式锁的正确实现方式

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  3. php+redis 学习 二 悲观锁

    <?php header('content-type:text/html;chaeset=utf-8'); /** * redis实战 * * 实现悲观锁机制 * */ $timeout = 5 ...

  4. Redis系列(二):Redis的5种数据结构及其常用命令

    上一篇博客,我们讲解了什么是Redis以及在Windows和Linux环境下安装Redis的方法, 没看过的同学可以点击以下链接查看: Redis系列(一):Redis简介及环境安装. 本篇博客我们来 ...

  5. Redis系列二:reids介绍

    一.什么是redis.redis有哪些特性.redis有哪些应用场景.redis的版本 1. 什么是redis redis是一种基于键值对(key-value)数据库,其中value可以为string ...

  6. Redis系列(二)-Hredis客户端设计及开源

    接上篇c#实现redis客户端(一),重新整理些了下. 阅读目录: 项目说明 Hredis设计图 单元测试场景 总结 项目说明 背景:因为有地方要用,而又没找到对sentinel良好支持的Net客户端 ...

  7. Redis系列二之事务及消息通知

    一.事务 Redis中的事务是一组命令的集合.一个事务中的命令要么都执行,要么都不执行. 1.事务简介 事务的原理是先将一个事务的命令发送给Redis,然后再让Redis依次执行这些命令.下面看一个示 ...

  8. Redis系列二(yum切换为网易163)

    这个可能和Redis没有直接的关系... 是我在yum install的时候发现centos的yum实在是太慢,上网查了下.网易163有个yum镜像,为了让CentOS6使用速度更快的YUM更新源,可 ...

  9. redis系列二: linux下安装redis

    下面介绍在Linux环境下,Redis的安装与配置 一. 安装 1.首先上官网下载Redis 压缩包,地址:http://redis.io/download 下载稳定版3.0即可. 2.通过远程管理工 ...

随机推荐

  1. 调试 Android* x86 应用程序的方法以及要使用的工具

    作者:Xiaodong Wang 1.简单介绍 众所周知,Android* 开发者头顶很多称呼:设计员.程序员等,而且一般会不可避免地被称为故障检修工. 代码中的错误无法避免.因此不管您是否一開始就造 ...

  2. MongoDB 学习笔记一 安装以及基础命令

    一.MongoDB安装配置 1.获取最新版本号: wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.0.2.tgz 2.解压缩就可 ...

  3. 解决burp suite 使用chrome訪问https失真的问题

    用burp suite 訪问https网页 尤其使用chrome(有时候firefox也会) 会出现js或者css载入不出来的情况 这样的时候,导出burp suite的证书,保存为cer格式 然后进 ...

  4. Cannot change version of project facet Dynamic Web Module to 3.1 (Eclipse Maven唯一解决方式)

    If you want to use version 3.1 you need to use the following schema: http://xmlns.jcp.org/xml/ns/jav ...

  5. lydsy1013: [JSOI2008]球形空间产生器sphere 高斯消元

    题链:http://www.lydsy.com/JudgeOnline/problem.php?id=1013 1013: [JSOI2008]球形空间产生器sphere 时间限制: 1 Sec  内 ...

  6. 用Swift语言和Sprite Kit复制微信飞机大战游戏

    先上GitHub链接: https://github.com/songrotek/PlaneWar.git 接下来略微解说一下! 这个程序还有点Bug,见谅! 1 说明 游戏採用了Sprite kit ...

  7. H264 层次构成[2]

    H264层次构成 H264标准是由JVT(Joint Video Team,视频联合工作组)组织提出的新一代数字视频编码标准.JVT于2001年12月在泰国Pattaya成立.它由ITU-T的VCEG ...

  8. [noip模拟赛]算算数

    https://www.zybuluo.com/ysner/note/1298755 题面 有一天小胡同学看到了一种表达式.这个表达式有四个变量\(A,B,C,D\).这四 个变量都只有\(0\)和\ ...

  9. Create schema error (unknown database schema '')

    Andrey Devyatka 4 years ago Permalink Raw Message Hi,Please tell me, can I use the static library in ...

  10. ci完整集成

    http://www.cnblogs.com/zhanchenjin/p/5032218.html http://blog.csdn.net/williamwanglei/article/detail ...