gRPC學習記錄(六)--客戶端連線池
對於客戶端來說建立一個channel是昂貴的,因為建立channel需要連線,但是建立一個stub是很簡單的,就像建立一個普通物件,因此Channel就需要複用,也就是說需要實現一個連線池應用.本文使用commons-pool2
來實現連線池應用. 該案例可以當成連線池模板案例.
<!--客戶端連線池--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.4.2</version> </dependency>
寫法的封裝類似我的另一篇博文: ,模仿SpringJdbcTemplate模板類寫法.
首先定義一個回撥介面.
public interface WorkCallBack<S> { void callback(S s); }
再者定義一個產生連線池的工廠,需要繼承自BasePooledObjectFactory,其用處是產生連線池中需要的客戶端.
public class HelloWorldFactory extends BasePooledObjectFactory<HelloWorldClientSingle> { private String host = "127.0.0.1"; private int port = 50051; @Override public HelloWorldClientSingle create() throws Exception { return new HelloWorldClientSingle(this.host,this.port); } @Override public PooledObject<HelloWorldClientSingle> wrap(HelloWorldClientSingle helloWorldClientSingle) { return new DefaultPooledObject<>(helloWorldClientSingle); } @Override public void destroyObject(PooledObject<HelloWorldClientSingle> p) throws Exception { p.getObject().shutdown(); super.destroyObject(p); } }
實現相應的連線池,注意看execute()
方法,該方法是一個模板方法,進行從池中獲取客戶端和歸還客戶端給連線池,其主要邏輯都定義在WorkCallBack
介面中,也因此從服務端拿回的資料要在其裡面處理完畢.
public class HelloWorldClientPool { private static GenericObjectPool<HelloWorldClientSingle> objectPool = null; static { // 連線池的配置 GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); // 池中的最大連線數 poolConfig.setMaxTotal(8); // 最少的空閒連線數 poolConfig.setMinIdle(0); // 最多的空閒連線數 poolConfig.setMaxIdle(8); // 當連線池資源耗盡時,呼叫者最大阻塞的時間,超時時丟擲異常 單位:毫秒數 poolConfig.setMaxWaitMillis(-1); // 連線池存放池化物件方式,true放在空閒佇列最前面,false放在空閒佇列最後 poolConfig.setLifo(true); // 連線空閒的最小時間,達到此值後空閒連線可能會被移除,預設即為30分鐘 poolConfig.setMinEvictableIdleTimeMillis(1000L * 60L * 30L); // 連線耗盡時是否阻塞,預設為true poolConfig.setBlockWhenExhausted(true); // 連線池建立 objectPool = new GenericObjectPool<>(new HelloWorldFactory(), poolConfig); } /** * 從連線池獲取物件 */ private static HelloWorldClientSingle borrowObject(){ try { HelloWorldClientSingle clientSingle = objectPool.borrowObject(); System.out.println("總建立執行緒數"+objectPool.getCreatedCount()); return clientSingle; } catch (Exception e) { e.printStackTrace(); } //連線池失敗則主動建立 return createClient(); } /** * 當連線池異常,則主動建立物件 */ private static HelloWorldClientSingle createClient(){ return new HelloWorldClientSingle("127.0.0.1", 55001); } /** * 執行器 * @param workCallBack 主要服務內容 */ public static Runnable execute(WorkCallBack<HelloWorldClientSingle> workCallBack){ return () -> { HelloWorldClientSingle client = borrowObject(); try { workCallBack.callback(client); } finally { /** 將連線物件返回給連線池 */ objectPool.returnObject(client); } }; } }
對於客戶端來說,因為存根是不能共享的,所以存根要放在呼叫函式中例項化,不要擔心效能問題,這個操作就是建立一個物件.greeterBlockingStub = GreeterGrpc.newBlockingStub(channel).withCompression("gzip");
該程式碼從之前的建構函式中移位到了greet中.
public class HelloWorldClientSingle { private final ManagedChannel channel; //一個gRPC通道 private GreeterGrpc.GreeterBlockingStub greeterBlockingStub;//阻塞/同步 存根 //初始化通道和存根 public HelloWorldClientSingle(String host,int port){ channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build(); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } //客戶端方法 public void greet(String name){ //需要用到存根時建立,不可複用 greeterBlockingStub = GreeterGrpc.newBlockingStub(channel).withCompression("gzip"); HelloRequest request = HelloRequest.newBuilder().setName(name).build(); HelloReply response; try { response = greeterBlockingStub.sayHello(request); } catch (StatusRuntimeException e) { System.out.println("RPC呼叫失敗:"+e.getMessage()); return; } System.out.println("伺服器返回資訊:"+response.getMessage()); } }
寫一個簡單的測試類
public class HelloWorldClientTest { public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread( HelloWorldClientPool.execute(clientSingle -> { clientSingle.greet("world"); })).start(); } } }
因為我限定的8個客戶端,所以最高也就8個channel再跑了.
Paste_Image.png
作者:此博廢棄_更新在個人部落格
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2618/viewspace-2820539/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mysql、redis 客戶端連線池MySqlRedis客戶端
- Presto學習筆記——Go客戶端連線PrestoREST筆記Go客戶端
- Java 客戶端 Jedis和JedisPool 連線池Java客戶端
- impala客戶端連線客戶端
- OceanBase學習之路7|透過 MySQL 客戶端連線 OceanBase 租戶MySql客戶端
- 某客戶系統tomcat連線池連線異常Tomcat
- Redis學習筆記(十) 客戶端Redis筆記客戶端
- Go基於gRPC實現客戶端連入服務端GoRPC客戶端服務端
- Redis客戶端連線數DevOpsRedis客戶端dev
- grpc套路客戶端編寫RPC客戶端
- GRPC Android客戶端演化史RPCAndroid客戶端
- swoole 之建立一個 MySQL 連線池 學習分享記錄 [持續更新]MySql
- HikariCP連線池的學習
- 比特幣學習筆記——————3、比特幣客戶端比特幣筆記客戶端
- Golang 學習筆記(一) - HTTP 客戶端 - 基礎Golang筆記HTTP客戶端
- GRpc新增客戶端的五種方式RPC客戶端
- Go gRPC 系列三:流式客戶端和服務端GoRPC客戶端服務端
- Oracle 19c中連線RMAN客戶端的連線方法Oracle客戶端
- 記錄一次網路連線除錯問題只有tcp客戶端為什麼自己會連線上自己除錯TCP客戶端
- 最近學習了Http連線池HTTP
- 使用 WebSocket 客戶端連線 MQTT 伺服器Web客戶端MQQT伺服器
- 客戶端怎麼連線到伺服器?客戶端伺服器
- gRPC負載均衡(客戶端負載均衡)RPC負載客戶端
- 一次獲取客戶端 IP 記錄客戶端
- 客戶端筆記客戶端筆記
- Golang 學習筆記(二) - HTTP 客戶端 - 使用 Client 型別Golang筆記HTTP客戶端client型別
- gRPC入門學習之旅(六)RPC
- 使用 Java 客戶端透過 HTTPS 連線到 EasysearchJava客戶端HTTP
- HTTP客戶端連線,選擇HttpClient還是OkHttp?HTTP客戶端client
- 4.2.14 啟用客戶端快速連線故障轉移客戶端
- ESP作為單連線中的TCP客戶端TCP客戶端
- 記錄連線數導致警報失效,連線池少問題
- gRPC 的增刪改查系列之客戶端RPC客戶端
- java版gRPC實戰之四:客戶端流JavaRPC客戶端
- php連結nsq客戶端PHP客戶端
- gRPC學習記錄(一)--概念性知識RPC
- 雲端計算學習路線教程大綱課件:客戶端查詢客戶端
- Go gRPC 系列二:一元客戶端與服務端GoRPC客戶端服務端