前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分布式锁是怎么回事

分布式锁是怎么回事

作者头像
普通程序员
发布2019-10-23 11:33:58
9830
发布2019-10-23 11:33:58
举报
文章被收录于专栏:普通程序员

一、需求缘起

之前做微信钱包的项目,许多功能都需要与腾讯微信的前台(App)或后台交互,微信需要一个access_token凭证用于身份验证。

这是微信公众平台对access_token的一段描述

access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。

因此第三方需要一个access_token获取和刷新的中控服务器。而其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则会造成access_token覆盖而影响业务。

中控服务器结果如下图

存在什么问题?中控服务器只有一个,单机。如果中控服务器挂了,所有业务都会受到影响。

改进一下架构,采用两个中控服务器(如下图)。

采用两个中控服务器,能够防止单点故障。但是两个定时器会从微信服务器分别获取access_token,会导致access_token刷新次数增加(微信规定一天只能刷新2000次)。极限情况下还可能导致Cache中的access_token失效(中控服务器1先获取access_token1,中控服务器2后获取access_token2,由于分布式原因,有可能access_token1在access_token2之后才存入Cache)。

需要一个技术手段,确保两个中控服务器,只有一个能够从“微信服务器”获取access_token。分布式锁!

二、怎么做

网上有很多分布式锁的做法,通过zookeeper,redis等软件都能实现。(http://surlymo.iteye.com/blog/2082684)

在这里,采用mysql数据库来实现这个功能。

微信access_token是2小时过期,为了保险起见,每隔1个小时就获取(刷新)一次access_token。

建立一张数据库表t_token_lock(id,refreshtime,version),

id:是主键,分布式锁功能里用来定位某条数据记录

refreshtime:刷新access_token的时间,每更新一次增加1小时(每隔1小时刷新一次)

version:记录更新的版本号,默认从0开始,每更新一次就+1

数据库表中最初存放一条记录(1,2017-03-18 21:00:00,0)

两个中控服务器通过定时器(假设) 每过5分钟访问一次数据库表,执行以下操作:

1、查询数据记录 select id,refreshtime,version from t_token_lock where id=1, 将得到的refreshtime记为lastRefreshtime,version记为lastVersion

2、判断当前时间now是否大于refreshtime 如果是,执行第3步;如果否(还没到刷新时间),结束。

3、更新数据记录 update t_token_lock set refreshtime=lastRefreshtime +1h and version=lastVersion+1 where id=1 and version=lastVersion

只有第3步能够成功更新记录的中控服务器,允许访问微信服务器刷新access_token。分布式锁已经实现了!

三、原理解释

怎么理解这3步实现了分布式锁呢?

两个中控服务器每个5分钟读一次数据,大多数时候,refreshtime>now(refreshtime是设置的未来一个小时的时刻,这一个小时之内的时间访问数据,都是这个结果),这种情况下没到刷新时间,不会刷新acceess_token。

我们只需要讨论临界情况,即查询数据记录时需要刷新access_token的情况。

两个中控服务器的计时器一般是不同步的,多数情况下,两个中控服务器会一前一后(一个执行完了,另一个才执行)的执行这3步。这种情况下,后一个执行这3个步骤的中控服务器,看到的refreshtime已经是1个小时之后,它不会去刷新access_token。

因此,只需要讨论两个中控服务器并发同时执行这3步的时候

当两个中控服务器同时执行了第1步、第2步后,它们会执行第3步更新数据库记录。由于mysql数据库锁的存在,不可能同时更新同一条数据记录。后一个更新记录的中控服务器更新记录时,version字段的值已经被前一个中控服务器+1,因此version=lastVersion的条件不满足,不能成功更新记录。后一个中控服务器也就不会去请求(刷新)access_token。

至此,分布式锁被转化成了mysql的行级锁。那mysql的行级锁又是怎么实现的呢(苦海无边,回头是岸)?不管怎样,mysql在单机上实现锁会容易多了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 普通程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档