go 实现的高性能分布式锁服务,每秒可处理 83 万加锁和解锁请求 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
sujin190
V2EX    Go 编程语言

go 实现的高性能分布式锁服务,每秒可处理 83 万加锁和解锁请求

  •  
  •   sujin190
    snower 2019-03-12 18:33:55 +08:00 6440 次点击
    这是一个创建于 2410 天前的主题,其中的信息可能已经有所发展或是发生改变。
    之前遇到在下单扣费之类的场景需要分布式锁,后来就自己做了一个,优化一段时间,感觉性能还行啊,i5 8g 机器单机每秒可以完成 83 万加锁解锁请求,不得不说写一个好的 benchmark 也很难啊。

    项目地址:

    https://github.com/snower/slock

    除了分布式锁同步场景外,还实现了分布式 Event,分布式 Semaphore,在消息中心、秒杀枪库存、限流都可以比较方便使用了。

    多核性能也不错,可以用到多核,单机测试中,带宽沾满千兆,go 的性能还是好啊。
    第 1 条附言    2019-03-12 21:36:13 +08:00
    好吧,既然如此,我来纠正一下,锁服务,并不是分布式系统用的锁

    小微场景可以简化同步逻辑的,也并不能解决一致性问题,解决在一致性已经得到保证下的同步需求,改善性能,或者跨服务即时标记反馈之类的
    42 条回复    2019-03-14 23:12:36 +08:00
    pifuant
        1
    pifuant  
       2019-03-12 18:38:31 +08:00
    单机分布式锁?
    holyghost
        2
    holyghost  
       2019-03-12 18:39:39 +08:00
    单机分布式锁?
    sujin190
        3
    sujin190  
    OP
       2019-03-12 18:41:00 +08:00
    @pifuant #1
    @holyghost #2 单机 83 万加锁解锁,但是网络服务啊,不是单机用的
    比如 web 场景,多台机器需要同步操作库存扣费啥的
    F281M6Dh8DXpD1g2
        4
    F281M6Dh8DXpD1g2  
       2019-03-12 18:42:42 +08:00
    楼主是不是不知道啥是分布式锁........
    sujin190
        5
    sujin190  
    OP
       2019-03-12 18:44:50 +08:00
    @liprais #4 有什么区别么?重点是不局限必须在同一台机器,而保证原子,无论怎么最终还是需要一个中心来确认
    sujin190
        6
    sujin190  
    OP
       2019-03-12 18:46:37 +08:00
    @liprais #4 而且也只是小服务,主要就是简单,快,针对 web 场景需要同步或是限流之类使用完全没问题啊
    holyghost
        7
    holyghost  
       2019-03-12 18:49:07 +08:00
    @sujin190 有。。。而且肯定不是一个中心来确认
    whatsmyip
        8
    whatsmyip  
       2019-03-12 18:50:57 +08:00
    emmmm
    yangbin9317
        9
    yangbin9317  
       2019-03-12 18:52:49 +08:00 via iPhone
    tql ……
    zealot0630
        10
    zealot0630  
       2019-03-12 18:54:25 +08:00 via Android
    楼主放弃了 CAP 中的 C,然后搞了个毫无实用价值的东西
    sujin190
        11
    sujin190  
    OP
       2019-03-12 18:54:35 +08:00
    @holyghost #7 那可能你是没理解,我这需要的是同步,不是一致性,Paxos 之类的协议都解决的是一致性问题,并不是解决同步问题
    一致性有很多协议可以解决,但是同步无论什么协议,最终都需要一个中心来确认吧
    而且在需要同步的场景中,那么应该是很快速资源消耗很低的方式实现才是
    在简单场景中,很多时候完全可以依赖同步很简单解决一致性问题,但是同步并不是完全用了解决一致性问题的
    zealot0630
        12
    zealot0630  
       2019-03-12 18:55:02 +08:00 via Android
    搞错了 放弃了 A
    sujin190
        13
    sujin190  
    OP
       2019-03-12 18:55:14 +08:00
    @zealot0630 #10 这解决的是同步问题,并不是数据库场景中的一致性问题
    wusatosi
        14
    wusatosi  
       2019-03-12 19:08:01 +08:00
    那要是中心突然下线了怎么办(。)
    pifuant
        15
    pifuant  
       2019-03-12 19:39:21 +08:00
    @sujin190 高可用都保证不了, 这个分布式锁谁敢用?
    sujin190
        16
    sujin190  
    OP
       2019-03-12 19:53:01 +08:00
    @wusatosi #14 同步问题中不是特别怕中心挂的情况吧

    一般来说同步场景都是某一刻同步,比如 a 和 b 在前一刻用 1 中心同步,那么 c 和 d 为啥不能在下一刻用 2 备用中心同步呢,其中产生的一致性问题应该仍然还是由数据库事物或者其他一致性协议来保证

    总的来说,分布式锁其中一个场景应该是想要解决的问题应该是我们在很多时候使用一致性结果来同步的极大资源消耗问题,比如很明显的秒杀场景中,是否还有库存这个状态

    其他的比如扫码登陆时,是否已经扫码不也是一个同步问题么
    sujin190
        17
    sujin190  
    OP
       2019-03-12 19:54:43 +08:00
    @pifuant #15 本来就是小工具啊,解决小微场景中某些用锁可以很方便解决的同步问题,并没有说在大型场景中可以很成熟使用
    wweir
        18
    wweir  
       2019-03-12 19:59:02 +08:00 via Android
    讲个笑话,paxos、raft 没解决同步的问题
    sujin190
        19
    sujin190  
    OP
       2019-03-12 20:01:04 +08:00
    @pifuant #15 不过最近也在考虑也行可以加入 binlog 和集群模式看看,也只是探讨,在很多小微场景确实高可用不是特别突出,简单快速解决问题也挺好不是
    sujin190
        20
    sujin190  
    OP
       2019-03-12 20:01:48 +08:00
    @wweir #18 paxos、raft 解决的是一致性问题吧
    lhx2008
        21
    lhx2008  
       2019-03-12 20:03:41 +08:00 via Android
    如果不用高可用,和 redis 单机锁性能相比何如?应该也没啥优势吧。
    aleung
        22
    aleung  
       2019-03-12 20:03:57 +08:00 via Android
    你说这是高性能锁服务就好了,那么大家还能讨论一下。
    wweir
        23
    wweir  
       2019-03-12 20:06:05 +08:00 via Android
    @sujin190 亲,这边建议您了解一下二(三)步提交、raft log 是什么呢
    sujin190
        24
    sujin190  
    OP
       2019-03-12 20:08:46 +08:00
    @lhx2008 #21 首先 redis 锁没有 wait。。都是延时重试
    sujin190
        25
    sujin190  
    OP
       2019-03-12 20:09:00 +08:00
    @aleung #22 对对对,就是这个意思
    kkeiko
        26
    kkeiko  
       2019-03-12 20:10:20 +08:00
    楼主的代码实践的还不错,但一般来说,秒杀场景首先要求高可用,可以参考淘宝的秒杀系统设计的一些文章。
    lhx2008
        27
    lhx2008  
       2019-03-12 20:10:21 +08:00 via Android
    @sujin190 如果不是走 tcp,有啥意义
    sujin190
        28
    sujin190  
    OP
       2019-03-12 20:11:47 +08:00
    @wweir #23 我知道啊,这难道不是用一致性来解决同步问题么,所以核心还是一致性啊
    这里不是主要讲数据同步,更多是即时状态同步
    sujin190
        29
    sujin190  
    OP
       2019-03-12 20:13:22 +08:00
    @lhx2008 #27 走 tcp 啊,不是单机的库,啥意思?
    aleung
        30
    aleung  
       2019-03-12 20:28:46 +08:00 via Android
    @sujin190 你做的是“给分布式系统使用的锁服务”,而从你的描述中,大家理解的是“锁服务,这个服务本身是分布式的”。你始终还没有理解到这个区别。
    reus
        31
    reus  
       2019-03-12 20:32:39 +08:00   1
    一行测试都没有

    变量名不符合惯例

    目录结构不符合惯例,主程序没法 go get 下载

    不知道标准库的 binary 包,协议处理过于罗嗦

    go vet 发现一处大错,复制了 sync.Mutex

    总而言之,正确性都未能保证,就不要奢谈性能了
    jay1002008
        32
    jay1002008  
       2019-03-12 20:44:58 +08:00
    这个单点问题有点严重
    sujin190
        33
    sujin190  
    OP
       2019-03-12 21:29:19 +08:00
    @reus #31 玩一下,要啥测试啊,麻烦死了
    协议没有用 binary 包,这是故意的,binary 包内部用了反射,性能很差
    至于正确性,正确运行就是正确性
    sujin190
        34
    sujin190  
    OP
       2019-03-12 21:31:09 +08:00
    @aleung #30 那可能是有歧义,没说给分布式系统用的锁,你说的对,锁服务
    wusatosi
        35
    wusatosi  
       2019-03-12 22:15:39 +08:00
    @sujin190
    那假设 a,b,c,d 都在抢一个锁,a 在写入前中心下线,b,c,d 请求锁,这时候换到 node 2,写在了 a 前面怎么办?(。)
    "分布式"标签都在了,没有办法冗余不妥吧...
    reus
        36
    reus  
       2019-03-12 22:43:47 +08:00   2
    @sujin190 没有测试,就说明你没有尽最大努力去保证正确。连复制 sync.Mutex 这种错误都出现了,基本可以说是垃圾代码。嫌麻烦不写测试,却不嫌麻烦不用 binary 包,不知所谓。
    JohnSmith
        37
    JohnSmith  
       2019-03-13 00:39:34 +08:00 via iPhone
    @zealot0630 不应该是 P 吗?分区可用性
    reus
        38
    reus  
       2019-03-13 08:47:45 +08:00
    ./slock.go:118:33: assignment copies lock value to free_result_command_lock: sync.Mutex

    go vet 报的这个错,表示你以为上了锁的地方,实际没有上锁,因为你复制了 sync.Mutex 而不是用同一个。
    我不知道你哪里来的自信,没有测试也敢说“正确运行”
    index90
        39
    index90  
       2019-03-13 11:25:51 +08:00
    不明白没有一致性的分布式锁有什么应用场景
    sujin190
        40
    sujin190  
    OP
       2019-03-13 23:48:28 +08:00
    @wusatosi #35
    @index90 #39
    首先我们认为能够使用外部锁同步的,应该是极其短时且大量相关性不高事件,所以冲突概率不高,其次就算冲突,底层应该还有事物或是 raft 这样的一致性协议保证最终一致性,所以不会造成太大问题,我想已经有很多论文证明过通过一个外部锁解决一致性问题是不可能的,更别说通过外部锁解决外部系统一致性问题更不可能,所以这里同样无法解决

    但是即使如此,外部锁仍有其意义
    在大型系统中,raft 这样的协议解决冲突非常复杂消耗资源,更别说微服务场景中,一致性的产生更加复杂,如果外部锁某些时候确实可以消减一部分的冲突,对系统性能改善或许是有意义的,更别说在平滑系统负载,抗冲击都是有一定的意义

    而在大量的中小型系统中,几乎都是短时任务的场景下,本身系统负载就低,遇到奔溃的几率本身就微乎其微,在复杂度开发周期成本考量下,我想这只是一个工程抉择问题,而且大量单机 redis 场景下,过于考虑高可用其实意义不大吧

    从其他来说,操作系统提供的锁,除了 Lock 还有 Event 和 Semaphore 的吧,以往很多时候我们都用轮询、订阅或是队列来解决这两个问题了,但是在简单场景中,这确实有些复杂,能购用更简单的 Event 和 Semaphore 语义来解决这个问题又有什么不好呢

    总的来说,这其实是一个工程问题,不是学术,更不是一个可以通用的解决方案,在工程中,我们有更多考量,过往积累,实现周期复杂度,成本,维护性等等,所以是否有用还是看整体系统方案,比如云,难道没有单点问题,不会有崩溃不一致问题么,我想事实不可能,但是我们综合考量,确实是最好的

    只是个方案,大家仁者见仁,智者见智就好了,这不是一个通用解决方案,也不是一个学士问题
    sujin190
        41
    sujin190  
    OP
       2019-03-13 23:49:39 +08:00
    @reus #38 好吧,我对 go vet 不太熟,这地方也不是核心锁,所以没注意到了,现在学习到了,已经修改过来了,感谢
    swulling
        42
    swulling  
       2019-03-14 23:12:36 +08:00
    和分布式锁没有半点关系.
    哦不对,有 1/4 的关系,都是锁。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     6344 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 02:10 PVG 10:10 LAX 19:10 JFK 22:10
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86