2017年11月8日星期三

分布式锁的使用

最近项目碰到一个问题,涉及到分布式锁的使用,场景:多个客户端同时上传文件,server可能同时写文件,由于腾讯云的文件系统(COS:对象存储)对同时多个相同文件上传时,会移动其中一个文件,导致会有一个写失败,因此需要server在写的时候用锁来避免竞争。

同事一开始想的方案是直接用个文件来做锁:任何一个server收到上传请求的时候,会创建一个文件(名字用上传文件名来命名),多个server同时创建文件时,只会有一个创建成功,这样就可以锁住了。然后锁失败的server就反复读这个文件,直到获得锁的一端处理完数据,删除这个文件为止。

这个方案还是有一些问题的:比如如果获取锁的一方挂了,就会导致锁一直不会被销毁,这样其他server就会上传不了文件了。

对于分布式锁,之前用得最多的就是zk了,这次又重新复习了一下分布式锁的内容,网上有几篇文章说的比较好的:
分布式锁的几种实现方式:http://www.hollischuang.com/archives/1716,这篇文章谈到了分布式锁的几个要求:
这把锁要是一把可重入锁(避免死锁)
这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)
有高可用的获取锁和释放锁功能
获取锁和释放锁的性能要好
其实主要是避免死锁,和阻塞,失效时间,性能问题还在其次。文章还对几种锁:数据库锁,缓存锁,zk做了分析。从结论和我们实际应用来看,还是zk比较靠谱一点。

还有一篇文章谈到了redis做分布式锁的问题,里面对锁的机制和问题也做了很深入的分析。
http://zhangtielei.com/posts/blog-redlock-reasoning.html 。最开始我们也考虑过用redis做分布式锁,但是过期时间很不好设置。最后也放弃了redis作为分布式锁的方案。

我们最后用了什么方案呢?没用redis,也没用zk,只是做了简单的重试,这样就基本解决了问题。之所以用这个方案,一个时间成本考虑,一个是从现状分析:并发的情况不多,出现冲突的时候可以重试一下。所以说在分布式领域,有时候很难有完美的技术解决方案,但是根据实际情况可以采用更灵活的方案来解决问题。