最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PowerJob的ServerDiscoveryService工作流程源碼解讀

 更新時(shí)間:2023年12月24日 15:26:55   作者:codecraft  
這篇文章主要為大家介紹了PowerJob的ServerDiscoveryService工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

本文主要研究一下PowerJob的ServerDiscoveryService

ServerDiscoveryService

tech/powerjob/worker/background/ServerDiscoveryService.java

@Slf4j
public class ServerDiscoveryService {
    private final Long appId;
    private final PowerJobWorkerConfig config;
    private String currentServerAddress;
    private final Map<String, String> ip2Address = Maps.newHashMap();
    /**
     *  服務(wù)發(fā)現(xiàn)地址
     */
    private static final String DISCOVERY_URL = "http://%s/server/acquire?%s";
    /**
     * 失敗次數(shù)
     */
    private static int FAILED_COUNT = 0;
    /**
     * 最大失敗次數(shù)
     */
    private static final int MAX_FAILED_COUNT = 3;
    public ServerDiscoveryService(Long appId, PowerJobWorkerConfig config) {
        this.appId = appId;
        this.config = config;
    }
    //......
}
ServerDiscoveryService定義了currentServerAddress、ip2Address、服務(wù)發(fā)現(xiàn)url模版,失敗次數(shù),最大失敗次數(shù)

start

public void start(ScheduledExecutorService timingPool) {
        this.currentServerAddress = discovery();
        if (StringUtils.isEmpty(this.currentServerAddress) && !config.isEnableTestMode()) {
            throw new PowerJobException("can't find any available server, this worker has been quarantined.");
        }
        // 這里必須保證成功
        timingPool.scheduleAtFixedRate(() -> {
                    try {
                        this.currentServerAddress = discovery();
                    } catch (Exception e) {
                        log.error("[PowerDiscovery] fail to discovery server!", e);
                    }
                }
                , 10, 10, TimeUnit.SECONDS);
    }
其start方法先通過discovery方法獲取currentServerAddress,然后注冊(cè)定時(shí)任務(wù)每隔10s重新刷新一下currentServerAddress

discovery

private String discovery() {
        if (ip2Address.isEmpty()) {
            config.getServerAddress().forEach(x -> ip2Address.put(x.split(":")[0], x));
        }
        String result = null;
        // 先對(duì)當(dāng)前機(jī)器發(fā)起請(qǐng)求
        String currentServer = currentServerAddress;
        if (!StringUtils.isEmpty(currentServer)) {
            String ip = currentServer.split(":")[0];
            // 直接請(qǐng)求當(dāng)前Server的HTTP服務(wù),可以少一次網(wǎng)絡(luò)開銷,減輕Server負(fù)擔(dān)
            String firstServerAddress = ip2Address.get(ip);
            if (firstServerAddress != null) {
                result = acquire(firstServerAddress);
            }
        }
        for (String httpServerAddress : config.getServerAddress()) {
            if (StringUtils.isEmpty(result)) {
                result = acquire(httpServerAddress);
            }else {
                break;
            }
        }
        if (StringUtils.isEmpty(result)) {
            log.warn("[PowerDiscovery] can't find any available server, this worker has been quarantined.");
            // 在 Server 高可用的前提下,連續(xù)失敗多次,說明該節(jié)點(diǎn)與外界失聯(lián),Server已經(jīng)將秒級(jí)任務(wù)轉(zhuǎn)移到其他Worker,需要?dú)⑺辣镜氐娜蝿?wù)
            if (FAILED_COUNT++ > MAX_FAILED_COUNT) {
                log.warn("[PowerDiscovery] can't find any available server for 3 consecutive times, It's time to kill all frequent job in this worker.");
                List<Long> frequentInstanceIds = HeavyTaskTrackerManager.getAllFrequentTaskTrackerKeys();
                if (!CollectionUtils.isEmpty(frequentInstanceIds)) {
                    frequentInstanceIds.forEach(instanceId -> {
                        HeavyTaskTracker taskTracker = HeavyTaskTrackerManager.removeTaskTracker(instanceId);
                        taskTracker.destroy();
                        log.warn("[PowerDiscovery] kill frequent instance(instanceId={}) due to can't find any available server.", instanceId);
                    });
                }
                FAILED_COUNT = 0;
            }
            return null;
        } else {
            // 重置失敗次數(shù)
            FAILED_COUNT = 0;
            log.debug("[PowerDiscovery] current server is {}.", result);
            return result;
        }
    }
discovery方法從config.getServerAddress()解析地址放到ip2Address,若currentServerAddress有值則acquire,否則遍歷config.getServerAddress()執(zhí)行acquire;若還沒有獲取到則判斷FAILED_COUNT是否超出MAX_FAILED_COUNT,超出則遍歷HeavyTaskTrackerManager.getAllFrequentTaskTrackerKeys()挨個(gè)執(zhí)行remove及destory

acquire

private String acquire(String httpServerAddress) {
        String result = null;
        String url = buildServerDiscoveryUrl(httpServerAddress);
        try {
            result = CommonUtils.executeWithRetry0(() -> HttpUtils.get(url));
        }catch (Exception ignore) {
        }
        if (!StringUtils.isEmpty(result)) {
            try {
                ResultDTO resultDTO = JsonUtils.parseObject(result, ResultDTO.class);
                if (resultDTO.isSuccess()) {
                    return resultDTO.getData().toString();
                }
            }catch (Exception ignore) {
            }
        }
        return null;
    }
    private String buildServerDiscoveryUrl(String address) {
        ServerDiscoveryRequest serverDiscoveryRequest = new ServerDiscoveryRequest()
                .setAppId(appId)
                .setCurrentServer(currentServerAddress)
                .setProtocol(config.getProtocol().name().toUpperCase());
        String query = Joiner.on(OmsConstant.AND).withKeyValueSeparator(OmsConstant.EQUAL).join(serverDiscoveryRequest.toMap());
        return String.format(DISCOVERY_URL, address, query);
    }
acquire方法通過buildServerDiscoveryUrl構(gòu)建url,然后執(zhí)行HttpUtils.get(url)獲取地址

ServerController

tech/powerjob/server/web/controller/ServerController.java

@RestController
@RequestMapping("/server")
@RequiredArgsConstructor
public class ServerController implements ServerInfoAware {
    private ServerInfo serverInfo;
    private final TransportService transportService;
    private final ServerElectionService serverElectionService;
    private final AppInfoRepository appInfoRepository;
    private final WorkerClusterQueryService workerClusterQueryService;
    //......
    @GetMapping("/acquire")
    public ResultDTO<String> acquireServer(ServerDiscoveryRequest request) {
        return ResultDTO.success(serverElectionService.elect(request));
    }
    //......    
}
acquireServer方法執(zhí)行serverElectionService.elect(request)返回server地址

elect

tech/powerjob/server/remote/server/election/ServerElectionService.java

public String elect(ServerDiscoveryRequest request) {
        if (!accurate()) {
            final String currentServer = request.getCurrentServer();
            // 如果是本機(jī),就不需要查數(shù)據(jù)庫那么復(fù)雜的操作了,直接返回成功
            Optional<ProtocolInfo> localProtocolInfoOpt = Optional.ofNullable(transportService.allProtocols().get(request.getProtocol()));
            if (localProtocolInfoOpt.isPresent() && localProtocolInfoOpt.get().getAddress().equals(currentServer)) {
                log.debug("[ServerElectionService] this server[{}] is worker's current server, skip check", currentServer);
                return currentServer;
            }
        }
        return getServer0(request);
    }
elect方法判斷如果是本機(jī)就直接返回,否則執(zhí)行g(shù)etServer0

getServer0

private String getServer0(ServerDiscoveryRequest discoveryRequest) {
        final Long appId = discoveryRequest.getAppId();
        final String protocol = discoveryRequest.getProtocol();
        Set<String> downServerCache = Sets.newHashSet();
        for (int i = 0; i < RETRY_TIMES; i++) {
            // 無鎖獲取當(dāng)前數(shù)據(jù)庫中的Server
            Optional<AppInfoDO> appInfoOpt = appInfoRepository.findById(appId);
            if (!appInfoOpt.isPresent()) {
                throw new PowerJobException(appId + " is not registered!");
            }
            String appName = appInfoOpt.get().getAppName();
            String originServer = appInfoOpt.get().getCurrentServer();
            String activeAddress = activeAddress(originServer, downServerCache, protocol);
            if (StringUtils.isNotEmpty(activeAddress)) {
                return activeAddress;
            }
            // 無可用Server,重新進(jìn)行Server選舉,需要加鎖
            String lockName = String.format(SERVER_ELECT_LOCK, appId);
            boolean lockStatus = lockService.tryLock(lockName, 30000);
            if (!lockStatus) {
                try {
                    Thread.sleep(500);
                }catch (Exception ignore) {
                }
                continue;
            }
            try {
                // 可能上一臺(tái)機(jī)器已經(jīng)完成了Server選舉,需要再次判斷
                AppInfoDO appInfo = appInfoRepository.findById(appId).orElseThrow(() -> new RuntimeException("impossible, unless we just lost our database."));
                String address = activeAddress(appInfo.getCurrentServer(), downServerCache, protocol);
                if (StringUtils.isNotEmpty(address)) {
                    return address;
                }
                // 篡位,如果本機(jī)存在協(xié)議,則作為Server調(diào)度該 worker
                final ProtocolInfo targetProtocolInfo = transportService.allProtocols().get(protocol);
                if (targetProtocolInfo != null) {
                    // 注意,寫入 AppInfoDO#currentServer 的永遠(yuǎn)是 default 的地址,僅在返回的時(shí)候特殊處理為協(xié)議地址
                    appInfo.setCurrentServer(transportService.defaultProtocol().getAddress());
                    appInfo.setGmtModified(new Date());
                    appInfoRepository.saveAndFlush(appInfo);
                    log.info("[ServerElection] this server({}) become the new server for app(appId={}).", appInfo.getCurrentServer(), appId);
                    return targetProtocolInfo.getAddress();
                }
            }catch (Exception e) {
                log.error("[ServerElection] write new server to db failed for app {}.", appName, e);
            } finally {
                lockService.unlock(lockName);
            }
        }
        throw new PowerJobException("server elect failed for app " + appId);
    }
getServer0方法先判斷appInfoRepository中當(dāng)前appId的originServer是否存活,是則直接返回,否則加鎖將transportService.defaultProtocol().getAddress()寫入到appInfo的currentServer

小結(jié)

PowerJob的ServerDiscoveryService定義了start方法,它先通過discovery方法獲取currentServerAddress,然后注冊(cè)定時(shí)任務(wù)每隔10s重新刷新一下currentServerAddress;

discovery方法主要是遍歷config.getServerAddress()執(zhí)行acquire;

acquire方法通過buildServerDiscoveryUrl構(gòu)建url,然后執(zhí)行HttpUtils.get(url)獲取該appId的server地址。

以上就是PowerJob的ServerDiscoveryService工作流程源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于PowerJob ServerDiscoveryService的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringMVC實(shí)現(xiàn)Controller的三種方式總結(jié)

    SpringMVC實(shí)現(xiàn)Controller的三種方式總結(jié)

    這篇文章主要介紹了SpringMVC實(shí)現(xiàn)Controller的三種方式總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Sentinel?Gateway自定義限流返回結(jié)果方式

    Sentinel?Gateway自定義限流返回結(jié)果方式

    這篇文章主要介紹了Sentinel?Gateway自定義限流返回結(jié)果方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Java列出2到100之間所有素?cái)?shù)的方法

    Java列出2到100之間所有素?cái)?shù)的方法

    這篇文章主要介紹了Java列出2到100之間所有素?cái)?shù)的方法,涉及java數(shù)值運(yùn)算的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • SpringBoot實(shí)現(xiàn)自動(dòng)配置全過程

    SpringBoot實(shí)現(xiàn)自動(dòng)配置全過程

    SpringBoot通過自動(dòng)配置減少樣板代碼,基于條件注解和spring.factories篩選加載配置類,結(jié)合外部配置和自定義模塊實(shí)現(xiàn)靈活配置,提供調(diào)試工具排查問題
    2025-08-08
  • SpringBoot開發(fā)技巧之如何處理跨域請(qǐng)求CORS

    SpringBoot開發(fā)技巧之如何處理跨域請(qǐng)求CORS

    CORS(Cross-Origin Resource Sharing)"跨域資源共享",是一個(gè)W3C標(biāo)準(zhǔn),它允許瀏覽器向跨域服務(wù)器發(fā)送Ajax請(qǐng)求,打破了Ajax只能訪問本站內(nèi)的資源限制
    2021-10-10
  • SpringBoot解決跨域的5種方式小結(jié)

    SpringBoot解決跨域的5種方式小結(jié)

    在項(xiàng)目開發(fā)中,時(shí)常會(huì)遇到跨域問題,本文主要介紹了五種解決跨域的方法,使用最多的是第三種,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • 多數(shù)據(jù)源下@transactional事務(wù)踩坑實(shí)戰(zhàn)指南

    多數(shù)據(jù)源下@transactional事務(wù)踩坑實(shí)戰(zhàn)指南

    在微服務(wù)架構(gòu)日益普及的現(xiàn)在,多數(shù)據(jù)源事務(wù)管理成為常見需求,這篇文章主要介紹了多數(shù)據(jù)源下@transcation事務(wù)踩坑的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2026-05-05
  • 一文詳解jvm中的引用類型

    一文詳解jvm中的引用類型

    在Java中對(duì)象以引用來指向JVM的內(nèi)存區(qū)塊,這里我們總結(jié)了強(qiáng)引用、軟引用、弱引用和假象引用(幽靈引用),下面這篇文章主要給大家介紹了關(guān)于jvm中引用類型的相關(guān)資料,需要的朋友可以參考下
    2024-04-04
  • 用C++實(shí)現(xiàn)求N!中末尾0的個(gè)數(shù)的方法詳解

    用C++實(shí)現(xiàn)求N!中末尾0的個(gè)數(shù)的方法詳解

    這篇文章主要介紹了用C++實(shí)現(xiàn)求N!中末尾0的個(gè)數(shù)的方法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • JAVA冒泡排序和二分查找的實(shí)現(xiàn)

    JAVA冒泡排序和二分查找的實(shí)現(xiàn)

    本文詳細(xì)介紹了JAVA冒泡排序和二分查找的實(shí)現(xiàn),雖然這兩種算法比較簡(jiǎn)單,但是確實(shí)我們必須需要掌握的。下面來看看。
    2016-07-07

最新評(píng)論

伊宁县| 宁阳县| 永川市| 红河县| 古丈县| 体育| 昂仁县| 台东市| 垦利县| 富宁县| 图们市| 共和县| 鹰潭市| 东安县| 米脂县| 湘乡市| 阿合奇县| 三亚市| 佛教| 万宁市| 曲松县| 三河市| 长兴县| 庆元县| 元氏县| 舒兰市| 临邑县| 河北省| 无极县| 宜兰县| 柳河县| 朝阳县| 晋州市| 福贡县| 安达市| 交口县| 阜平县| 商南县| 海南省| 佳木斯市| 新乐市|