需求:
咱们先举个某系统验证的列子:(A渠道系统,业务B系统,外部厂商C系统)
(1)B业务系统调用A渠道系统,验证传入的手机、身份证、姓名三要素是否一致。
(2)A渠道系统再调用外部厂商C系统。
(3)A渠道系统将结果返回给B业务系统。
这3个过程当中,(2)过程,调用外部厂商是须要计费的。
当B业务系统并发量很高时,有100笔相同的三要素校验,因为是相同的三要素,A渠道只要调用一次厂商便可知道结果。为了防止在某一请求还没响应结束的同时,其余请求也去调用外部系统,这个时候就须要加锁处理php
分布式锁的特色
原子性:同一时刻,只能有一个机器的一个线程获得锁;
可重入性:同一对象(如线程、类)能够重复、递归调用该锁而不发生死锁;
可阻塞:在没有得到锁以前,只能阻塞等待直至得到锁;
高可用:哪怕发生程序故障、机器损坏,锁仍然可以获得被获取、被释放;
高性能:获取、释放锁的操做消耗小。redis
要实现:加锁,减锁,锁超时
实现方式能够是:数据库 mc redis 系统文件 zookeeper数据库
我如今就是渠道系统,当100个相同的业务请求传递过来,个人第一个请求要先加锁,而后请求外部厂商系统,等响应结果之后,插入另外一个key中,而后再删除锁。
其余请求先去获取下锁,若是已经存在锁就轮寻等待,若是锁不在了,直接去查询结果。
若是第一个请求失败了,结果并无插入到位,就继续获取锁再去查询外部系统。并发
获取锁:
$redis->set('lock:手机号&身份证&姓名', 1, ['nx', 'ex'=>10]);
释放锁:
就是直接删除这个key
锁超时:
lock的key有超时时间分布式
新版的redis set命令就能够实现分布式锁,能够同时实现若是不存在时才去set和超时时间两项。高并发
<?php $redis=new Redis(); $redis->connect("127.0.0.1",6379); //高并发时防止重复请求 //渠道系统传递过来的key $lockKey='lock:18806767777&37781991111629092&taoshihan'; $resultKey='res:18806767777&37781991111629092&taoshihan'; //若是已经查询过值,能够直接返回 $info=$redis->get($resultKey); if($info){ exit($info); } //若是没有值的,获取锁 $lock=$redis->set($lockKey, 1, ['nx', 'ex'=>10]); if($lock){ //请求外部系统获取结果,好比响应结果比较慢 sleep(8); $info='{"name":"taoshihan"}'; $ret=$redis->set($resultKey,$info); if($ret){ //删除锁 $redis->del($lockKey); exit($info); } } echo "请稍后重试!";