Thrift RPC Client 流程
Thrift客戶端有兩種:同步客戶端和非同步客戶端。
同步客戶端
同步客戶端比較簡單,先看一下類圖。
TServiceClient:用於以同步方式與TService進行通訊;
Iface介面和Client類都是通過Thrift檔案自動生成的程式碼。
TServiceClient
TServiceClient定義了基礎的向Server傳送請求和從Server接收響應的方法。
public abstract class TServiceClient {
public TServiceClient(TProtocol prot) {
this(prot, prot);
}
public TServiceClient(TProtocol iprot, TProtocol oprot) {
iprot_ = iprot;
oprot_ = oprot;
}
protected TProtocol iprot_;//輸入TProtocol
protected TProtocol oprot_;//輸出TProtocol
protected int seqid_;//序列號
public TProtocol getInputProtocol() {
return this.iprot_;
}
public TProtocol getOutputProtocol() {
return this.oprot_;
}
//向Server傳送請求
protected void sendBase(String methodName, TBase args) throws TException {
//寫訊息頭,seqid_只是簡單的++,非執行緒安全,接收響應時要進行seqid_的校驗
oprot_.writeMessageBegin(new TMessage(methodName, TMessageType.CALL, ++seqid_));
args.write(oprot_);//寫引數
oprot_.writeMessageEnd();
oprot_.getTransport().flush();//傳送
}
//從Server接收響應
protected void receiveBase(TBase result, String methodName) throws TException {
TMessage msg = iprot_.readMessageBegin();//讀訊息頭,若沒有資料一直等待,詳見TTransport的實現
if (msg.type == TMessageType.EXCEPTION) { //異常訊息通過TApplicationException讀取
TApplicationException x = TApplicationException.read(iprot_);
iprot_.readMessageEnd();
throw x;
}
if (msg.seqid != seqid_) { //序列號不一致報異常
throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, methodName + " failed: out of sequence response");
}
result.read(iprot_);//讀資料,由其result子類實現
iprot_.readMessageEnd();
}
}
Iface
public interface Iface {
//thrift中定義的方法
public ResultCommon sayHello(String paramJson) throws org.apache.thrift.TException;
}
Client
public static class Client extends org.apache.thrift.TServiceClient implements Iface {
//Client工廠類
public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {
public Factory() {}
public Client getClient(org.apache.thrift.protocol.TProtocol prot) {
return new Client(prot);
}
public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
return new Client(iprot, oprot);
}
}
public Client(org.apache.thrift.protocol.TProtocol prot) {
super(prot, prot);
}
public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
super(iprot, oprot);
}
//sayHello方法呼叫入口
public ResultCommon sayHello(String paramJson) throws org.apache.thrift.TException {
send_sayHello(paramJson);//傳送請求
return recv_sayHello();//接收響應
}
//傳送請求
public void send_sayHello(String paramJson) throws org.apache.thrift.TException {
sayHello_args args = new sayHello_args();//組裝引數
args.setParamJson(paramJson);
sendBase("sayHello", args);//呼叫父類的sendBase方法傳送請求
}
//接收響應
public ResultCommon recv_sayHello() throws org.apache.thrift.TException {
sayHello_result result = new sayHello_result();
receiveBase(result, "sayHello");
//呼叫父類的receiveBase方法傳送請求
if (result.isSetSuccess()) {
return result.success;
}
throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "sayHello failed: unknown result");
}
}
非同步客戶端
非同步客戶端實現比較複雜,通過回撥實現,先看一個非同步客戶端的例子。非同步客戶端需要使用
String paramJson = "{\"wewe\":\"111\"}";
TNonblockingSocket tNonblockingSocket = new TNonblockingSocket("127.0.0.1", 8090);
//使用非阻塞TNonblockingSocket
TAsyncClientManager tAsyncClientManager = new TAsyncClientManager();
HelloService.AsyncClient asyncClient = new HelloService.AsyncClient.Factory(tAsyncClientManager, new TBinaryProtocol.Factory()).getAsyncClient(tNonblockingSocket);
asyncClient.sayHello(paramJson, new AsyncMethodCallback<HelloService.AsyncClient.sayHello_call>() {
@Override
public void onError(Exception exception) {
//... 9
}
@Override
public void onComplete(sayHello_call response) {
ResultCommon resultCommon = response.getResult();
System.out.println(resultCommon.getDesc());
}
});
涉及到的類結構圖如下:
TAsyncClient:非同步客戶端抽象類,通過Thrift檔案生成的AsyncClient需繼承該類;
TAsyncClientManager:非同步客戶端管理類,包含一個selector執行緒,用於轉換方法呼叫物件;
TAsyncMethodCall:封裝了非同步方法呼叫,Thrift檔案定義的所有方法都會在AsyncClient中生成對應的繼承於TAsyncMethodCall的內部類(如sayHello_call);
AsyncMethodCallback:接收服務端回撥的介面,使用者需要定義實現該介面的類。
TAsyncClient
TAsyncClient為非同步客戶端提供了公共的屬性和方法。
public abstract class TAsyncClient {
protected final TProtocolFactory ___protocolFactory;
protected final TNonblockingTransport ___transport;
protected final TAsyncClientManager ___manager;//非同步客戶端管理類
protected TAsyncMethodCall ___currentMethod;//非同步方法呼叫
private Exception ___error;
private long ___timeout;
public TAsyncClient(TProtocolFactory protocolFactory, TAsyncClientManager manager, TNonblockingTransport transport) {
this(protocolFactory, manager, transport, 0);
}
public TAsyncClient(TProtocolFactory protocolFactory, TAsyncClientManager manager, TNonblockingTransport transport, long timeout) {
this.___protocolFactory = protocolFactory;
this.___manager = manager;
this.___transport = transport;
this.___timeout = timeout;
}
public TProtocolFactory getProtocolFactory() {
return ___protocolFactory;
}
public long getTimeout() {
return ___timeout;
}
public boolean hasTimeout() {
return ___timeout > 0;
}
public void setTimeout(long timeout) {
this.___timeout = timeout;
}
//客戶端是否處於異常狀態
public boolean hasError() {
return ___error != null;
}
public Exception getError() {
return ___error;
}
//檢查是否準備就緒,如果當前Cilent正在執行一個方法或處於error狀態則報異常
protected void checkReady() {
if (___currentMethod != null) {
throw new IllegalStateException("Client is currently executing another method: " + ___currentMethod.getClass().getName());
}
if (___error != null) {
throw new IllegalStateException("Client has an error!", ___error);
}
}
//執行完成時delegate方法會呼叫該方法,將___currentMethod置為null
protected void onComplete() {
___currentMethod = null;
}
//執行出現異常時delegate方法會呼叫該方法,
protected void onError(Exception exception) {
___transport.close();//關閉連線
___currentMethod = null;//將___currentMethod置為null
___error = exception;//異常資訊
}
}
AsyncClient
AsyncClient類是通過Thrift檔案自動生成的,在該類中含有每個方法的呼叫入口,並且為每個方法生成了一個方法呼叫類方法名_call,如sayHello_call。sayHello_call實現了父類TAsyncMethodCall的連個抽象方法:write_args和getResult,因為每個方法的引數和返回值不同,所以這兩個方法需要具體子類實現。
public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface {
//AsyncClient工廠類
public static class Factory implements org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {
private org.apache.thrift.async.TAsyncClientManager clientManager;
private org.apache.thrift.protocol.TProtocolFactory protocolFactory;
public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) {
this.clientManager = clientManager;
this.protocolFactory = protocolFactory;
}
public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) {
return new AsyncClient(protocolFactory, clientManager, transport);
}
}
public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) {
super(protocolFactory, clientManager, transport);
}
//sayHello方法呼叫入口
public void sayHello(String paramJson, org.apache.thrift.async.AsyncMethodCallback<sayHello_call> resultHandler) throws org.apache.thrift.TException {
checkReady();//檢查當前Client是否可用
//建立方法呼叫例項
sayHello_call method_call = new sayHello_call(paramJson, resultHandler, this, ___protocolFactory, ___transport);
this.___currentMethod = method_call;
//呼叫TAsyncClientManager的call方法
___manager.call(method_call);
}
public static class sayHello_call extends org.apache.thrift.async.TAsyncMethodCall {
private String paramJson;
public sayHello_call(String paramJson, org.apache.thrift.async.AsyncMethodCallback<sayHello_call> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
super(client, protocolFactory, transport, resultHandler, false);
this.paramJson = paramJson;
}
//傳送請求
public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("sayHello", org.apache.thrift.protocol.TMessageType.CALL, 0));
sayHello_args args = new sayHello_args();
args.setParamJson(paramJson);
args.write(prot);
prot.writeMessageEnd();
}
//獲取返回結果
public ResultCommon getResult() throws org.apache.thrift.TException {
if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
throw new IllegalStateException("Method call not finished!");
}
org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
return (new Client(prot)).recv_sayHello();
}
}
}
TAsyncClientManager
TAsyncClientManager是非同步客戶端管理類,它為維護了一個待處理的方法呼叫佇列pendingCalls,並通過SelectThread執行緒監聽selector事件,當有就緒事件時進行方法呼叫的處理。
public class TAsyncClientManager {
private static final Logger LOGGER = LoggerFactory.getLogger(TAsyncClientManager.class.getName());
private final SelectThread selectThread;
//TAsyncMethodCall待處理佇列
private final ConcurrentLinkedQueue<TAsyncMethodCall> pendingCalls = new ConcurrentLinkedQueue<TAsyncMethodCall>();
//初始化TAsyncClientManager,新建selectThread執行緒並啟動
public TAsyncClientManager() throws IOException {
this.selectThread = new SelectThread();
selectThread.start();
}
//方法呼叫
public void call(TAsyncMethodCall method) throws TException {
if (!isRunning()) {
throw new TException("SelectThread is not running");
}
method.prepareMethodCall();//做方法呼叫前的準備
pendingCalls.add(method);//加入待處理佇列
selectThread.getSelector().wakeup();//喚醒selector,很重要,因為首次執行方法呼叫時select Thread還阻塞在selector.select()上
}
public void stop() {
selectThread.finish();
}
public boolean isRunning() {
return selectThread.isAlive();
}
//SelectThread執行緒類,處理方法呼叫的核心
private class SelectThread extends Thread {
private final Selector selector;
private volatile boolean running;
private final TreeSet<TAsyncMethodCall> timeoutWatchSet = new TreeSet<TAsyncMethodCall>(new TAsyncMethodCallTimeoutComparator());
public SelectThread() throws IOException {
this.selector = SelectorProvider.provider().openSelector();
this.running = true;
this.setName("TAsyncClientManager#SelectorThread " + this.getId());
setDaemon(true);//非守護執行緒
}
public Selector getSelector() {
return selector;
}
public void finish() {
running = false;
selector.wakeup();
}
public void run() {
while (running) {
try {
try {
if (timeoutWatchSet.size() == 0) {
//如果超時TAsyncMethodCall監控集合為空,直接無限期阻塞監聽select()事件。TAsyncClientManager剛初始化時是空的
selector.select();
} else {
//如果超時TAsyncMethodCall監控集合不為空,則計算Set中第一個元素的超時時間戳是否到期
long nextTimeout = timeoutWatchSet.first().getTimeoutTimestamp();
long selectTime = nextTimeout - System.currentTimeMillis();
if (selectTime > 0) { //還沒有到期,超時監聽select()事件,超過selectTime自動喚醒selector
selector.select(selectTime);
} else {
//已經到期,立刻監聽select()事件,不會阻塞selector
selector.selectNow();
}
}
} catch (IOException e) {
LOGGER.error("Caught IOException in TAsyncClientManager!", e);
}
//監聽到就緒事件或者selector被喚醒會執行到此處
transitionMethods();
//處理就緒keys
timeoutMethods();//超時方法呼叫處理
startPendingMethods();//處理pending的方法呼叫
} catch (Exception exception) {
LOGGER.error("Ignoring uncaught exception in SelectThread", exception);
}
}
}
//監聽到就緒事件或者selector被喚醒,如果有就緒的SelectionKey就呼叫methodCall.transition(key);
private void transitionMethods() {
try {
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if (!key.isValid()) {
//跳過無效key,方法呼叫出現異常或key被取消等會導致無效key
continue;
}
TAsyncMethodCall methodCall = (TAsyncMethodCall)key.attachment();
//呼叫methodCall的transition方法,執行相關的動作並將methodCall的狀態轉換為下一個狀態
methodCall.transition(key);
//如果完成或發生錯誤,從timeoutWatchSet刪除該methodCall
if (methodCall.isFinished() || methodCall.getClient().hasError()) {
timeoutWatchSet.remove(methodCall);
}
}
} catch (ClosedSelectorException e) {
LOGGER.error("Caught ClosedSelectorException in TAsyncClientManager!", e);
}
}
//超時方法呼叫處理
private void timeoutMethods() {
Iterator<TAsyncMethodCall> iterator = timeoutWatchSet.iterator();
long currentTime = System.currentTimeMillis();
while (iterator.hasNext()) {
TAsyncMethodCall methodCall = iterator.next();
if (currentTime >= methodCall.getTimeoutTimestamp()) { //如果超時,從timeoutWatchSet中刪除並呼叫onError()方法
iterator.remove();
methodCall.onError(new TimeoutException("Operation " + methodCall.getClass() + " timed out after " + (currentTime - methodCall.getStartTime()) + " ms."));
} else {
//如果沒有超時,說明之後的TAsyncMethodCall也不會超時,跳出迴圈,因為越早進入timeoutWatchSet的TAsyncMethodCall越先超時。
break;
}
}
}
//開始等待的方法呼叫,迴圈處理pendingCalls中的methodCall
private void startPendingMethods() {
TAsyncMethodCall methodCall;
while ((methodCall = pendingCalls.poll()) != null) {
// Catch registration errors. method will catch transition errors and cleanup.
try { //向selector註冊並設定初次狀態
methodCall.start(selector);
//如果客戶端指定了超時時間且transition成功,將methodCall加入到timeoutWatchSet
TAsyncClient client = methodCall.getClient();
if (client.hasTimeout() && !client.hasError()) {
timeoutWatchSet.add(methodCall);
}
} catch (Exception exception) {
//異常處理
LOGGER.warn("Caught exception in TAsyncClientManager!", exception);
methodCall.onError(exception);
}
}
}
}
//TreeSet用的比較器,判斷是否是同一個TAsyncMethodCall例項
private static class TAsyncMethodCallTimeoutComparator implements Comparator<TAsyncMethodCall> {
public int compare(TAsyncMethodCall left, TAsyncMethodCall right) {
if (left.getTimeoutTimestamp() == right.getTimeoutTimestamp()) {
return (int)(left.getSequenceId() - right.getSequenceId());
} else {
return (int)(left.getTimeoutTimestamp() - right.getTimeoutTimestamp());
}
}
}
}
TAsyncMethodCall
TAsyncMethodCall實現了對方法呼叫的封裝。一次方法呼叫過程就是一個TAsyncMethodCall例項的生命週期。TAsyncMethodCall例項在整個生命週期內有以下狀態,正常情況下的狀態狀態過程為:CONNECTING -> WRITING_REQUEST_SIZE -> WRITING_REQUEST_BODY -> READING_RESPONSE_SIZE -> READING_RESPONSE_BODY -> RESPONSE_READ,如果任何一個過程中發生了異常則直接轉換為ERROR狀態。
public static enum State {
CONNECTING,//連線狀態
WRITING_REQUEST_SIZE,//寫請求size
WRITING_REQUEST_BODY,//寫請求體
READING_RESPONSE_SIZE,//讀響應size
READING_RESPONSE_BODY,//讀響應體
RESPONSE_READ,//讀響應完成
ERROR;//異常狀態
}
TAsyncMethodCall的原始碼分析如下:
public abstract class TAsyncMethodCall<T> {
private static final int INITIAL_MEMORY_BUFFER_SIZE = 128;
private static AtomicLong sequenceIdCounter = new AtomicLong(0);//序列號計數器
private State state = null;//狀態在start()方法中初始化
protected final TNonblockingTransport transport;
private final TProtocolFactory protocolFactory;
protected final TAsyncClient client;
private final AsyncMethodCallback<T> callback;//回撥例項
private final boolean isOneway;
private long sequenceId;//序列號
private ByteBuffer sizeBuffer;//Java NIO概念,frameSize buffer
private final byte[] sizeBufferArray = new byte[4];//4位元組的訊息Size位元組陣列
private ByteBuffer frameBuffer;//Java NIO概念,frame buffer
private long startTime = System.currentTimeMillis();
protected TAsyncMethodCall(TAsyncClient client, TProtocolFactory protocolFactory, TNonblockingTransport transport, AsyncMethodCallback<T> callback, boolean isOneway) {
this.transport = transport;
this.callback = callback;
this.protocolFactory = protocolFactory;
this.client = client;
this.isOneway = isOneway;
this.sequenceId = TAsyncMethodCall.sequenceIdCounter.getAndIncrement();
}
protected State getState() {
return state;
}
protected boolean isFinished() {
return state == State.RESPONSE_READ;
}
protected long getStartTime() {
return startTime;
}
protected long getSequenceId() {
return sequenceId;
}
public TAsyncClient getClient() {
return client;
}
public boolean hasTimeout() {
return client.hasTimeout();
}
public long getTimeoutTimestamp() {
return client.getTimeout() + startTime;
}
//將請求寫入protocol,由子類實現
protected abstract void write_args(TProtocol protocol) throws TException;
//方法呼叫前的準備處理,初始化frameBuffer和sizeBuffer
protected void prepareMethodCall() throws TException {
//TMemoryBuffer記憶體快取傳輸類,繼承了TTransport
TMemoryBuffer memoryBuffer = new TMemoryBuffer(INITIAL_MEMORY_BUFFER_SIZE);
TProtocol protocol = protocolFactory.getProtocol(memoryBuffer);
write_args(protocol);//將請求寫入protocol
int length = memoryBuffer.length();
frameBuffer = ByteBuffer.wrap(memoryBuffer.getArray(), 0, length);
TFramedTransport.encodeFrameSize(length, sizeBufferArray);
sizeBuffer = ByteBuffer.wrap(sizeBufferArray);
}
//向selector註冊並設定開始狀態,可能是連線狀態或寫狀態
void start(Selector sel) throws IOException {
SelectionKey key;
if (transport.isOpen()) {
state = State.WRITING_REQUEST_SIZE;
key = transport.registerSelector(sel, SelectionKey.OP_WRITE);
} else {
state = State.CONNECTING;
key = transport.registerSelector(sel, SelectionKey.OP_CONNECT); //如果是非阻塞連線初始化會立即成功,轉換為寫狀態並修改感興趣事件
if (transport.startConnect()) {
registerForFirstWrite(key);
}
}
key.attach(this);//將本methodCall附加在key上
}
void registerForFirstWrite(SelectionKey key) throws IOException {
state = State.WRITING_REQUEST_SIZE;
key.interestOps(SelectionKey.OP_WRITE);
}
protected ByteBuffer getFrameBuffer() {
return frameBuffer;
}
//轉換為下一個狀態,根據不同的狀態做不同的處理。該方法只會在selector thread中被呼叫,不用擔心併發
protected void transition(SelectionKey key) {
// 確保key是有效的
if (!key.isValid()) {
key.cancel();
Exception e = new TTransportException("Selection key not valid!");
onError(e);
return;
}
try {
switch (state) {
case CONNECTING:
doConnecting(key);//建連線
break;
case WRITING_REQUEST_SIZE:
doWritingRequestSize();//寫請求size
break;
case WRITING_REQUEST_BODY:
doWritingRequestBody(key);//寫請求體
break;
case READING_RESPONSE_SIZE:
doReadingResponseSize();//讀響應size
break;
case READING_RESPONSE_BODY:
doReadingResponseBody(key);//讀響應體
break;
default: // RESPONSE_READ, ERROR, or bug
throw new IllegalStateException("Method call in state " + state + " but selector called transition method. Seems like a bug...");
}
} catch (Exception e) {
key.cancel();
key.attach(null);
onError(e);
}
}
//出現異常時的處理
protected void onError(Exception e) {
client.onError(e);//置Client異常資訊
callback.onError(e);//回撥異常方法
state = State.ERROR;//置當前物件為ERROR狀態
}
//讀響應訊息體 private void doReadingResponseBody(SelectionKey key) throws IOException {
if (transport.read(frameBuffer) < 0) {
throw new IOException("Read call frame failed");
}
if (frameBuffer.remaining() == 0) {
cleanUpAndFireCallback(key);
}
}
//方法呼叫完成的處理
private void cleanUpAndFireCallback(SelectionKey key) {
state = State.RESPONSE_READ;//狀態轉換為讀取response完成
key.interestOps(0);//清空感興趣事件
key.attach(null);//清理key的附加資訊
client.onComplete();//將client的___currentMethod置為null
callback.onComplete((T)this);//回撥onComplete方法
}
//讀響應size,同樣可能需要多多次直到把sizeBuffer讀滿
private void doReadingResponseSize() throws IOException {
if (transport.read(sizeBuffer) < 0) {
throw new IOException("Read call frame size failed"); }
if (sizeBuffer.remaining() == 0) {
state = State.READING_RESPONSE_BODY;
//讀取FrameSize完成,為frameBuffer分配FrameSize大小的空間用於讀取響應體
frameBuffer = ByteBuffer.allocate(TFramedTransport.decodeFrameSize(sizeBufferArray));
}
}
//寫請求體
private void doWritingRequestBody(SelectionKey key) throws IOException {
if (transport.write(frameBuffer) < 0) {
throw new IOException("Write call frame failed");
}
if (frameBuffer.remaining() == 0) {
if (isOneway) {
//如果是單向RPC,此時方法呼叫已經結束,清理key並進行回撥
cleanUpAndFireCallback(key);
} else {
//非單向RPC,狀態轉換為READING_RESPONSE_SIZE
state = State.READING_RESPONSE_SIZE;
//重置sizeBuffer,準備讀取frame size
sizeBuffer.rewind();
key.interestOps(SelectionKey.OP_READ);//修改感興趣事件
}
}
}
//寫請求size到transport,可能會寫多次直到sizeBuffer.remaining() == 0才轉換狀態
private void doWritingRequestSize() throws IOException {
if (transport.write(sizeBuffer) < 0) {
throw new IOException("Write call frame size failed");
}
if (sizeBuffer.remaining() == 0) {
state = State.WRITING_REQUEST_BODY;
}
}
//建立連線
private void doConnecting(SelectionKey key) throws IOException {
if (!key.isConnectable() || !transport.finishConnect()) {
throw new IOException("not connectable or finishConnect returned false after we got an OP_CONNECT");
}
registerForFirstWrite(key);
}
}
總結
最後總結一下非同步客戶端的處理流程,如下圖所示。
需要注意的是,一個AsyncClient例項只能同時處理一個方法呼叫,必須等待前一個方法呼叫完成後才能使用該AsyncClient例項呼叫其他方法,疑問:和同步客戶端相比有什麼優勢?不用等返回結果,可以幹其他的活?又能幹什麼活呢?如果客戶端使用了連線池(也是AsyncClient例項池,一個AsyncClient例項對應一個連線),該執行緒不用等待前一個連線進行方法呼叫的返回結果,就可以去執行緒池獲取一個可用的連線,使用新的連線進行方法呼叫,而原來的連線在收到返回結果後,狀態變為可用,返回給連線池。這樣相對於同步客戶端單個執行緒序列傳送請求的情況,非同步客戶端單個執行緒進行傳送請求的效率會大大提高,需要的執行緒數變小,但是可能需要的連線數會增大,單個請求的響應時間會變長。線上程數是效能瓶頸,或對請求的響應時間要求不高的情況下,使用非同步客戶端比較合適。
相關文章
- Thrift RPC 系列教程(1)——Thrift語言RPC
- Thrift RPC 通訊搭建RPC
- Thrift RPC新增access logRPC
- JMeter 測試 thrift RPC 介面JMeterRPC
- Thrift RPC 系列教程(3)——模組化RPC
- RPC框架實踐之:Apache ThriftRPC框架Apache
- rpc框架之thrift連線池實現RPC框架
- 效能工具之Jmeter壓測Thrift RPC服務JMeterRPC
- Spring Cloud整合Thrift RPC(一) - 使用指南SpringCloudRPC
- Spring Cloud整合Thrift RPC(二) - 應用案例SpringCloudRPC
- Thrift使用入門(2) - 用Thrift實現一個簡單的Server/Client應用程式Serverclient
- CSharp使用Thrift作為RPC框架入門(一)CSharpRPC框架
- Thrift RPC 系列教程(5)—— 介面設計篇:struct & enum設計RPCStruct
- C#使用Thrift作為RPC框架實戰(四)之TSocketC#RPC框架
- guide-rpc-framework 流程梳理GUIIDERPCFramework
- C#使用Thrift作為RPC框架入門(三)之三層架構C#RPC框架架構
- 介面自動化測試:Thrift框架RPC協議客戶端開發框架RPC協議客戶端
- Rpc-實現Client對ZooKeeper的服務監聽RPCclient
- 深入淺出 Redis client/server互動流程RedisclientServer
- hive metastore異常 org.apache.thrift.protocol.TProtocolException: Missing version in readMessageBegin, old clientHiveASTApacheProtocolExceptionclient
- Thrift示例
- ImportError: No module named thrift.Thrift問題解決ImportError
- thrift安裝
- Thrift c#C#
- 分享一款非官方 Hyperf RPC 客戶端 huangdijia/jet-clientRPC客戶端client
- Thrift使用入門(1) - Thrift概述及其安裝
- 4.WebStorm 建立vue專案,can not install ‘ij-rpc-client’/npm ERR!WebORMVueRPCclientNPM
- Mac 安裝thriftMac
- Thrift 入門教程
- thrift with Go (0.11.0)Go
- ubuntu下安裝thriftUbuntu
- Thrift-java例項Java
- Thrift架構~目錄架構
- Thrift IDL 快速入門
- Thrift的網路堆疊
- golang 網路框架之 thriftGolang框架
- Thrift之Protocol原始碼分析Protocol原始碼
- 如何使用thrift 服務引擎元件元件