当前位置:首页 » 操作系统 » 数据库分布式锁

数据库分布式锁

发布时间: 2024-06-11 20:51:36

1. 高并发没锁可不行,三种分布式锁详解

Java中的锁主要包括synchronized锁和JUC包中的锁,这些锁都是针对单个JVM实例上的锁,对于分布式环境如果我们需要加锁就显得无能为力。在单个JVM实例上,锁的竞争者通常是一些不同的线程,而在分布式环境中,锁的竞争者通常是一些不同的线程或者进程。如何实现在分布式环境中对一个对象进行加锁呢?答案就是分布式锁。

目前分布式锁的实现方案主要包括三种:

基于数据库实现分布式锁主要是利用数据库的唯一索引来实现,唯一索引天然具有排他性,这刚好符合我们对锁的要求:同一时刻只能允许一个竞争者获取锁。加锁时我们在数据库中插入一条锁记录,利用业务id进行防重。当第一个竞争者加锁成功后,第二个竞争者再来加锁就会抛出唯一索引冲突,如果抛出这个异常,我们就判定当前竞争者加锁失败。防重业务id需要我们自己来定义,例如我们的锁对象是一个方法,则我们的业务防重id就是这个方法的名字,如果锁定的对象是一个类,则业务防重id就是这个类名。

基于缓存实现分布式锁:理论上来说使用缓存来实现分布式锁的效率最高,加锁速度最快,因为Redis几乎都是纯内存操作,而基于数据库的方案和基于Zookeeper的方案都会涉及到磁盘文件IO,效率相对低下。一般使用Redis来实现分布式锁都是利用Redis的 SETNX key value 这个命令,只有当key不存在时才会执行成功,如果key已经存在则命令执行失败。

基于Zookeeper:Zookeeper一般用作配置中心,其实现分布式锁的原理和Redis类似,我们在Zookeeper中创建瞬时节点,利用节点不能重复创建的特性来保证排他性。

在实现分布式锁的时候我们需要考虑一些问题,例如:分布式锁是否可重入,分布式锁的释放时机,分布式锁服务端是否有单点问题等。

上面已经分析了基于数据库实现分布式锁的基本原理:通过唯一索引保持排他性,加锁时插入一条记录,解锁是删除这条记录。下面我们就简要实现一下基于数据库的分布式锁。

id字段是数据库的自增id,unique_mutex字段就是我们的防重id,也就是加锁的对象,此对象唯一。在这张表上我们加了一个唯一索引,保证unique_mutex唯一性。holder_id代表竞争到锁的持有者id。

如果当前sql执行成功代表加锁成功,如果抛出唯一索引异常(DuplicatedKeyException)则代表加锁失败,当前锁已经被其他竞争者获取。

解锁很简单,直接删除此条记录即可。

是否可重入 :就以上的方案来说,我们实现的分布式锁是不可重入的,即是是同一个竞争者,在获取锁后未释放锁之前再来加锁,一样会加锁失败,因此是不可重入的。解决不可重入问题也很简单:加锁时判断记录中是否存在unique_mutex的记录,如果存在且holder_id和当前竞争者id相同,则加锁成功。这样就可以解决不可重入问题。

锁释放时机 :设想如果一个竞争者获取锁时候,进程挂了,此时distributed_lock表中的这条记录就会一直存在,其他竞争者无法加锁。为了解决这个问题,每次加锁之前我们先判断已经存在的记录的创建时间和当前系统时间之间的差是否已经超过超时时间,如果已经超过则先删除这条记录,再插入新的记录。另外在解锁时,必须是锁的持有者来解锁,其他竞争者无法解锁。这点可以通过holder_id字段来判定。

数据库单点问题 :单个数据库容易产生单点问题:如果数据库挂了,我们的锁服务就挂了。对于这个问题,可以考虑实现数据库的高可用方案,例如MySQL的MHA高可用解决方案。

使用Jedis来和Redis通信。

可以看到,我们加锁就一行代码:
jedis.set(String key, String value, String nxxx, String expx, int time);
这个set()方法一共五个形参:
第一个为key,我们使用key来当锁,因为key是唯一的。
第二个为value,这里写的是锁竞争者的id,在解锁时,我们需要判断当前解锁的竞争者id是否为锁持有者。
第三个为nxxx,这个参数我们填的是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作。
第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期时间的设置,具体时间由第五个参数决定;
第五个参数为time,与第四个参数相呼应,代表key的过期时间。
总的来说,执行上面的set()方法就只会导致两种结果:1.当前没有锁(key不存在),那么久进行加锁操作,并对锁设置一个有效期,同时value表示加锁的客户端。2.已经有锁存在,不做任何操作。
上述解锁请求中, SET_IF_NOT_EXIST (不存在则执行)保证了加锁请求的排他性,缓存超时机制保证了即使一个竞争者加锁之后挂了,也不会产生死锁问题:超时之后其他竞争者依然可以获取锁。通过设置value为竞争者的id,保证了只有锁的持有者才能来解锁,否则任何竞争者都能解锁,那岂不是乱套了。

解锁的步骤:

注意到这里解锁其实是分为2个步骤,涉及到解锁操作的一个原子性操作问题。这也是为什么我们解锁的时候用Lua脚本来实现,因为Lua脚本可以保证操作的原子性。那么这里为什么需要保证这两个步骤的操作是原子操作呢?
设想:假设当前锁的持有者是竞争者1,竞争者1来解锁,成功执行第1步,判断自己就是锁持有者,这是还未执行第2步。这是锁过期了,然后竞争者2对这个key进行了加锁。加锁完成后,竞争者1又来执行第2步,此时错误产生了:竞争者1解锁了不属于自己持有的锁。可能会有人问为什么竞争者1执行完第1步之后突然停止了呢?这个问题其实很好回答,例如竞争者1所在的JVM发生了GC停顿,导致竞争者1的线程停顿。这样的情况发生的概率很低,但是请记住即使只有万分之一的概率,在线上环境中完全可能发生。因此必须保证这两个步骤的操作是原子操作。

是否可重入 :以上实现的锁是不可重入的,如果需要实现可重入,在 SET_IF_NOT_EXIST 之后,再判断key对应的value是否为当前竞争者id,如果是返回加锁成功,否则失败。

锁释放时机 :加锁时我们设置了key的超时,当超时后,如果还未解锁,则自动删除key达到解锁的目的。如果一个竞争者获取锁之后挂了,我们的锁服务最多也就在超时时间的这段时间之内不可用。

Redis单点问题 :如果需要保证锁服务的高可用,可以对Redis做高可用方案:Redis集群+主从切换。目前都有比较成熟的解决方案。

利用Zookeeper创建临时有序节点来实现分布式锁:

其基本思想类似于AQS中的等待队列,将请求排队处理。其流程图如下:


解决不可重入 :客户端加锁时将主机和线程信息写入锁中,下一次再来加锁时直接和序列最小的节点对比,如果相同,则加锁成功,锁重入。

锁释放时机 :由于我们创建的节点是顺序临时节点,当客户端获取锁成功之后突然session会话断开,ZK会自动删除这个临时节点。

单点问题 :ZK是集群部署的,主要一半以上的机器存活,就可以保证服务可用性。

Zookeeper第三方客户端curator中已经实现了基于Zookeeper的分布式锁。利用curator加锁和解锁的代码如下:

2. 鍒嗗竷寮忛挛镄勫疄鐜版柟寮

鍒嗗竷寮忛挛镄勫疄鐜版柟寮忎富瑕佸寘𨰾锘轰簬鏁版嵁搴撱佸熀浜庣紦瀛樼郴缁熴佸熀浜屿ookeeper绛夊嚑绉嶆柟娉曘

棣栧厛锛屽熀浜庢暟鎹搴撶殑鍒嗗竷寮忛挛瀹炵幇锛屽彲浠ュ埄鐢ㄦ暟鎹搴撶殑鍞涓绱㈠紩鎴栦富阌绾︽潫𨱒ュ疄鐜伴挛镄勫姛鑳姐备緥濡傦纴鍦ㄦ暟鎹搴扑腑鍒涘缓涓涓鍖呭惈鍞涓绱㈠紩镄勮〃锛屽綋闇瑕佸姞阌佹椂锛屽皾璇曞悜璇ヨ〃涓鎻掑叆涓𨱒¤板綍銆傜敱浜庡敮涓绱㈠紩镄勫瓨鍦锛屽彧链夌涓涓鎻掑叆镄勬搷浣滆兘澶熸垚锷燂纴钖庣画鎻掑叆镎崭綔灏呜阒诲炴垨杩斿洖澶辫触锛屼粠钥屽疄鐜伴挛镄勬晥鏋溿傝繖绉嶆柟寮忕殑浼樼偣鏄绠鍗曟槗琛岋纴浣嗙己镣规槸镐ц兘鍙鑳藉弹鍒版暟鎹搴撴ц兘镄勫奖鍝嶏纴涓斿湪楂桦苟鍙戝満鏅涓嫔彲鑳借〃鐜颁笉浣炽

鍏舵★纴锘轰簬缂揿瓨绯荤粺镄勫垎甯冨纺阌侊纴濡俣edis锛屾槸鍙︿竴绉嶅父瑙佺殑瀹炵幇鏂瑰纺銆俣edis鎻愪緵浜唖etnx锛坰et if not exist锛夊懡浠わ纴鍙浠ュ师瀛愭у湴璁剧疆涓涓猭ey镄勫硷纴骞惰繑锲炴槸钖﹁剧疆鎴愬姛銆傚埄鐢ㄨ繖涓鐗规э纴鍙浠ュ皢key浣滀负阌佺殑镙囧织锛屽綋闇瑕佸姞阌佹椂锛屽皾璇曡剧疆璇key銆傚傛灉璁剧疆鎴愬姛锛屽垯琛ㄧず銮峰彇鍒颁简阌侊绂濡傛灉璁剧疆澶辫触锛屽垯琛ㄧず阌佸凡琚鍏朵粬瀹㈡埛绔鍗犵敤銆傛ゅ栵纴Redis杩樻敮鎸佽剧疆key镄勮繃链熸椂闂达纴浠庤岄伩鍏嶆婚挛镄勬儏鍐点傝繖绉嶆柟寮忕殑浼樼偣鏄镐ц兘杈冮珮锛岄傜敤浜庨珮骞跺彂鍦烘櫙锛屼絾闇瑕侀濆栫殑Redis链嶅姟鏀鎸併

链钖庯纴锘轰簬Zookeeper镄勫垎甯冨纺阌佸疄鐜颁篃鏄涓绉嶅彲闱犵殑阃夋嫨銆俍ookeeper鏄涓涓涓哄垎甯冨纺搴旂敤鎻愪緵楂樻ц兘銆佸彲闱犮佹湁搴忕殑鍗忓悓链嶅姟镄勫紑婧愰”鐩銆傚埄鐢╖ookeeper镄勪复镞惰妭镣瑰拰watch链哄埗锛屽彲浠ュ疄鐜板垎甯冨纺阌併傚叿浣揿湴锛屽綋闇瑕佸姞阌佹椂锛屽湪Zookeeper镄勬寚瀹氲妭镣逛笅鍒涘缓涓涓涓存椂鑺傜偣浣滀负阌佺殑镙囧织銆傜敱浜屿ookeeper镄勮妭镣瑰叿链夊敮涓镐э纴锲犳ゅ彲浠ョ‘淇濆悓涓镞跺埢鍙链変竴涓瀹㈡埛绔鑳藉熷垱寤烘垚锷熴傚悓镞讹纴鍏朵粬瀹㈡埛绔鍙浠ラ氲繃watch链哄埗鐩戝惉璇ヨ妭镣圭殑鍙桦寲锛屼粠钥屽湪阌侀喷鏀炬椂鍙婃椂銮峰彇鍒伴氱煡銆傝繖绉嶆柟寮忕殑浼樼偣鏄鍙闱犳ч珮銆佹敮鎸佸嶆潅镄勫垎甯冨纺鍦烘櫙锛屼絾鐩稿规潵璇村疄鐜伴毦搴︾◢澶с

缁间笂镓杩帮纴鍒嗗竷寮忛挛镄勫疄鐜版柟寮忔湁澶氱嶏纴姣忕嶆柟寮忛兘链夊叾浼樼己镣瑰拰阃傜敤鍦烘櫙銆傚湪瀹为檯搴旂敤涓锛岄渶瑕佹牴鎹鍏蜂綋闇姹傚拰绯荤粺鐜澧冮夋嫨钖堥傜殑瀹炵幇鏂瑰纺銆傚悓镞讹纴涓轰简淇濊瘉鍒嗗竷寮忛挛镄勬g‘镐у拰镐ц兘锛岃缮闇瑕佹敞镒忓勭悊钖勭嶅纾甯告儏鍐点侀伩鍏嶆婚挛绛夐梾棰樸

3. 鍒嗗竷寮忛挛鍙婂叾甯歌佸疄鐜版柟寮

鍦ㄥ垎甯冨纺绯荤粺涓锛屼负浜嗕缭璇佸规暟鎹镄勪慨鏀规湁链缁堜竴镊存э纴阃氩父浣跨敤鍒嗗竷寮忛挛鎴栬呭垎甯冨纺浜嫔姟銆傛瘆濡傚父瑙佺殑澶氢釜绯荤粺钖屾椂淇鏀瑰晢鍝侊纴镞渚濊禆浜庣幇链夋暟鎹涔熻佷慨鏀规暟鎹锛屽傛灉娌℃湁闄愬埗锛岄珮骞跺彂𨱍呭喌涓嫔緢鍙鑳芥渶缁堟暟鎹鏄阌栾镄勚

涓庡崟链洪挛涓嶅悓锛屽垎甯冨纺阌佹洿锷犲嶆潅锛岄渶瑕佽冭槛缃戠粶寤惰繜銆佹湇锷¢樆濉炵瓑锛岄氩父鍏锋湁濡备笅鐗圭偣锛

鍒╃敤鏁版嵁搴扑富阌鍞涓镄勭壒镐э纴鍙浠ュ熀浜庡敮涓涓婚敭淇濊瘉澶氭℃搷浣滃彧链変竴娆℃垚锷熴傚湪鏁版嵁搴扑腑鍒涘缓涓涓琛锛岃〃涓鍖呭惈鏂规硶钖岖瓑瀛楁碉纴骞跺湪鏂规硶钖嶅瓧娈典笂鍒涘缓鍞涓绱㈠紩锛屾兂瑕佹墽琛屾煇涓鏂规硶锛屽氨浣跨敤杩欎釜鏂规硶钖嶅悜琛ㄤ腑鎻掑叆鏁版嵁锛屾垚锷熸彃鍏ュ垯銮峰彇阌侊纴镓ц屽畬鎴愬悗鍒犻櫎瀵瑰簲镄勮屾暟鎹閲婃斁阌併傞喷鏀鹃挛镞讹纴鐩存帴鍒犻櫎鏁版嵁搴撹板綍鍗冲彲銆

姝ゆ柟妗埚瓨鍦ㄧ殑闂棰樻槸寮轰緷璧栨暟鎹搴掳纴瀹规槗褰㈡垚鐑镣癸纴鏁版嵁搴挞挛琛ㄥ艰嚧镄勮秴镞朵细褰卞搷镐ц兘锛屾垨钥呮暟鎹搴揿畷链轰细瀵艰嚧链嶅姟涓嶅彲鐢ㄣ傚苟涓旓纴鏁版嵁搴撴湰韬娌℃湁澶辨晥链哄埗锛屽傛灉浠诲姟宕╂簝浼氩艰嚧鏁版嵁搴扑腑镄勯挛涓嶈兘琚閲婃斁銆傛暟鎹搴撴彃鍏ユ搷浣沧湰韬娌℃湁阒诲炴満鍒讹纴鏁呮棤娉曞疄鐜板垎甯冨纺阌佺殑阒诲炵瓑寰咃纴浠诲姟绾跨▼鍙鑳介渶瑕侀吨澶嶅皾璇曟彃鍏ャ傜敱浜庡敮涓涓婚敭镄勫瓨鍦锛屾寔链夐挛镄勭嚎绋嬩篃镞犳硶閲嶅嶈幏寰楅挛锛屽叾浠栫嚎绋嬬珵浜夐挛镄勮繃绋嬩腑涔熸棤娉曟牴鎹浼桦厛绾ц繘琛屽垎閰嶃

鍦ㄦ暟鎹搴扑腑涓鸿〃澧炲姞涓涓鐗堟湰鍙峰瓧娈碉纴姣忔℃搷浣沧椂鍒ゆ柇鐗堟湰鍙凤纴鍙链夌増链鍙蜂竴镊存墠鑳借繘琛屽瑰簲镄勪慨鏀癸纴淇鏀瑰悗鐗堟湰鍙峰姞 1锛岄氲繃 CAS 镄勬柟寮忚繘琛屼慨鏀广

姝ゅ疄鐜颁细澧炲姞鏁版嵁搴撴搷浣灭殑娆℃暟锛岄珮骞跺彂𨱍呭喌涓嫔彲鑳芥ц兘涓嶅ソ銆

for update鏄涓绉嶈岀骇阌侊纴鍙埚彨鎺掑畠阌侊纴涓镞︾敤鎴峰规煇涓琛屾柦锷犱简琛岀骇锷犻挛锛屽垯璇ョ敤鎴峰彲浠ユ煡璇涔熷彲浠ユ洿鏂拌锷犻挛镄勬暟鎹琛岋纴鍏跺畠鐢ㄦ埛鍙鑳芥煡璇浣嗕笉鑳芥洿鏂拌锷犻挛镄勬暟鎹琛屻傛垜浠鍙浠ヨや负銮峰缑鎺掍粬阌佺殑绾跨▼鍗宠幏寰楀垎甯冨纺阌侊纴浠诲姟镓ц屽畬鎴愬悗阃氲繃 commit 𨱒ラ喷鏀鹃挛銆俧or update 璇鍙ヤ细鍦ㄦ墽琛屾垚锷熷悗绔嫔嵆杩斿洖锛屽湪镓ц屽け璐ユ椂涓鐩村勪簬阒诲炵姸镐侊纴鐩村埌鎴愬姛銆

浣嗘槸 MySQL 浼氩规煡璇㈣繘琛屼紭鍖栵纴鍗充究鍦ㄦ浔浠朵腑浣跨敤浜嗙储寮曞瓧娈碉纴浣嗘槸钖︿娇鐢ㄧ储寮曟潵妫绱㈡暟鎹鏄鐢 MySQL 阃氲繃鍒ゆ柇涓嶅悓镓ц岃″垝镄勪唬浠锋潵鍐冲畾镄勶纴濡傛灉 MySQL 璁や负鍏ㄨ〃镓鏁堢巼镟撮珮锛屾瘆濡傚逛竴浜涘緢灏忕殑琛锛屽畠灏变笉浼氢娇鐢ㄧ储寮曪纴杩欑嶆儏鍐典笅 InnoDB 灏嗕娇鐢ㄨ〃阌侊纴钥屼笉鏄琛岄挛銆

setnx 镄勫惈涔夊氨鏄 SET if Not Exists锛屼富瑕佹湁涓や釜鍙傛暟 setnx(key, value)銆傝ユ柟娉曟槸铡熷瓙镄勶纴濡傛灉 key 涓嶅瓨鍦锛屽垯璁剧疆褰揿墠 key 鎴愬姛锛岃繑锲 1锛涘傛灉褰揿墠 key 宸茬粡瀛桦湪锛屽垯璁剧疆褰揿墠 key 澶辫触锛岃繑锲 0銆俿etnx 锻戒护涓嶈兘璁剧疆 key 镄勮秴镞舵椂闂达纴鍙鑳介氲繃 expire() 𨱒ヨ剧疆銆

阌佺殑瀹炵幇姝ラわ细

杩欎釜鏂规埚傛灉鍦ㄧ涓姝 setnx 镓ц屾垚锷熷悗锛屽湪 expire() 锻戒护镓ц屾垚锷熷墠锛屽彂鐢熶简瀹曟満镄勭幇璞★纴闾d箞灏变緷铹朵细鍑虹幇姝婚挛镄勯梾棰樸

杩欎釜鏂规堟槸瀵逛笂涓涓鏂规堢殑浼桦寲鐗堟湰銆

getset() 锻戒护涓昏佹湁涓や釜鍙傛暟 getset(key锛宯ewValue)銆傝ユ柟娉曟槸铡熷瓙镄勶纴瀵 key 璁剧疆 newValue 杩欎釜鍊硷纴骞朵笖杩斿洖 key 铡熸潵镄勬棫鍊笺傚亣璁 key 铡熸潵鏄涓嶅瓨鍦ㄧ殑锛岄偅涔堥栨℃墽琛岀殑杩斿洖鍊兼槸 null銆

阌佺殑瀹炵幇姝ラわ细

杩欎釜鏂规埚湪浠诲姟澶勭悊瓒呮椂鎴栧彂鐢熷畷链烘椂锛屾棤闇𨰾呭绩阌佽秴镞堕梾棰桡纴涓嬫¤锋眰鍙浠ュ垽鏂鍑哄疄闄呬笂阌佸凡缁忚秴镞朵简銆

zookeeper 鐢卞氢釜鑺傜偣鏋勬垚锛埚崟鏁帮级锛岄噰鐢 zab 涓镊存у岗璁銆傚洜姝ゅ彲浠ュ皢 zk 鐪嬫垚涓涓鍗旷偣缁撴瀯锛屽瑰叾淇鏀规暟鎹鍏跺唴閮ㄨ嚜锷ㄥ皢镓链夎妭镣规暟鎹杩涜屼慨鏀硅屽悗镓嶆彁渚涙煡璇㈡湇锷°

zookeeper 鏁版嵁鏄鐩褰曟爲镄勫舰寮忥纴姣忎釜鐩褰旷О涓 znode锛 znode 涓鍙瀛桦偍鏁版嵁锛堜竴鑸涓嶈秴杩 1M锛夛纴杩桦彲浠ュ湪鍏朵腑澧炲姞瀛愯妭镣广

瀛愯妭镣规湁涓夌岖被鍨嬨

zookeeper 鎻愪緵浜 Watch 链哄埗锛宑lient 鍙浠ョ洃鎺ф疮涓鑺傜偣镄勫彉鍖栵纴褰扑骇鐢熷彉鍖栦细缁 client 浜х敓涓涓浜嬩欢銆

鍙浠ュ埄鐢ㄤ复镞惰妭镣逛笌 watch 链哄埗瀹炵幇鍒嗗竷寮忛挛銆傛疮涓阌佸崰鐢ㄤ竴涓鏅阃氲妭镣 /lock锛屽綋闇瑕佽幏鍙栭挛镞跺湪 /lock 鐩褰曚笅鍒涘缓涓涓涓存椂鑺傜偣锛屽垱寤烘垚锷熷垯琛ㄧず銮峰彇阌佹垚锷燂纴澶辫触鍒 watch/lock 鑺傜偣锛屾湁鍒犻櫎镎崭綔钖庡啀铡讳簤阌併备复镞惰妭镣瑰ソ澶勫湪浜庡綋杩涚▼鎸傛帀钖庨挛镄勮妭镣硅嚜锷ㄥ垹闄や笉浼氩彂鐢熸婚挛銆

缂虹偣鍦ㄤ簬镓链夊彇阌佸け璐ョ殑杩涚▼閮界洃钖鐖惰妭镣癸纴寰埚规槗鍙戠敓缇婄兢鏁埚簲锛屽嵆褰挞喷鏀鹃挛钖庢墍链夌瓑寰呰繘绋嬩竴璧锋潵鍒涘缓鑺傜偣锛屽苟鍙戦噺寰埚ぇ銆

涓涓鍙琛岀殑浼桦寲鏂规堟槸涓婇挛鏀逛负鍒涘缓涓存椂链夊簭鑺傜偣锛屾疮涓涓婇挛镄勮妭镣瑰潎鑳藉垱寤鸿妭镣规垚锷燂纴鍙鏄鍏跺簭鍙蜂笉钖屻傚彧链夊簭鍙锋渶灏忕殑鍙浠ユ嫢链夐挛锛屽傛灉杩欎釜鑺傜偣搴忓彿涓嶆槸链灏忕殑鍒 watch 搴忓彿姣旀湰韬灏忕殑鍓崭竴涓鑺傜偣 (鍏骞抽挛)銆倃atch 浜嬩欢鍒版潵钖庯纴鍐嶆″垽鏂鏄钖﹀簭鍙锋渶灏忋傚彇阌佹垚锷熷垯镓ц屼唬镰侊纴链钖庨喷鏀鹃挛锛埚垹闄よヨ妭镣癸级銆

镐ц兘涓婂彲鑳芥病链夌紦瀛樻湇锷¢偅涔堥珮锛屽洜涓烘疮娆″湪鍒涘缓阌佸拰閲婃斁阌佺殑杩囩▼涓锛岄兘瑕佸姩镐佸垱寤恒侀攒姣佷复镞惰妭镣规潵瀹炵幇阌佸姛鑳姐俩ookeeper 涓鍒涘缓鍜屽垹闄よ妭镣瑰彧鑳介氲繃 Leader 链嶅姟鍣ㄦ潵镓ц岋纴铹跺悗灏嗘暟鎹钖屾ュ埌镓链夌殑 Follower 链哄櫒涓娿

鍒嗗竷寮忛挛姣旇缉澶嶆潅锛屼篃姣旇缉瀹规槗鍙戠敓姝婚挛銆傜洰鍓崭富娴佺殑瀹炵幇鏂瑰纺鍖呮嫭锛

鍒嗗竷寮忛挛鍙婂叾甯歌佸疄鐜版柟寮 - 绋嫔簭涔嫔绩

热点内容
php重命名文件夹 发布:2024-11-26 19:06:01 浏览:18
阿里云ecs服务器无法连接公网ip 发布:2024-11-26 19:01:32 浏览:42
java写helloworld 发布:2024-11-26 19:00:56 浏览:89
c语言递归排列 发布:2024-11-26 18:50:55 浏览:448
密码锁为什么不建议用南孚 发布:2024-11-26 18:45:00 浏览:153
荣耀20s安卓版本在哪里看 发布:2024-11-26 18:26:03 浏览:685
安卓手机前摄像头进灰怎么清理 发布:2024-11-26 18:23:08 浏览:173
kettlejava脚本 发布:2024-11-26 18:05:07 浏览:455
c语言关机命令 发布:2024-11-26 17:59:56 浏览:901
wmi文件夹 发布:2024-11-26 17:55:55 浏览:534