Die Mongod-Implementierung ist hier relativ einfach. Sie erstellt und verwaltet hauptsächlich zwei Sperrsammlungen (Sperren und Sperren) auf dem Konfigurationsserverknoten. Wenn Mongos startet, Es erstellt in jeder dieser beiden Sammlungen einen Datensatz und verwaltet dann den Status des Datensatzes (einschließlich Zeitstempel und Status), um die Sperrnutzung des aktuellen Mongos-Knotens zu identifizieren. Wenn Sie eine Sperre zwischen mehreren Computern verwenden möchten, stellen Sie einfach sicher, dass der Name der Sperre konsistent ist. Dieser Datensatz wird in der entsprechenden Sammlung des configsvr-Knotens gemeinsam genutzt, um sicherzustellen, dass nur ein Mongos-Knoten die Sperre erhält.
Der Code wird auf mehreren Servern bereitgestellt, also verteilt .
Mehrere Prozesse greifen gleichzeitig auf eine gemeinsame Ressource zu.
Datenbank: mongo
Java: Mongo-Operations-Plug-in-Klasse MongoTemplate (Maven-Referenz), wie folgt:
1 <!--mongodo开始--> 2 <dependency> 3 <groupId>org.springframework.data</groupId> 4 <artifactId>spring-data-mongodb</artifactId> 5 <version>1.8.2.RELEASE</version> 6 </dependency> 7 <dependency> 8 <groupId>org.springframework.data</groupId> 9 <artifactId>spring-data-commons</artifactId>10 <version>1.10.0.RELEASE</version>11 </dependency>12 <dependency>13 <groupId>org.mongodb</groupId>14 <artifactId>mongo-java-driver</artifactId>15 <version>2.13.0-rc2</version>16 </dependency>17 <!--mongodo结束-->
Implementiert hauptsächlich Logik und externe Aufrufmethoden, erhält die Sperre durch Aufrufen von getLock und gibt die Sperre durch Aufrufen von releaseLock frei lauten wie folgt:
1 import java.util.HashMap; 2 import java.util.List; 3 import java.util.Map; 4 5 6 public class MongoDistributedLock { 7 8 static MongoLockDao mongoLockDao; 9 10 static {11 mongoLockDao = SpringBeanUtils.getBean("mongoLockDao");12 } /**15 * 获得锁的步骤:16 * 1、首先判断锁是否被其他请求获得;如果没被其他请求获得则往下进行;17 * 2、判断锁资源是否过期,如果过期则释放锁资源;18 * 3.1、尝试获得锁资源,如果value=1,那么获得锁资源正常;(在当前请求已经获得锁的前提下,还可能有其他请求尝试去获得锁,此时会导致当前锁的过期时间被延长,由于延长时间在毫秒级,可以忽略。)19 * 3.2、value>1,则表示当前请求在尝试获取锁资源过程中,其他请求已经获取了锁资源,即当前请求没有获得锁;20 * !!!注意,不需要锁资源时,及时释放锁资源!!!。21 *22 * @param key23 * @param expire24 * @return25 */26 public static boolean getLock(String key, long expire) {27 List<MongoLock> mongoLocks = mongoLockDao.getByKey(key);28 //判断该锁是否被获得,锁已经被其他请求获得,直接返回29 if (mongoLocks.size() > 0 && mongoLocks.get(0).getExpire() >= System.currentTimeMillis()) {30 return false;31 }32 //释放过期的锁33 if (mongoLocks.size() > 0 && mongoLocks.get(0).getExpire() < System.currentTimeMillis()) {34 releaseLockExpire(key, System.currentTimeMillis());35 }36 //!!(在高并发前提下)在当前请求已经获得锁的前提下,还可能有其他请求尝试去获得锁,此时会导致当前锁的过期时间被延长,由于延长时间在毫秒级,可以忽略。37 Map<String, Object> mapResult = mongoLockDao.incrByWithExpire(key, 1, System.currentTimeMillis() + expire);38 //如果结果是1,代表当前请求获得锁39 if ((Integer) mapResult.get("value") == 1) {40 return true;41 //如果结果>1,表示当前请求在获取锁的过程中,锁已被其他请求获得。42 } else if ((Integer) mapResult.get("value") > 1) {43 return false;44 }45 return false;46 }47 48 /**49 * 释放锁50 *51 * @param key52 */53 public static void releaseLock(String key) {54 Map<String, Object> condition = new HashMap<>();55 condition.put("key", key);56 mongoLockDao.remove(condition);57 }58 59 /**60 * 释放过期锁61 *62 * @param key63 * @param expireTime64 */65 private static void releaseLockExpire(String key, long expireTime) {66 mongoLockDao.removeExpire(key, expireTime);67 }68 }
MongoLockDao-Implementierungscode:
1 import org.springframework.data.mongodb.core.FindAndModifyOptions; 2 import org.springframework.data.mongodb.core.query.Criteria; 3 import org.springframework.data.mongodb.core.query.Query; 4 import org.springframework.data.mongodb.core.query.Update; 5 import org.springframework.stereotype.Repository; 6 7 import java.util.HashMap; 8 import java.util.List; 9 import java.util.Map;10 11 12 @Repository13 public class MongoLockDao <MongoLock> {14 private Class<?> clz;15 16 public Class<?> getClz() {17 if (clz == null) {18 //获取泛型的Class对象19 clz = ((Class<?>)20 (((ParameterizedType) (this.getClass().getGenericSuperclass())).getActualTypeArguments()[0]));21 }22 return clz;23 }24 25 /**26 * 返回指定key的数据27 *28 * @param key29 * @return30 */31 public List<MongoLock> getByKey(String key) {32 Query query = new Query();33 query.addCriteria(Criteria.where("key").is(key));34 return (List<MongoLock>) mongoTemplate.find(query, getClz());35 }36 37 38 /**39 * 指定key自增increment(原子加),并设置过期时间40 *41 * @param key42 * @param increment43 * @param expire44 * @return45 */46 public Map<String, Object> incrByWithExpire(String key, double increment, long expire) {47 //筛选48 Query query = new Query();49 query.addCriteria(new Criteria("key").is(key));50 51 //更新52 Update update = new Update();53 update.inc("value", increment);54 update.set("expire", expire);55 //可选项56 FindAndModifyOptions options = FindAndModifyOptions.options();57 //没有则新增58 options.upsert(true);59 //返回更新后的值60 options.returnNew(true);61 Map<String, Object> resultMap = new HashMap<>();62 resultMap.put("value", Double.valueOf(((MongoLock)63 mongoTemplate.findAndModify(query, update, options, getClz())).getValue()).intValue());64 resultMap.put("expire", Long.valueOf(((MongoLock)65 mongoTemplate.findAndModify(query, update, options, getClz())).getExpire()).longValue());66 return resultMap;67 }68 69 70 /**71 * 根据value删除过期的内容72 *73 * @param key74 * @param expireTime75 */76 public void removeExpire(String key, long expireTime) {77 Query query = new Query();78 query.addCriteria(Criteria.where("key").is(key));79 query.addCriteria(Criteria.where("expire").lt(expireTime));80 mongoTemplate.remove(query, getClz());81 }82 83 public void remove(Map<String, Object> condition) {84 Query query = new Query();85 Set<Map.Entry<String, Object>> set = condition.entrySet();86 int flag = 0;87 for (Map.Entry<String, Object> entry : set) {88 query.addCriteria(Criteria.where(entry.getKey()).is(entry.getValue()));89 flag = flag + 1;90 }91 if (flag == 0) {92 query = null;93 }94 mongoTemplate.remove(query, getClz());95 }96 97 }
MongoLock-Entität:
1 public class MongoLock { 2 3 private String key; 4 private double value; 5 private long expire; 6 7 public double getValue() { 8 return value; 9 }10 11 public void setValue(double value) {12 this.value = value;13 }14 15 public long getExpire() {16 return expire;17 }18 19 public void setExpire(long expire) {20 this.expire = expire;21 }22 23 public String getKey() {24 return key;25 }26 27 public void setKey(String key) {28 this.key = key;29 }30 }
Prämisse: Verwenden Sie Mongo, um die Selbstinkrementierung der ID zu realisieren, und der Selbstinkrementierungsprozess ist eine atomare Operation, also threadsicher.
Angenommen, es gibt zwei Anfragen, A und B, die Ressourcen anfordern.
Wenn A eine Ressource anfordert, ruft es Mongo auf, um sie um +1 zu erhöhen, und gibt das Ergebnis an A zurück, nämlich 1. Zu diesem Zeitpunkt ist das Ergebnis gleich 1, was darauf hinweist, dass dort Während des Anforderungsprozesses von A gibt es keine weiteren Anforderungen. Die Ressource wird angefordert und die Sperrressource wird A zugewiesen.
Wenn B eine Ressource anfordert, ruft es Mongo auf, um +1 zu erhöhen, und gibt das Ergebnis an A zurück, nämlich 2. Wenn das Ergebnis zu diesem Zeitpunkt größer als 1 ist, bedeutet dies, dass während des Anforderungsprozesses von B andere Ressourcenanforderungen vorliegen und die Sperrressourcen B nicht zugewiesen werden können.
Auf diese Weise fordern mehrere Anfragen dieselbe Sperre an und werden in die Warteschlange gestellt.
Über die Ablaufzeit der Sperre:
Wenn der Code im Bild 1releaseLockExpire(key, System.currentTimeMillis()) geändert wird releaseLockExpire(key) , d. h. wenn beim Aufheben der Sperre die Ablaufzeit nicht übergeben wird, kommt es zu folgender Situation:
Zwei Anfragen A und B erfüllen gleichzeitig die Bedingungen Zeit und geben Sie den Code 1 ein
B schließt den Löschvorgang ab und gibt Code 2 ein und hat gerade die Sperrressource erhalten Zu diesem Zeitpunkt hat A möglicherweise gerade damit begonnen, die Sperre aufzuheben.
Zu diesem Zeitpunkt gibt A die gerade von B erworbene Sperre frei, so dass B die gerade erworbene Sperre verliert und B dies nicht erkennt, was zu einem logischen Fehler führt .
Und releaseLockExpire(key, System.currentTimeMillis()) bestimmt die Ablaufzeit beim Aufheben der Sperre, damit die gerade erhaltene Sperre B nicht versehentlich gelöscht wird.
Das obige ist der detaillierte Inhalt vonBeispielerklärung einer verteilten Mongo-Sperre. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!