首页 >> 中医药浴

GO 编程:锁和延时任务子系统

发布时间:2025年11月25日 12:19

标准规范戈中都的CAS来充分利用相同的基本功能且价格更低,大众可以另行想法。

在MMORPG种系统中都,trylock相当是一个好同样。因为大量的goroutine放栓可能亦会造成了CPU无意义的天然资源太多。有一个专有名词用来描述这种放栓的桥段:活栓。

活栓常指的是程序中都看来在但会可执行,但CPU窄周期被太多在放栓,而非可执行使命上,从而程序中都既有的可执行效率极低。活栓的原因有别于起来要麻烦很多。所以在MMORPG桥段下,不建议用到这种栓。

基于Redis的setnx

在分布式桥段下,我们也必需这种“放占”的演算,这时候怎么办呢?我们可以用到redis共享的setnx请求:

package mainimport ( "fmt" "sync" "time" "github.com/go-redis/redis")func incr() { client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB }) var lockKey = "counter_lock" var counterKey = "counter" // lock resp := client.SetNX(lockKey, 1, time.Second*5) lockSuccess, err := resp.Result() if err != nil || !lockSuccess { fmt.Println(err, "lock result: ", lockSuccess) return } // counter ++ getResp := client.Get(counterKey) cntValue, err := getResp.Int64() if err == nil || err == redis.Nil { cntValue++ resp := client.Set(counterKey, cntValue, 0) _, err := resp.Result() if err != nil { // log err println("set value error!") } } println("current counter is ", cntValue) delResp := client.Del(lockKey) unlockSuccess, err := delResp.Result() if err == nil && unlockSuccess> 0 { println("unlock success!") } else { println("unlock failed", err) }}func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() incr() }() } wg.Wait()}

进去开始运行结果:

❯❯❯ go run redis_setnx.go lock result: false lock result: false lock result: false lock result: false lock result: false lock result: false lock result: false lock result: false lock result: falsecurrent counter is 2028unlock success!

通过字符串和可执行结果可以碰到,我们远程初始化setnx开始运行工序上和MMORPG的trylock更为相近,如果获所取栓收场,那么相关的使命演算就不应该之前向前可执行。

setnx很适合于在较高并放桥段下,用来争放一些“唯一”的天然资源。比如现金请注意妹种系统中都租客放起订购,而多个租客亦会对其进行时并放争放。这种桥段我们很难另行缺少完全保持一致的时间段来假定先为后,因为不管是浏览器设备的时间段,还是分布式桥段下的各台驱动器的时间段,都是很难另行在改组后前提错误的时序的。哪怕是我们同一个四楼的炮兵部队,相同的驱动器的种系统时间段可能也亦会有细微的区别。

所以,我们必需缺少于这些允诺到达Redis路由器的时序来要用错误的放栓可用。如果浏览器的网络平台自然环境较为反之亦然,那也根本无法自求多福了。

基于Zookeeperpackage mainimport ( "time" "github.com/samuel/go-zookeeper/zk")func main() { c, _, err := zk.Connect([]string{"127.0.0.1"}, time.Second) //*10) if err != nil { panic(err) } l := zk.NewLock(c, "/lock", zk.WorldACL(zk.PermAll)) err = l.Lock() if err != nil { panic(err) } println("lock succ, do your business logic") time.Sleep(time.Second * 10) // do some thing l.Unlock() println("unlock succ, finish business logic")}

基于ZooKeeper的栓与基于Redis的栓的相同之处在于Lock最终以后亦会一直阻断,这与我们MMORPG桥段中都的mutex.Lock很相近。

其原理也是基于临时Sequence路由器和watch API,例如我们这里用到的是/lock路由器。Lock亦会在该路由器下的路由器以下中都插入自己的值,只要路由器下的侄路由器起因变化,就亦会汇报所有watch该路由器的程序中都。这时候程序中都亦会定期检查局限性路由器下最小的侄路由器的id确实与自己的保持一致。如果保持一致,解释加栓最终了。

这种分布式的阻断栓较为适合于分布式使命调度桥段,但不适合于较高频次持栓时间段窄的放栓桥段。按照Google的Chubby论文里的阐述,基于强保持一致协定的栓受限制于粗粒度的加栓可用。这里的粗粒度常指栓迁出时间段较宽。我们在用到时也应探讨在自己的业务范围桥段中都用到确实恰当。

基于etcd

etcd是分布式种系统中都,基本功能上与ZooKeeper十分相似的接口,这两年愈来愈雨了。右边基于ZooKeeper我们充分利用了分布式阻断栓,基于etcd,也可以充分利用十分相似的基本功能:

package mainimport ( "log" "github.com/zieckey/etcdsync")func main() { m, err := etcdsync.New("/lock", 10, []string{""}) if m == nil || err != nil { log.Printf("etcdsync.New failed") return } err = m.Lock() if err != nil { log.Printf("etcdsync.Lock failed") return } log.Printf("etcdsync.Lock OK") log.Printf("Get the lock. Do something here.") err = m.Unlock() if err != nil { log.Printf("etcdsync.Unlock failed") } else { log.Printf("etcdsync.Unlock OK") }}

etcd中都很难像ZooKeeper那样的Sequence路由器。所以其栓充分利用和基于ZooKeeper充分利用的有所相同。在上述示例字符串中都用到的etcdsync的Lock工序是:

先为定期检查/lock路径下确实有值,如果有值,解释栓以后被别人放了如果很难值,那么只读自己的值。只读最终返回,解释加栓最终。只读时如果路由器被其它路由器只读过了,那么亦会造成了加栓收场,这时候到 3watch /lock下的意外事件,此时遭遇阻断当/lock路径下起因意外事件时,局限性数据流被唤醒。定期检查起因的意外事件确实是移除意外事件(解释栓被所持者亦然动unlock),或者月内意外事件(解释栓月内重新启动)。如果是的话,那么回到 1,放放栓工序。

在在,在etcdv3的API中都官方以后共享了可以并不需要用到的栓API,大众可以查阅etcd的文档要用进一步的研习。

如何同样恰当的栓

业务范围还在MMORPG就可以搞定的极限时,那么按照消费用到也就是说的MMORPG栓建议书就可以。

如果蓬勃放展到了分布式服务阶段,但业务范围消费量很小,qps很小的但会,用到哪种栓建议书都相比之下。如果公司内已有可以用到的ZooKeeper、etcd或者Redis炮兵部队,那么就尽量在不引进原先种系统本体设计火炉叠的但会满足业务范围消费。

业务范围蓬勃放展到都从级的话,就必需从各种因素来重新考虑了。首先为是你的栓确实在任何严峻的条件下都不受限制样本遗漏,如果不受限制,那么就切勿用到Redis的setnx的有趣栓。

对栓样本的稳定性要求极较高的话,那根本无法用到etcd或者ZooKeeper这种通过保持连续性协定前提样本稳定性的栓建议书。但可靠的背面不一定都是较低的旅客量和极较高的延期。必需根据业务范围的极限对其进行时舆论压力测试者,以确保分布式栓所用到的etcd或ZooKeeper炮兵部队可以承受得住实际上的业务范围允诺舆论压力。必需注意的是,etcd和Zookeeper炮兵部队是很难另行通过上升路由器来提较高其性能的。要对其进行时平行扩张,根本无法上升搭建多个炮兵部队来赞成更多的允诺。这亦会进一步提较高对运维和监控的要求。多个炮兵部队可能必需引进proxy,很难proxy那就必需业务范围去根据某个业务范围id来要用分片。如果业务范围以后上直通的但会要用扩张,还要重新考虑样本的动态迁移。这些都不是更容易的事情。

在同样完全保持一致的建议书时,还是必需多加探讨,对几率即已要用预估。

反应时间使命种系统

我们在要用种系统时,很多时候是处理过程实时的使命,允诺来了立刻就处理过程,然后立刻给浏览器以反馈。但有时也亦会遇到非实时的使命,比如断定的时间段点放布助于要公告。或者必需在浏览器要用了一件事情的X分钟/Y两星期后,对其特定高难度,比如汇报、放券等等。

如果业务范围消费量较为小,有时我们也可以通过样本戈因应轮询来对这种使命进行时有趣处理过程,但上了消费量的公司,自然亦会寻找颇为普适的解决建议书来解决这一类原因。

一般有两种基本概念来解决这个原因:

充分利用一套十分相似crontab的分布式时才会使命管理种系统。充分利用一个赞成时才会送达谣言的谣言路由请注意。

两种基本概念进而引申成了一些相同的种系统,但其某种程度是相比之下的。都是必需充分利用一个时才会器(timer)。在MMORPG的桥段下时才会器似乎相当少见,例如我们在和网络平台戈撑腰的时候偶尔亦会初始化SetReadDeadline()formula_,就是在本地创建了一个时才会器,在到达常指明的时间段后,我们亦会收到时才会器的汇报,告诉我们时间段已到。这时候如果加载还很难完成的话,就可以认为起因了网络平台原因,从而中都断加载。

比如说我们从时才会器开始,探寻反应时间使命种系统的充分利用。

时才会器的充分利用

时才会器(timer)的充分利用在工专业人士以后是有解的原因了。类似于的就是时间段火炉和时间段轮。

时间段火炉

最类似于的时间段火炉一般用小顶火炉充分利用,小顶火炉似乎就是一种特殊的二叉树

小顶火炉的益处是什么呢?对于时才会器来说,如果火炉顶特性比局限性的时间段还要大,那么解释火炉内所有特性都比局限性时间段大。进而解释这个总能我们还很难适当对时间段火炉进行时任何处理过程。时才会定期检查的时间段断定性是O(1)。

当我们放掘出火炉顶的特性之比局限性时间段时,那么解释可能以后有一批意外事件以后开始月内了,这时进行时但会的弹成和火炉缩减可用就好。每一次火炉缩减的时间段断定性都是O(LgN)。

Go自身的内置时才会器就是用时间段火炉来充分利用的,不过并很难用到二叉火炉,而是用到了扁平一些的四叉火炉。在最近的版本中都,还加了一些冗余,我们先为不说冗余,先为来进去四叉的小顶火炉长什么样:

小顶火炉的性质,父路由器比其4个侄路由器都小,侄路由器之间很难比如说的体积间的关系要求。

四叉火炉中都特性加班和火炉缩减与二叉火炉很难什么某种程度区别。

时间段轮

用时间段轮来充分利用时才会器时,我们必需请注意述每一个格侄的“孔径”,可以将时间段轮比如说一个计时器,中都心有秒针方向转轴。每次转轴到一个孔径时,我们就必需去放送给该孔径机腹的使命以下确实有以后到期的使命。

从本体上来讲,时间段轮和杂凑请注意很相近,如果我们把杂凑方法请注意述为:即会时间段%时间段轮特性体积。那么这就是一个有趣的杂凑请注意。在杂凑流血冲突时,运用于链请注意机腹杂凑流血冲突的时才会器。

除了这种单层时间段轮,专业人士也有一些时间段轮运用于多层充分利用,这里就不再继续赘述了。

使命放放

有了基本的时才会器充分利用建议书,如果我们开放的是MMORPG种系统,那么就可以撸起袖侄开干了,不过本章我们讨论的是分布式,靠近“分布式”还稍微有一些靠近。

我们还必需把这些“时才会”或是“反应时间”(某种程度也是时才会)使命放放成去。比如说是一种基本概念:

每一个实例整年一两星期,亦会去样本戈里把下一个两星期必需处理过程的时才会使命鱿鱼成来,鱿鱼所取的时候只要所取那些task_id % shard_count = shard_id的那些使命即可。

当这些时才会使命被即会之后必需汇报浏览器内侧,有两种基本概念:

将使命被即会的信息封装为一条谣言,放往谣言路由请注意,由浏览器内侧对谣言路由请注意进行时窃听。对浏览器预先为配置的程序在formula_进行时初始化。

两种建议书相互竞争优缺点,如果运用于1,那么如果谣言路由请注意成失灵亦会造成了整个种系统不可视,当然,现在的谣言路由请注意一般也亦会有自身的较高可视建议书,大多数时候我们不用担心这个原因。其次一般业务范围工序中都间放谣言路由请注意的话亦会造成了反应时间上升,时才会使命若必须在即会后的几十毫秒到几百毫秒内完成,那么运用于谣言路由请注意就亦会有一定的几率。如果运用于2,亦会连带时才会使命种系统的负担。我们知道,MMORPG的时才会器可执行时最怕的就是程序在formula_可执行时间段过长,这样亦会阻断近期的使命可执行。在分布式桥段下,这种忧心依然是受限制的。一个蓄意的业务范围程序在可能就亦会并不需要接踵而来整个时才会使命种系统。所以我们还要重新考虑在程序在的基础上上升经过测试者的加班时间段所设,并且对由浏览器放进的加班时间段要用慎助于的备案。

样本再继续平衡点和因数等回避

当我们的使命可执行炮兵部队有驱动器失灵时,必需对使命进行时助于新分配。按照以后的求模策略,对这台驱动器还很难处理过程的使命进行时助于新分配就较为麻烦了。如果是实际上开始运行的直通上种系统,还要在失灵时的使命平衡点各个方面花更多的于是便。

比如说给成一种基本概念:

我们可以参考Elasticsearch的样本分布本体设计,每份使命样本都有多个原稿,这里理论上两原稿

一份样本虽然有两个所持者,但所持者所持的原稿亦会进行时界定,比如所持的是亦然原稿还也就是说亦然原稿,亦然原稿在示意图中都为摸黑以外,非亦然原稿为但会直通条。

一个使命只亦会在所持亦然原稿的路由器上被可执行。

当有驱动器失灵时,使命样本必需进行时样本再继续平衡点的工作,比如路由器1挂了。

路由器1的样本亦会被迁移到路由器2和路由器3上。

当然,也可以用稍微较为简单一些的基本概念,比如对炮兵部队中都的路由器进行时角色划分,由协调路由器来要用这种失灵时的使命助于新分配工作,重新难以实现较高可视,协调路由器可能也必需有1至2个备用路由器以防不测。

以后所述我们亦会用谣言路由请注意即会对浏览器的汇报,在用到谣言路由请注意时,很多路由请注意是不赞成exactly once的形式化的,这种但会我们必需让浏览器自己来主要职责谣言的去助于或者消费的因数等处理过程。

四川男科医院哪家医院好
贵州生殖感染治疗方法有什么
郑州风湿检查多少钱
南宁白癜风医院专家预约挂号
河南白癜风治疗方法
感染者又增加?新冠的三大知识点一定要知道!
药品说明书
月经疾病
排毒减肥
腹泻

上一篇: 光华股份再一冲击上市:研发实力堪忧、产品得率超理论值

下一篇: 五甲记

友情链接