Dubbo implementation principle and source code analysis — Fine collection Netty implementation principle and source code analysis — boutique collection
“Spring Implementation principles and source code analysis — Boutique Collection” MyBatis implementation principle and source code analysis — boutique collection
Spring MVC Implementation Principle and source code Analysis — A collection of fine works Database Entity Design Collection
Spring Boot Implementation principle and source code analysis — Boutique Collection Java Interview Questions + Java Learning Guide

Abstract: the original source www.iocoder.cn/Eureka/inst… “Taro source” welcome to reprint, keep the summary, thank you!

This article is mainly based on Eureka version 1.8.X

  • 1. An overview of the
  • 2. Why do you need an expiration date
  • 3. EvictionTask
  • Expiration logic
  • 666. The eggs

๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚ follow wechat public number:

  1. RocketMQ/MyCAT/Sharding-JDBC all source code analysis article list
  2. RocketMQ/MyCAT/Sharding-JDBC ไธญๆ–‡ ่งฃ ๅ†ณ source GitHub address
  3. Any questions you may have about the source code will be answered carefully. Even do not know how to read the source can also ask oh.
  4. New source code parsing articles are notified in real time. It’s updated about once a week.
  5. Serious source communication wechat group.

1. An overview of the

This document mainly shares the lease of eureka-server that has expired and been renewed with time.

FROM Deep Analytics Service Discovery Component Netflix Eureka

Recommended Spring Cloud books:

  • Please support the legal version. Download piracy, is equal to the initiative to write low-level bugs.
  • DD — Spring Cloud Micro Services
  • Zhou Li — “Spring Cloud and Docker Micro-service Architecture Combat”
  • Buy two books together, jingdong free delivery.

2. Why do you need an expiration date

Normally, an application instance sends an offline request to the Eureka-server. However, in actual cases, the application instance may crash abnormally or the network is abnormal, so that the offline request cannot be submitted successfully.

In this case, the Eureka-client heartbeat is used to extend the lease and the Eureka-server is used to clear the timeout lease.

3. EvictionTask

Com.net flix. Eureka. Registry. AbstractInstanceRegistry. EvictionTask, clean up the lease expired tasks. When eureka-Server is started, EvictionTask initialization is executed periodically, and the implementation code is as follows:

/ / AbstractInstanceRegistry Java/clean up the lease expired tasks * * * * / private final AtomicReference < EvictionTask > evictionTaskRef = new AtomicReference<EvictionTask>(); protected void postInit() { // .... If (evictionTaskRef.get()! = null) { evictionTaskRef.get().cancel(); } evictionTaskRef.set(new EvictionTask()); evictionTimer.schedule(evictionTaskRef.get(), serverConfig.getEvictionIntervalTimerInMs(), serverConfig.getEvictionIntervalTimerInMs()); }Copy the code
  • configurationeureka.evictionIntervalTimerInMs, the execution frequency of clearing expired leases (unit: ms). By default, 60000 milliseconds.
  • EvictionTask implementation code is as follows:

    Class EvictionTask extends TimerTask {@override public void run() {try {long compensationTimeMs = getCompensationTimeMs(); logger.info("Running the evict task with compensationTime {}ms", compensationTimeMs); // Remove evict(compensationTimeMs); } catch (Throwable e) { logger.error("Could not run the evict task", e); }}}Copy the code
    • Call #compensationTimeMs() to get the compensation time in milliseconds. Formula = Current time – Last task execution time – Task execution frequency. Why we need to compensate time in milliseconds is revealed in the “4. Expiration logic” Lease#isisExpired(additionalLeaseMs) method. #compensationTimeMs()

      / / Private Final AtomicLong lastExecutionNanosRef = new AtomicLong(0L); long getCompensationTimeMs() { long currNanos = getCurrentTimeNano(); long lastNanos = lastExecutionNanosRef.getAndSet(currNanos); if (lastNanos == 0L) { return 0L; } long elapsedMs = TimeUnit.NANOSECONDS.toMillis(currNanos - lastNanos); long compensationTime = elapsedMs - serverConfig.getEvictionIntervalTimerInMs(); return compensationTime <= 0L ? 0L : compensationTime; }Copy the code
      • Due to JVM GC, or clock skew, the timer actually executes slightly later than expected. I run the machine under low load, about 10 ms.

        compute a compensation time defined as the actual time this task was executed since the prev iteration, vs the configured amount of time for execution. This is useful for cases where changes in time (due to clock skew or gc for example) causes the actual eviction task to execute later than the desired time according to the configured cycle.

    • Invoke the #evict(compensationTime) method to clean up expired leases, as detailed in “4. Expiration Logic.”

Expiration logic

Invoke #evict(compensationTime) to clean up the expired lease logic as follows:

1: public void evict(long additionalLeaseMs) { 2: logger.debug("Running the evict task"); 3: 4: if (! isLeaseExpirationEnabled()) { 5: logger.debug("DS: lease expiration is currently disabled."); 6: return; 7:} 8: 9: // Obtain all expired leases 10: // We collect first all expired items, to evict them in random order. For large eviction sets, 11: // if we do not that, we might wipe out whole apps before self preservation kicks in. By randomizing it, 12: // the impact should be evenly distributed across all applications. 13: List<Lease<InstanceInfo>> expiredLeases = new ArrayList<>(); 14: for (Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry : registry.entrySet()) { 15: Map<String, Lease<InstanceInfo>> leaseMap = groupEntry.getValue(); 16: if (leaseMap ! = null) { 17: for (Entry<String, Lease<InstanceInfo>> leaseEntry : leaseMap.entrySet()) { 18: Lease<InstanceInfo> lease = leaseEntry.getValue(); 19: if (lease.isExpired(additionalLeaseMs) && lease.getHolder() ! = null) {// expired 20: expiredLeases. Add (lease); 21:} 22:} 23:} 24:} 25: 26: // Calculate the maximum number of allowable clean leases 27: // To compensate for GC pauses or drifting local time, we need to use current registry size as a base for 28: // triggering self-preservation. Without that we would wipe out full registry. 29: int registrySize = (int) getLocalRegistrySize(); 30: int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold()); 31: int evictionLimit = registrySize - registrySizeThreshold; 27: int toEvict = math.min (expiredLeases. Size (), evictionLimit); 27: int toEvict = leases. 35: if (toEvict > 0) { 36: logger.info("Evicting {} items (expired={}, evictionLimit={})", toEvict, expiredLeases.size(), evictionLimit); 37: 38: // Expiration one by one 39: Random Random = new Random(System.currentTimemillis ()); 40: for (int i = 0; i < toEvict; i++) { 41: // Pick a random item (Knuth shuffle algorithm) 42: int next = i + random.nextInt(expiredLeases.size() - i); 43: Collections.swap(expiredLeases, i, next); 44: Lease<InstanceInfo> lease = expiredLeases.get(i); 45: 46: String appName = lease.getHolder().getAppName(); 47: String id = lease.getHolder().getId(); 48: EXPIRED.increment(); 49: logger.warn("DS: Registry: expired lease for {}/{}", appName, id); 50: internalCancel(appName, id, false); 51:} 52:} 53:}Copy the code
  • Lines 3 to 7: The judgment allows the execution of the clearing of expired leases logic, mainly related to the self-protection mechanism, which is explained in detail in Eureka Source Code Parsing — Application Instance Registration Discovery (IV) self-protection Mechanism.
  • Lines 9 through 24: Get all set of expired leases.

    • Line 19: Call the Lease#isisExpired(additionalLeaseMs) method to determine if the lease has expired as follows:

      // Lease.java
      public boolean isExpired(long additionalLeaseMs) {
         return (evictionTimestamp > 0 || System.currentTimeMillis() > (lastUpdateTimestamp + duration + additionalLeaseMs));
      }
      
      public void renew() {
         lastUpdateTimestamp = System.currentTimeMillis() + duration;
      }
      Copy the code
      • ๐Ÿ˜ˆ note: Without considering the additionalLeaseMs parameter, the lease expires by one more duration than expected, LastUpdateTimestamp = system.currentTimemillis () + duration The correct setting should be lastUpdateTimestamp = System.CurrentTimemillis ().

        Note that due to renew() doing the โ€˜wrongโ€ thing and setting lastUpdateTimestamp to +duration more than what it should be, the expiry will actually be 2 * duration. This is a minor bug and should only affect instances that ungracefully shutdown. Due to possible wide ranging impact to existing usage, this will not be fixed.

      • TODO [0023] : additionalLeaseMs

  • Lines 26 to 34: Calculate the maximum number of leases allowed for cleanup, and then calculate the number of leases allowed for cleanup.

    • ๐Ÿ˜ˆ Note: Even if eureka-server turns off self-protection, if you use the default configuration renewalPercentThreshold = 0.85, the result will be batch phasing out. Here’s an example:

      // Assume 20 leases, 10 of which expire. Int registrySize = 20; Int registrySizeThreshold = (int) (20 * 0.85) = 17; int evictionLimit = 20 - 17 = 3; int toEvict = Math.min(10, 3) = 3; // After the first round of execution, 17 leases remain, of which 7 have expired. Int registrySize = 17; Int registrySizeThreshold = (int) (17 * 0.85) = 14; int evictionLimit = 17 - 14 = 3; int toEvict = Math.min(7, 3) = 3; // At the end of the second round of execution, 14 leases remain, of which 4 have expired. Int registrySize = 14; Int registrySizeThreshold = (int) (14 * 0.85) = 11; int evictionLimit = 14 - 11 = 3; int toEvict = Math.min(4, 3) = 3; // After the third round of execution, there are 11 leases left, among which 1 lease has expired. Int registrySize = 11; Int registrySizeThreshold = (int) (11 * 0.85) = 9; int evictionLimit = 11 - 9 = 2; int toEvict = Math.min(1, 2) = 1; // After the fourth round of execution, 10 leases remain, of which 0 have expired. The end.Copy the code
      • Conclusion: The difference between starting self-protection and not is whether the logic of clearing expired leases is performed. If you want to closePartial graduallyExpiration, setrenewalPercentThreshold = 0 ใ€‚
    • Due to the JVM GC, or local time difference reasons, may be self protection mechanism, the threshold expectedNumberOfRenewsPerMin numberOfRenewsPerMinThreshold correctly, in relatively “dangerous” is the date of operation, Recalculate the self-protection threshold.

  • Lines 35 to 51: Random clearing of expired leases. Because the lease is added to the array according to the order of applications, a random method is adopted to avoid the expiration of all applications.

    • Line 39: Pass in the current time to generate randomness for the seed, avoiding Java’s pseudo-randomness situation. In why are Random Numbers in Java pseudorandom? Have detailed analysis.
    • Lines 41 to 43: Randomly transpose the following elements to the current position (i).
  • Line 50: Call#internalCancel()Method of offline expired lease inEureka Source Code Analysis — Application Instance Registration discovery (4) self-Protection MechanismHave detailed analysis.

666. The eggs

๐Ÿ˜ซ originally thought a relatively easy article, turned out to consume more time than expected, maybe four hours. Mainly stuck in the compensation time, I do not understand at present. If you know fat friends, trouble to inform.

Fat friends, share my public number (impression channel source code) to your fat friends?