一、Redis数据类型

  1.string

    string是Redis的最基本数据类型,一个key对应一个value,每个value最大可存储512M。string一半用来存图片或者序列化的数据。

  2.hash

    相当于一个string类型的映射表。特别适合用来存储对象。例如可以存储用户信息,用户ID作为hash类型里的每一个key。

    案例:我们这边需要对接微信粉丝的数据到我们自己的平台上,但微信提供的接口只支持单天查询,那么如果我们想要查看最近一个月微信粉丝的状况,就需要循环30次调用微信的接口。一个月勉强还可以接受,那么如果想要查半年,甚至一年呢?那么我们的接口里就需要循环365次调微信的接口,这就会使我们的接口变得非常慢,甚至超时。还有这些数据,比如单天新增粉丝数,是不会变得,而且每天都有一个数据,这样就特别适合存在redis的hash类型里,以日期(2018-10-10)作为hash的key。

  3.list

    list类型是简单的字符串列表,每个列表可以存储232 - 1 个值。可以从头部或者尾部顺序插入数据。list类型可以用来做电商里的秒杀营销系统或关注列表。

  4.set

    set是string类型的无序集合。该集合是通过哈希实现的,添加、删除的复杂度都是O(1),所以查找非常快。

    案例:我们这边是以手机号为唯一标示符,防止重复用户注册,会判断该手机号有没有注册过,那么如果用set类型存储注册过的用户手机号,就会很快判断出该用户是否注册过,而不用去查数据库了。

  5.zset

    和set一样,但zset多了一个score来让set变得有序,且不允许有重复的成员。

    案例:我们这边有一个账户记录需要按记录时间排序,那么就可以将时间戳当作score存储zset中。

二、redis分布式锁

  网上很多redis分布式锁的实现方式不能说错误的,但至少不够严谨,在某些极端情况下是会出问题的。一旦出现问题,还是挺麻烦的事情,所以我们要知道redis分布式锁的正确姿势。

  其实很简单,利用redis的原子性。关于原子性,官方的一段描述为:

  大概意思就是redis执行lua脚本的时候,会被当成一条命令执行,在此期间,不会执行其他命令,所以lua脚本尽量是快脚本而不是慢脚本。

  所以,正确的姿势是:

    public function getDistributeLock($redis, string $key, int $userId, int $expire)
{
$luaScript = <<<LUA
if (redis.call('exists', KEYS[1]) == 0) and redis.call('setex', KEYS[1], ARGV[1], ARGV[2])
then
return 1
else
return 0
end
LUA; return $redis->eval($luaScript, 1, $key, $expire, $userId) > 0 ? true : false;
}

  这里我们把一段lua脚本放到redis的eval方法里执行,这样就可以保证这一段命令的原子性。

  那么如果不用lua脚本,姿势应该是这样的:

    public function wrongGetDistributeLock($redis, string $key, int $userId, int $expire)
{ // 若锁不存在,则加锁
if(!$redis->exists($key) && ($redis->setex($key, $expire, $userId) == 'OK')) {
return true;
} return false;
}

  前面提到过,这种姿势在某些情况下会出问题:如果同时好几个客户端同时请求,同时通过了上面if条件的第一层,那么这时候就会出现多个同时拿到锁,并且前面人的锁会被覆盖。

  然后,正确的解锁姿势是:

    public function releaseDistributeLock($redis, string $key, int $userId)
{
$luaScript = <<<LUA
if redis.call('get', KEYS[1]) == ARGV[1]
then
return redis.call('del', KEYS[1])
else
return 0
end
LUA;
$redis->eval($luaScript, 1, $key, $userId);
}

  同样需要使用lua脚本来达到原子性。那么如果不使用lua脚本的姿势是:

    public function wrongReleaseLock($redis, string $key, int $userId)
{
if($userId == $redis->get($key)) {
$redis->del($key);
}
}

  会有这样一种情况:A请求通过if语句后,这时候这个redis的key刚好过期了,然后B客户端加锁成功,这时候A请求就会把客户端B刚加的锁给解除了。

  虽然我上面提到的两种情况都是很极端、很少出现的。但如果可以用很简单的方法避免掉,so why not?

  上面提到的redis分布式锁,满足了三个特性:

  • 互斥性。同时只能又一个客户端拥有锁
  • 不会发生死锁。 
  • 加锁和解锁的必须是同一个客户端。

  童鞋们,有什么疑问,可以在地下留言哦。

Redis全方位详解--数据类型使用场景和redis分布式锁的正确姿势的更多相关文章

  1. Redis全方位详解--磁盘持久化和容灾备份

    序言 在上一篇博客中,博客介绍了redis的数据类型使用场景和redis分布式锁的正确姿势.我们知道一旦Redis重启,存在redis里面的数据就会全部丢失.所以这篇博客中向大家介绍Redis的磁盘持 ...

  2. 【分布式缓存系列】Redis实现分布式锁的正确姿势

    一.前言 在我们日常工作中,除了Spring和Mybatis外,用到最多无外乎分布式缓存框架——Redis.但是很多工作很多年的朋友对Redis还处于一个最基础的使用和认识.所以我就像把自己对分布式缓 ...

  3. 【分布式缓存系列】集群环境下Redis分布式锁的正确姿势

    一.前言 在上一篇文章中,已经介绍了基于Redis实现分布式锁的正确姿势,但是上篇文章存在一定的缺陷——它加锁只作用在一个Redis节点上,如果通过sentinel保证高可用,如果master节点由于 ...

  4. Redis实现分布式锁的正确姿势

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

  5. 掌握Redis分布式锁的正确姿势

    本文中案例都会在上传到git上,请放心浏览 git地址:https://github.com/muxiaonong/Spring-Cloud/tree/master/order-lock 本文会使用到 ...

  6. Redis分布式锁的正确姿势

    1. 核心代码: import redis.clients.jedis.Jedis; import java.util.Collections; /** * @Author: qijigui * @C ...

  7. Redis学习详解(一):Redis持久化机制之RDB

    Redis的持久化机制有两种:RDB持久化和AOF持久化.因为Redis是一个内存数据库,如果没有合适的持久化机制,那么一旦服务器进程退出,服务器中的数据库状态也会消失.本章介绍RDB持久化机制. R ...

  8. python操作redis用法详解

    python操作redis用法详解 转载地址 1.redis连接 redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用 ...

  9. Redis原理详解

    Redis原理详解 数据类型 Redis最为常用的数据类型主要有以下五种: String Hash List Set Sorted set 在具体描述这几种数据类型之前,我们先通过一张图了解下Redi ...

随机推荐

  1. vue使用百度地图

    1.在百度地图申请密钥:http://lbsyun.baidu.com/ 将 <script type="text/javascript" src="http:// ...

  2. windows 程序员电脑设置

    程序员电脑设置: 1.详细目录 a.在一个文件夹下设为详细信息 b.win7点击"组织"-->"文件夹的搜索选项"-->"查看" ...

  3. Oracle存储过程简单实例

    转自 http://www.cnblogs.com/nicholas_f/articles/1526029.html /*不带任何参数存储过程(输出系统日期)*/create or replace p ...

  4. OpenLDAP权限配置

    安装好了openldap之后,就是对它进行配置了,其中一项就是设置访问控制,限制普通用户只能修改/访问他们能修改/访问的项.这就是ACL需要做的事情. 设置方法 1.可以将 include行放在/et ...

  5. 软工读书笔记 week 7 ——《构建之法》

    总时长近两周的结对项目终于算是结束了,马上要重新开启团队项目.于是这几天决定对<构建之法>一书中与团队项目及需求分析有关的章节进行重点阅读,希望能够从中得到启发,并运用到接下来的团队项目中 ...

  6. 结对作业——随机生成四则运算(Core 第7组)

    结对作业 ——随机生成四则运算(core第7组) 吕佳玲 PB16060145 涂涵越 PB16060282 GITHUB地址 https://github.com/hytu99/homework_2 ...

  7. Typescript 基础知识

    Typescript 就是 Javascript 的超集,所以首先你要知道 Javascript 基础知识 类型注解 类型注解在TypeScript中是记录函数或变量约束的简便方法. // 布尔值 l ...

  8. LeetCode题解之Multiply Strings

    1.题目描述 2.问题分析 按照手算乘法的过程进行计算,首先计算乘法,然后计算加法. 3.代码 string multiply(string num1, string num2) { string s ...

  9. Azure 镜像市场虚拟机映像制作指南

    本指南为 Azure 镜像市场(以下简称 Azure 镜像市场)独立软件供应商介绍制作虚拟机映像并上传到Azure的主要过程. 制作虚拟机映像有两种方式.一种是直接在Azure上申请相应的操作系统虚拟 ...

  10. [C# | WinCE | Solution] 在 WinCE 上访问 SSL 加密后的 WCF SOAP 服务接口出现“未能与远程服务器建立信任关系”

    Scenario: 服务器的 SOAP 使用了 GeoTrust 签名的 EV 证书,WinCE调用时出现“未能与远程服务器建立信任关系”的错误.原因是该 WinCE 设备信任的证书包括 Global ...