Java SOA 框架

最近幾個(gè)星期學(xué)習(xí)了點(diǎn)后端的東西,現(xiàn)在簡(jiǎn)單的記錄下,先說(shuō)說(shuō)公司的的SOA(什么是SOA,google)框架。

服務(wù)注冊(cè)

SOA 服務(wù)在啟動(dòng)的時(shí)候會(huì)向配置中心注冊(cè)服務(wù)信息

CoreBootstrap.getInstance().include(args != null && args.length > 0?args:new String[]{"conf/Configure.json"}).start();

程序啟動(dòng)的時(shí)候會(huì)從配置文件讀取服務(wù)的服務(wù)名, 集群名,協(xié)議, 業(yè)務(wù)端口,I/O處理線程池大小,業(yè)務(wù)處理線程池大小,緩沖隊(duì)列大小 ,提供服務(wù)的接口名列表等信息, 將服務(wù)名,集群名,機(jī)器ip,端口號(hào) 注冊(cè)到配置中心

服務(wù)發(fā)現(xiàn)

SOA 客戶端通過(guò)配置文件中的服務(wù)名,集群名,協(xié)議 等信息創(chuàng)建SOA 客戶端

ClientUtil.getContext().initClients("conf/Client.json");
  • 負(fù)載均衡
    SOA 服務(wù)的負(fù)載均衡是在客戶端做的,客戶端在初始化的時(shí)候從配置中心根據(jù)服務(wù)名拉取ip 數(shù)組, 通過(guò)round-robin 做負(fù)載均衡
public String getUrl() {
        int index = this.counter.getAndIncrement();
        index %= this.providerList.size();
        index = index >= 0?index:index + this.providerList.size();
        return (String)this.providerList.get(index);
    }
  • 線程池策略

客戶端線程池策略支持semaphore(線程池滿時(shí)拋出異常) 和 queue(線程池滿時(shí)排隊(duì)等待執(zhí)行);


public Object execute(Task task) throws Throwable {
        BreakerMetrics metric = metrics.get(task.getMethod());
        if (metric.isOpen()) {
            metric.increment(BreakerStatus.BREAKER_REJECT);
            task.setStatus(CallStatus.sick);
            if (task.supportsFallback()) {
                return task.callFallback();
            } else {
                throw new RequestRejectedException(String.format("Service(%s)'s circuit-breaker is open!", property.getService()));
            }
        }

        if (strategy.isBusy()) {
            task.setStatus(CallStatus.no_available_thread);
            if (task.supportsFallback()) {
                return task.callFallback();
            } else {
                throw new NoAvailableWorkerException(String.format("Service(%s) has no available worker in client!", property.getService()));
            }
        } else {
            try {
                return callCommand(task, metric);
            } finally {
                strategy.release();
            }
        }
    }

...

public boolean isBusy() {
        return !semaphore.tryAcquire();
}

...

private void initCalculator() {
        this.calculator = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(property.getCheckWindowInMillis());
                    } catch (InterruptedException e) {
                        break;
                    }

                    metrics.values().forEach((metric) -> {
                        metric.calc();
                    });
                }
            }
        });
        this.calculator.start();
    }

...

public void calc() {
        MetricSnapshot check = array.calcCheck();
        if (open && (check.getCircuitBreak() + check.getTotal()) < 1.0f) {
            logger.error("Api({}), Action(Close), Info(No request for a while)!", apiName);
            open = false;
            return;
        }

        if (open) {
            return;
        }

        if (check.getTotal() >= property.getRequestCountThreshold()) {
            float total = check.getTotal();
            float error = check.getError();
            float errorPercentage = error / total;
            if (errorPercentage > property.getErrorPercentageThreshold()) {
                lastSingleTestTime = new AtomicLong(System.currentTimeMillis());
                logger.error(
                        "Api({}), Action(Open), Info(Error percentage: {}, Total request: {}, all requests will try to invoke fallback instead, single test will start after {}ms)!",
                        apiName, errorPercentage, total, property.getSingleTestWindowInMillis());
                open = true;
            } else {
                logger.debug("Api({}), Action(Check), Info(Error percentage: {}, Total request: {})!", apiName, errorPercentage, total);
            }
        }
    }

metric.isOpen() 性能指標(biāo)的統(tǒng)計(jì)通過(guò)一個(gè)線程定時(shí)計(jì)算出一個(gè)指標(biāo)快照,判斷出是否達(dá)到性能瓶頸
strategy.isBusy() 目前只對(duì)semaphore 策略有效。

通信協(xié)議

目前支持json協(xié)議和thrift二進(jìn)制協(xié)議

thrift二進(jìn)制協(xié)議

兼容Apache thrift 二進(jìn)制協(xié)議,不過(guò)為了追蹤各個(gè)SOA服務(wù)之間的調(diào)用情況,會(huì)嘗試加入了一些額外的信息。


public Object invoke() throws TUserException, TSystemException, TUnknownException {
        Object e;
        try {
            this.tSocket.open();
            if(this.tSocket.isUpgraded() == null && this.tryUpgraded) {
                try {
                    this.writeRequest(UPGRADE_METHODINFO, new Object[]{AgentConfiguration.getServiceName()});
                    this.readResponse(UPGRADE_METHODINFO, true);
                    this.tSocket.setUpgraded(true);
                } catch (TApplicationException var6) {
                    this.tSocket.setUpgraded(false);
                }
            }

            this.writeRequest(this.methodInfo, this.args);
            e = this.readResponse(this.methodInfo, false);
        } catch (TTransportException | TProtocolException var7) {
            this.tSocket.closeImpl();
            throw var7;
        } finally {
            this.tSocket.close();
        }

        return e;
    }

調(diào)用rpc 接口的時(shí)候,會(huì)嘗試調(diào)用UPGRADE_METHODINFO :__thriftpy_tracing_method_name__v2
接口,判斷service是否支持額外字段,從而升級(jí)。

  • thrift二進(jìn)制協(xié)議格式
 protected void writeRequest(MethodInfo methodInfo, Object[] args) {
        if(Boolean.TRUE.equals(this.tSocket.isUpgraded())) {
            TraceHeader header = new TraceHeader(Trace.getCurrentRequestId(), Trace.getCurrentRpcIdWithAppId(), this.context.exportMeta());
            this.writeBean(TRACE_HEADER, header);
        }

        this.writeMessageBegin(new TMessage(methodInfo.getName(), 1, 1));
        this.writeArgs(methodInfo, args);
        this.writeMessageEnd();
        this.flush();
    }

協(xié)議格式

bool類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),一個(gè)字節(jié)的值(true:1,false:0).

Byte類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),一個(gè)字節(jié)的值.

I16類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),兩個(gè)字節(jié)的值.

I32類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),四個(gè)字節(jié)的值.

I64類型和double類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),八個(gè)字節(jié)的值.

String類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),四個(gè)字節(jié)的負(fù)載數(shù)據(jù)長(zhǎng)度,負(fù)載數(shù)據(jù)的值.

Struct類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),結(jié)構(gòu)體負(fù)載數(shù)據(jù),一個(gè)字節(jié)的結(jié)束標(biāo)記.

MAP類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),一個(gè)字節(jié)的鍵類型,一個(gè)字節(jié)的值類型,四個(gè)字節(jié)的負(fù)載數(shù)據(jù)長(zhǎng)度,負(fù)載數(shù)據(jù)的值.

Set類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),一個(gè)字節(jié)的值類型,四個(gè)字節(jié)的負(fù)載數(shù)據(jù)長(zhǎng)度,負(fù)載數(shù)據(jù)的值.

List類型:

一個(gè)字節(jié)的類型,兩個(gè)字節(jié)的字段編號(hào),一個(gè)字節(jié)的值類型,四個(gè)字節(jié)的負(fù)載數(shù)據(jù)長(zhǎng)度,負(fù)載數(shù)據(jù)的值.

消息(函數(shù))類型:
四個(gè)字節(jié)的版本(含調(diào)用類型),四個(gè)字節(jié)的消息名稱長(zhǎng)度,消息名稱,四個(gè)字節(jié)的流水號(hào),消息負(fù)載數(shù)據(jù)的值,一個(gè)字節(jié)的結(jié)束標(biāo)記。

  • 數(shù)據(jù)傳輸

數(shù)據(jù)傳輸通過(guò)tcp傳輸結(jié)束之后關(guān)閉長(zhǎng)連接(留點(diǎn)長(zhǎng)連接緩沖池是不是會(huì)好點(diǎn)),

json協(xié)議

發(fā)現(xiàn)json協(xié)議其實(shí)是走的http 協(xié)議POST方法傳輸數(shù)據(jù), 此處省略

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,837評(píng)論 18 139
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,341評(píng)論 11 349
  • 簡(jiǎn)介 用簡(jiǎn)單的話來(lái)定義tcpdump,就是:dump the traffic on a network,根據(jù)使用者...
    保川閱讀 5,983評(píng)論 1 13
  • 每個(gè)人,都應(yīng)該學(xué)會(huì)相應(yīng)的生存能力,每一個(gè)單身人,則更應(yīng)該多培養(yǎng)一點(diǎn)生存能力,多學(xué)一些東西,記得多學(xué)會(huì)照顧自己,比如...
    遺棄小屋閱讀 579評(píng)論 0 4
  • 加到大了不起的微信,撒花!
    李葳Taiwan閱讀 127評(píng)論 0 0