最近幾個(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();
}
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ù), 此處省略