Redis 鍜?Zookeeper 鍒板簳璋佹洿鐗涳紵
Posted 寮€鍙戣€呮妧鏈墠绾?/a>
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis 鍜?Zookeeper 鍒板簳璋佹洿鐗涳紵相关的知识,希望对你有一定的参考价值。
鍦ㄧ湅|鏄熸爣|鐣欒█, 鐪熺埍
涓轰粈涔堢敤鍒嗗竷寮忛攣锛?/span>
鍩轰簬Redis瀹炵幇鍒嗗竷寮忛攣
// 鑾峰彇閿?/span>
// NX鏄寚濡傛灉key涓嶅瓨鍦ㄥ氨鎴愬姛锛宬ey瀛樺湪杩斿洖false锛孭X鍙互鎸囧畾杩囨湡鏃堕棿
SET anyLock unique_value NX PX 30000
// 閲婃斁閿侊細閫氳繃鎵ц涓€娈祃ua鑴氭湰
// 閲婃斁閿佹秹鍙婂埌涓ゆ潯鎸囦护锛岃繖涓ゆ潯鎸囦护涓嶆槸鍘熷瓙鎬х殑
// 闇€瑕佺敤鍒皉edis鐨刲ua鑴氭湰鏀寔鐗规€э紝redis鎵цlua鑴氭湰鏄師瀛愭€х殑
if redis.call( "get",KEYS[ 1]) == ARGV[ 1] then
return redis.call( "del",KEYS[ 1])
else
return 0
end
涓€瀹氳鐢⊿ET key value NX PX milliseconds 鍛戒护
濡傛灉涓嶇敤锛屽厛璁剧疆浜嗗€硷紝鍐嶈缃繃鏈熸椂闂达紝杩欎釜涓嶆槸鍘熷瓙鎬ф搷浣滐紝鏈夊彲鑳藉湪璁剧疆杩囨湡鏃堕棿涔嬪墠瀹曟満锛屼細閫犳垚姝婚攣(key姘镐箙瀛樺湪)
value瑕佸叿鏈夊敮涓€鎬?/span>
杩欎釜鏄负浜嗗湪瑙i攣鐨勬椂鍊欙紝闇€瑕侀獙璇乿alue鏄拰鍔犻攣鐨勪竴鑷存墠鍒犻櫎key銆?/span>
杩欐槸閬垮厤浜嗕竴绉嶆儏鍐碉細鍋囪A鑾峰彇浜嗛攣锛岃繃鏈熸椂闂?0s锛屾鏃?5s涔嬪悗锛岄攣宸茬粡鑷姩閲婃斁浜嗭紝A鍘婚噴鏀鹃攣锛屼絾鏄鏃跺彲鑳紹鑾峰彇浜嗛攣銆侫瀹㈡埛绔氨涓嶈兘鍒犻櫎B鐨勯攣浜嗐€?/span>
鍗曟満妯″紡
master-slave + sentinel閫変妇妯″紡
redis cluster妯″紡
鑾峰彇褰撳墠鏃堕棿鎴筹紝鍗曚綅鏄绉?/span>
杞祦灏濊瘯鍦ㄦ瘡涓猰aster鑺傜偣涓婂垱寤洪攣锛岃繃鏈熸椂闂磋缃緝鐭紝涓€鑸氨鍑犲崄姣
灏濊瘯鍦ㄥぇ澶氭暟鑺傜偣涓婂缓绔嬩竴涓攣锛屾瘮濡?涓妭鐐瑰氨瑕佹眰鏄?涓妭鐐癸紙n / 2 +1锛?/span>
瀹㈡埛绔绠楀缓绔嬪ソ閿佺殑鏃堕棿锛屽鏋滃缓绔嬮攣鐨勬椂闂村皬浜庤秴鏃舵椂闂达紝灏辩畻寤虹珛鎴愬姛浜?/span>
瑕佹槸閿佸缓绔嬪け璐ヤ簡锛岄偅涔堝氨渚濇鍒犻櫎杩欎釜閿?/span>
鍙鍒汉寤虹珛浜嗕竴鎶婂垎甯冨紡閿侊紝浣犲氨寰椾笉鏂疆璇㈠幓灏濊瘯鑾峰彇閿?/span>
鍙︿竴绉嶆柟寮忥細Redisson
SET anyLock unique_value NX PX 30000
Config config = new Config();
config.useClusterServers()
.addNodeAddress( "redis://192.168.31.101:7001")
.addNodeAddress( "redis://192.168.31.101:7002")
.addNodeAddress( "redis://192.168.31.101:7003")
.addNodeAddress( "redis://192.168.31.102:7001")
.addNodeAddress( "redis://192.168.31.102:7002")
.addNodeAddress( "redis://192.168.31.102:7003");
RedissonClient redisson = Redisson.create(config);
RLock lock = redisson.getLock( "anyLock");
lock. lock();
lock.unlock();
redisson鎵€鏈夋寚浠ら兘閫氳繃lua鑴氭湰鎵ц锛宺edis鏀寔lua鑴氭湰鍘熷瓙鎬ф墽琛?/span>
redisson璁剧疆涓€涓猭ey鐨勯粯璁よ繃鏈熸椂闂翠负30s,濡傛灉鏌愪釜瀹㈡埛绔寔鏈変竴涓攣瓒呰繃浜?0s鎬庝箞鍔烇紵
redisson涓湁涓€涓?/span>
watchdog
鐨勬蹇碉紝缈昏瘧杩囨潵灏辨槸鐪嬮棬鐙楋紝瀹冧細鍦ㄤ綘鑾峰彇閿佷箣鍚庯紝姣忛殧10绉掑府浣犳妸key鐨勮秴鏃舵椂闂磋涓?0s杩欐牱鐨勮瘽锛屽氨绠椾竴鐩存寔鏈夐攣涔熶笉浼氬嚭鐜発ey杩囨湡浜嗭紝鍏朵粬绾跨▼鑾峰彇鍒伴攣鐨勯棶棰樹簡銆?/span>
redisson鐨勨€滅湅闂ㄧ嫍鈥濋€昏緫淇濊瘉浜嗘病鏈夋閿佸彂鐢熴€?/span>
(濡傛灉鏈哄櫒瀹曟満浜嗭紝鐪嬮棬鐙椾篃灏辨病浜嗐€傛鏃跺氨涓嶄細寤堕暱key鐨勮繃鏈熸椂闂达紝鍒颁簡30s涔嬪悗灏变細鑷姩杩囨湡浜嗭紝鍏朵粬绾跨▼鍙互鑾峰彇鍒伴攣)
// 鍔犻攣閫昏緫
private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {
if (leaseTime != - 1) {
return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
}
// 璋冪敤涓€娈祃ua鑴氭湰锛岃缃竴浜沰ey銆佽繃鏈熸椂闂?/span>
RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
ttlRemainingFuture.addListener( new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
return;
}
Long ttlRemaining = future.getNow();
// lock acquired
if (ttlRemaining == null) {
// 鐪嬮棬鐙楅€昏緫
scheduleExpirationRenewal(threadId);
}
}
});
return ttlRemainingFuture;
}
<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hset', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);",
Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}
// 鐪嬮棬鐙楁渶缁堜細璋冪敤浜嗚繖閲?/span>
private void scheduleExpirationRenewal(final long threadId) {
if (expirationRenewalMap.containsKey(getEntryName())) {
return;
}
// 杩欎釜浠诲姟浼氬欢杩?0s鎵ц
Timeout task = commandExecutor.getConnectionManager().newTimeout( new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
// 杩欎釜鎿嶄綔浼氬皢key鐨勮繃鏈熸椂闂撮噸鏂拌缃负30s
RFuture<Boolean> future = renewExpirationAsync(threadId);
future.addListener( new FutureListener<Boolean>() {
@Override
public void operationComplete(Future<Boolean> future) throws Exception {
expirationRenewalMap.remove(getEntryName());
if (!future.isSuccess()) {
log.error( "Can't update lock " + getName() + " expiration", future.cause());
return;
}
if (future.getNow()) {
// reschedule itself
// 閫氳繃閫掑綊璋冪敤鏈柟娉曪紝鏃犻檺寰幆寤堕暱杩囨湡鏃堕棿
scheduleExpirationRenewal(threadId);
}
}
});
}
}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
if (expirationRenewalMap.putIfAbsent(getEntryName(), new ExpirationEntry(threadId, task)) != null) {
task.cancel();
}
}
鍙﹀锛宺edisson杩樻彁渚涗簡瀵箁edlock绠楁硶鐨勬敮鎸? 瀹冪殑鐢ㄦ硶涔熷緢绠€鍗曪細 RedissonClient redisson = Redisson.create(config);
RLock lock1 = redisson.getFairLock( "lock1");
RLock lock2 = redisson.getFairLock( "lock2");
RLock lock3 = redisson.getFairLock( "lock3");
RedissonRedLock multiLock = new RedissonRedLock(lock1, lock2, lock3);
multiLock. lock();
multiLock.unlock();
灏忕粨锛?/span>
鏈妭鍒嗘瀽浜嗕娇鐢╮edis浣滀负鍒嗗竷寮忛攣鐨勫叿浣撹惤鍦版柟 妗?/span> 浠ュ強 鍏朵竴浜涘眬闄愭€?/span> 鐒跺悗浠嬬粛浜嗕竴涓猺edis鐨勫鎴风妗嗘灦redisson锛?/span> 杩欎篃鏄垜鎺ㄨ崘澶у浣跨敤鐨勶紝 姣旇嚜宸卞啓浠g爜瀹炵幇浼氬皯care寰堝缁嗚妭銆?/span>
鍩轰簬zookeeper瀹炵幇鍒嗗竷寮忛攣
鏈夊簭鑺傜偣锛氬亣濡傚綋鍓嶆湁涓€涓埗鑺傜偣涓?/span>
/lock
锛屾垜浠彲浠ュ湪杩欎釜鐖惰妭鐐逛笅闈㈠垱寤哄瓙鑺傜偣锛?/span>zookeeper鎻愪緵浜嗕竴涓彲閫夌殑鏈夊簭鐗规€э紝渚嬪鎴戜滑鍙互鍒涘缓瀛愯妭鐐光€?lock/node-鈥濆苟涓旀寚鏄庢湁搴忥紝閭d箞zookeeper鍦ㄧ敓鎴愬瓙鑺傜偣鏃朵細鏍规嵁褰撳墠鐨勫瓙鑺傜偣鏁伴噺鑷姩娣诲姞鏁存暟搴忓彿
涔熷氨鏄锛屽鏋滄槸绗竴涓垱寤虹殑瀛愯妭鐐癸紝閭d箞鐢熸垚鐨勫瓙鑺傜偣涓?/span>
/lock/node-0000000000
锛屼笅涓€涓妭鐐瑰垯涓?/span>/lock/node-0000000001
锛屼緷娆$被鎺ㄣ€?/span>涓存椂鑺傜偣锛氬鎴风鍙互寤虹珛涓€涓复鏃惰妭鐐癸紝鍦ㄤ細璇濈粨鏉熸垨鑰呬細璇濊秴鏃跺悗锛寊ookeeper浼氳嚜鍔ㄥ垹闄よ鑺傜偣銆?/span>
浜嬩欢鐩戝惉锛氬湪璇诲彇鏁版嵁鏃讹紝鎴戜滑鍙互鍚屾椂瀵硅妭鐐硅缃簨浠剁洃鍚紝褰撹妭鐐规暟鎹垨缁撴瀯鍙樺寲鏃讹紝zookeeper浼氶€氱煡瀹㈡埛绔€傚綋鍓峼ookeeper鏈夊涓嬪洓绉嶄簨浠讹細
鑺傜偣鍒涘缓
鑺傜偣鍒犻櫎
鑺傜偣鏁版嵁淇敼
瀛愯妭鐐瑰彉鏇?/span>
浣跨敤zk鐨勪复鏃惰妭鐐瑰拰鏈夊簭鑺傜偣锛屾瘡涓嚎绋嬭幏鍙栭攣灏辨槸鍦▃k鍒涘缓涓€涓复鏃舵湁搴忕殑鑺傜偣锛屾瘮濡傚湪/lock/鐩綍涓嬨€?/span>
鍒涘缓鑺傜偣鎴愬姛鍚庯紝鑾峰彇/lock鐩綍涓嬬殑鎵€鏈変复鏃惰妭鐐癸紝鍐嶅垽鏂綋鍓嶇嚎绋嬪垱寤虹殑鑺傜偣鏄惁鏄墍鏈夌殑鑺傜偣鐨勫簭鍙锋渶灏忕殑鑺傜偣
濡傛灉褰撳墠绾跨▼鍒涘缓鐨勮妭鐐规槸鎵€鏈夎妭鐐瑰簭鍙锋渶灏忕殑鑺傜偣锛屽垯璁や负鑾峰彇閿佹垚鍔熴€?/span>
濡傛灉褰撳墠绾跨▼鍒涘缓鐨勮妭鐐逛笉鏄墍鏈夎妭鐐瑰簭鍙锋渶灏忕殑鑺傜偣锛屽垯瀵硅妭鐐瑰簭鍙风殑鍓嶄竴涓妭鐐规坊鍔犱竴涓簨浠剁洃鍚€?/span>
姣斿褰撳墠绾跨▼鑾峰彇鍒扮殑鑺傜偣搴忓彿涓?/span>
/lock/003
,鐒跺悗鎵€鏈夌殑鑺傜偣鍒楄〃涓?/span>[/lock/001,/lock/002,/lock/003]
,鍒欏/lock/002
杩欎釜鑺傜偣娣诲姞涓€涓簨浠剁洃鍚櫒銆?/span>
/lock/001
閲婃斁浜嗭紝
/lock/002
鐩戝惉鍒版椂闂达紝姝ゆ椂鑺傜偣闆嗗悎涓?/span>
[/lock/002,/lock/003]
,鍒?/span>
/lock/002
涓烘渶灏忓簭鍙疯妭鐐癸紝鑾峰彇鍒伴攣銆?/span>
Curator浠嬬粛
InterProcessMutex interProcessMutex = new InterProcessMutex(client, "/anyLock");
interProcessMutex.acquire();
interProcessMutex.release();
private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception
{
boolean haveTheLock = false;
boolean doDelete = false;
try {
if ( revocable.get() != null ) {
client.getData().usingWatcher(revocableWatcher).forPath(ourPath);
}
while ( (client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock ) {
// 鑾峰彇褰撳墠鎵€鏈夎妭鐐规帓搴忓悗鐨勯泦鍚?/span>
List<String> children = getSortedChildren();
// 鑾峰彇褰撳墠鑺傜偣鐨勫悕绉?/span>
String sequenceNodeName = ourPath.substring(basePath.length() + 1); // +1 to include the slash
// 鍒ゆ柇褰撳墠鑺傜偣鏄惁鏄渶灏忕殑鑺傜偣
PredicateResults predicateResults = driver.getsTheLock(client, children, sequenceNodeName, maxLeases);
if ( predicateResults.getsTheLock() ) {
// 鑾峰彇鍒伴攣
haveTheLock = true;
} else {
// 娌¤幏鍙栧埌閿侊紝瀵瑰綋鍓嶈妭鐐圭殑涓婁竴涓妭鐐规敞鍐屼竴涓洃鍚櫒
String previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();
synchronized( this){
Stat stat = client.checkExists().usingWatcher(watcher).forPath(previousSequencePath);
if ( stat != null ){
if ( millisToWait != null ){
millisToWait -= (System.currentTimeMillis() - startMillis);
startMillis = System.currentTimeMillis();
if ( millisToWait <= 0 ){
doDelete = true; // timed out - delete our node
break;
}
wait(millisToWait);
} else{
wait();
}
}
}
// else it may have been deleted (i.e. lock released). Try to acquire again
}
}
}
catch ( Exception e ) {
doDelete = true;
throw e;
} finally{
if ( doDelete ){
deleteOurPath(ourPath);
}
}
return haveTheLock;
}
涓ょ鏂规鐨勪紭缂虹偣姣旇緝
瀹冭幏鍙栭攣鐨勬柟寮忕畝鍗曠矖鏆达紝鑾峰彇涓嶅埌閿佺洿鎺ヤ笉鏂皾璇曡幏鍙栭攣锛屾瘮杈冩秷鑰楁€ц兘銆?/span>
鍙﹀鏉ヨ鐨勮瘽锛宺edis鐨勮璁″畾浣嶅喅瀹氫簡瀹冪殑鏁版嵁骞朵笉鏄己涓€鑷存€х殑锛屽湪鏌愪簺鏋佺鎯呭喌涓嬶紝鍙兘浼氬嚭鐜伴棶棰樸€傞攣鐨勬ā鍨嬩笉澶熷仴澹?/span>
鍗充究浣跨敤redlock绠楁硶鏉ュ疄鐜帮紝鍦ㄦ煇浜涘鏉傚満鏅笅锛屼篃鏃犳硶淇濊瘉鍏跺疄鐜?00%娌℃湁闂锛屽叧浜巖edlock鐨勮璁哄彲浠ョ湅How to do distributed locking
redis鍒嗗竷寮忛攣锛屽叾瀹為渶瑕佽嚜宸变笉鏂幓灏濊瘯鑾峰彇閿侊紝姣旇緝娑堣€楁€ц兘銆?/span>
zookeeper澶╃敓璁捐瀹氫綅灏辨槸鍒嗗竷寮忓崗璋冿紝寮轰竴鑷存€с€傞攣鐨勬ā鍨嬪仴澹€佺畝鍗曟槗鐢ㄣ€侀€傚悎鍋氬垎甯冨紡閿併€?/span>
濡傛灉鑾峰彇涓嶅埌閿侊紝鍙渶瑕佹坊鍔犱竴涓洃鍚櫒灏卞彲浠ヤ簡锛屼笉鐢ㄤ竴鐩磋疆璇紝鎬ц兘娑堣€楄緝灏忋€?/span>
寤鸿
鍐欏湪鏈€鍚庯細
鏈€鍚庣粰璇昏€呮暣鐞嗕簡涓€浠藉ぇ鍘傞潰璇曠湡棰橈紝闇€瑕佺殑鍙壂鐮佸洖澶嶁€?span class="mq-578">澶у巶闈㈣瘯鈥濊幏鍙栥€?/p>
END
鍚庡彴鍥炲鈥?/span>闈㈣瘯鈥?nbsp;鈥滆祫鏂欌€?nbsp;棰嗗彇涓€浠藉共璐э紝鏁扮櫨鎶€鏈潰璇曟墜鍐岀瓑浣?/span> 寮€鍙戣€呮妧鏈墠绾?锛屾眹闆嗘妧鏈墠绾垮揩璁拰鍏虫敞琛屼笟瓒嬪娍锛屽ぇ鍘傚共璐э紝鏄紑鍙戣€呯粡鍘嗗拰鎴愰暱鐨勪紭绉€鎸囧崡 銆?/span> 鍘嗗彶鎺ㄨ崘
濂芥枃鐐逛釜鍦ㄧ湅鍚э紒
以上是关于Redis 鍜?Zookeeper 鍒板簳璋佹洿鐗涳紵的主要内容,如果未能解决你的问题,请参考以下文章
fastjson鍒板簳鍋氶敊浜嗕粈涔堬紵涓轰粈涔堜細琚绻佺垎鍑烘紡娲烇紵