• Eureka 启动分析 和 配置调优


    1. InstanceInfoFactory
    2. com.netflix.discovery.DiscoveryClient
    3. DefaultEurekaServerContext : Initializing ...
    4. cluster.PeerEurekaNodes : Adding new peer nodes
    5. AbstractInstanceRegistry : Finished initializing remote region registries.
    6. DefaultEurekaServerContext : Initialized
    7. EurekaServiceRegistry : Registering application EUREKASERVER with eureka with status UP
    8. EurekaServerBootstrap : Initialized server context

    EurekaBootStrap

    this.initEurekaEnvironment();
    this.initEurekaServerContext();
    
    ((PeerAwareInstanceRegistry)registry).openForTraffic(applicationInfoManager, registryCount);
    
    public void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {
        this.expectedNumberOfClientsSendingRenews = count;
        this.updateRenewsPerMinThreshold();
    

    AbstractInstanceRegistry

    • 自我保护机制 ,若关闭 ------> evict 剔除服务。 若开启 --------> 进行服务保护( 网络抖动或者真的挂掉 )
    • eureka 优化点 RenewalPercentThreshold()); 续约百分比阈值
    • RenewalPercentThreshold 续约百分比阈值 ----默认0.85D
    • 这两个配置 需要考虑 实际服务数、阈值等测算后调节。少量服务建议开启保护,服务数量多可以下线,写事件监听进行 邮件、钉钉等通知提醒
    public void evict(long additionalLeaseMs) {
       .....
    int registrySize = (int)this.getLocalRegistrySize();
    int registrySizeThreshold = (int)((double)registrySize * this.serverConfig.getRenewalPercentThreshold());
    int evictionLimit = registrySize - registrySizeThreshold;
    int toEvict = Math.min(expiredLeases.size(), evictionLimit);
    if (toEvict > 0) {
        logger.info("Evicting {} items (expired={}, evictionLimit={})", new Object[]{toEvict, expiredLeases.size(), evictionLimit});
        Random random = new Random(System.currentTimeMillis());
    
    • RenewalThresholdUpdateIntervalMs 续约阈值更新间隔 ----默认900000ms
    • ExpectedClientRenewalIntervalSeconds 期望客户端续约间隔-----默认30s
    • 定时任务 Timer 进行剔除没有心跳的服务
    • 缺点:Timer 多线程并行处理任务时运行多个TimerTask,只要其中之一没有捕获抛出的异常,其他任务就会自动终止,建议使用ScheduleExecutorService
    • 优化点 剔除服务时间间隔毫秒数 EvictionIntervalTimerInMs
    • 可以进行 服务的快速下线 配置为 每1s进行一次剔除服务,提高可用性
    this.evictionTimer.schedule((TimerTask)this.evictionTaskRef.get(), this.serverConfig.getEvictionIntervalTimerInMs(), this.serverConfig.getEvictionIntervalTimerInMs());
    

    三级缓存机制

    • register --> readWriteCacheMap --> readonlyCacheMap

    • 每次注册的时候 更新register ,失效readWriteCacheMap中的相关服务

    • readWriteCacheMap readonly 之间 ,定时任务Timer 每隔30s 更新一次 (从readWriteCacheMap 中取数据放入readonlyCacheMap 主要提供读,高可用性)。不是强一致性

      eureka.server.response-cache-update-interval-ms=1000
      
    • 优化点 response-cache-update-interval-ms 配置时间间隔小一点,可以更快速的从readWriteCacheMap 取到数据,放入readonlyCacheMap

    • 优化点 eureka.server.use-read-only-response-cache=false

    • 三级缓存 默认为 true , false直接从readWriteCacheMap 中取数据,不去readonlyCacheMap,readonlyCacheMap数据一致性不高。

    @VisibleForTesting
    ResponseCacheImpl.Value getValue(Key key, boolean useReadOnlyCache) {
        ResponseCacheImpl.Value payload = null;
    
        try {
            if (useReadOnlyCache) {
                ResponseCacheImpl.Value currentPayload = (ResponseCacheImpl.Value)this.readOnlyCacheMap.get(key);
                if (currentPayload != null) {
                    payload = currentPayload;
                } else {
                    payload = (ResponseCacheImpl.Value)this.readWriteCacheMap.get(key);
                    this.readOnlyCacheMap.put(key, payload);
                }
            } else {
                payload = (ResponseCacheImpl.Value)this.readWriteCacheMap.get(key);
            }
        } catch (Throwable var5) {
            logger.error("Cannot get value for key : {}", key, var5);
        }
    
        return payload;
    }
    
    • CAP 中的C 一致性无法保证
    • eureka的数据结构
    private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry = new ConcurrentHashMap();
    

    ApplicationResource

    @POST
    @Consumes({"application/json", "application/xml"})
    public Response addInstance(InstanceInfo info, @HeaderParam("x-netflix-discovery-replication") String isReplication) {
    

    InstanceRegistry

    public void register(final InstanceInfo info, final boolean isReplication) {
        this.handleRegistration(info, this.resolveInstanceLeaseDuration(info), isReplication);
        super.register(info, isReplication);
    }
    
    • 服务注册 对readWriteCacheMap 中服务 进行失效
    public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
        try {
            this.read.lock();
           .......
            Lease<InstanceInfo> existingLease = (Lease)((Map)gMap).get(registrant.getId());
                synchronized(this.lock) {
                    if (this.expectedNumberOfClientsSendingRenews > 0) {
                        ++this.expectedNumberOfClientsSendingRenews;
                        this.updateRenewsPerMinThreshold();
                    }
                }
    -----------------------------------------------------------------------------------------
            Lease<InstanceInfo> lease = new Lease(registrant, leaseDuration);
    -----------------------------------------------------------------------------------------      
           ........
    -----------------------------------------------------------------------------------------
            this.invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
    -----------------------------------------------------------------------------------------
            logger.info("Registered instance {}/{} with status {} (replication={})", new Object[]{registrant.getAppName(), registrant.getId(), registrant.getStatus(), isReplication});
        } finally {
            this.read.unlock();
        }
    
    }
    

    Lease<InstanceInfo>,<T>泛型 。Lease自带各种时间字段

    • 服务信息 注入Lease中, 由于每30s心跳后进行服务续约,这个数据结构便于服务续约 (直接调用方法,而不用进行get、set)

    • 服务续约 和 服务下线

    • public void renew() {
          this.lastUpdateTimestamp = System.currentTimeMillis() + this.duration;
      }
      
      public void cancel() {
          if (this.evictionTimestamp <= 0L) {
              this.evictionTimestamp = System.currentTimeMillis();
          }
      

    ResponseCacheImpl

    public void invalidate(String appName, @Nullable String vipAddress, @Nullable String secureVipAddress) {
    

    EurekaServerAutoConfiguration

    • @Import({EurekaServerInitializerConfiguration.class})
      @ConditionalOnBean({Marker.class})
      

    EurekaServerInitializerConfiguration

    • implements SmartLifecycle
      
    • SmartLifecycle extends Lifecycle
      
    • Lifecycle -------> springframework.context

    • EurekaServerInitializerConfiguration 实现了Lifecycle中 start();

  • 相关阅读:
    获取ArcMap窗口句柄,通过WinAPI获取工作空间中点击要素的系统桌面坐标实现窗体跟随
    ArcGis Go to XY功能代码C#
    Python入门第二篇:基础语法
    python入门第一篇:python语言简介
    Robotium结果的收集和失败重跑
    adb问题整理
    adb pull 与 push
    Monkey测试的参数
    Linux主要命令
    命令行启动应用的几种常见类型
  • 原文地址:https://www.cnblogs.com/JMrLi/p/12964519.html
Copyright © 2020-2023  润新知