擊上方 "程序員小樂"關注, 星標或置頂一起成長
每天凌晨00點00分, 第一時間與你相約
每日英文
Someday, you will find the one, who will watch every sunrise with you until the sunset of your life.
總有一天,你會遇上那個人,陪你看每一次日出,直到你的人生落幕。
每日掏心話
每個人的心里,都有一個禁地,不愿再觸及,也不愿再想起,卻永遠無法忘記。既然忘不了,就不必費神忘記,做人本就很累,何必再自尋煩惱。
來自:等你歸去來 | 責編:樂樂
鏈接:cnblogs.com/yougewe/p/10327217.html
程序員小樂(ID:study_tech)第 835 次推文 圖片來自百度
往日回顧:手把手教你如何解決代碼中 if…else 過多的問題
正文
談到線上環境,一般開發同學,不太容易接觸到。即使接觸到,也只是其中的冰山一角!
所以,其實說起線上環境的部署,咱們好像都有點懂,但是又都不一定完全懂!網上的知識無窮無盡,但往往都是各司一職,對于普通同學,很難窺其全貌!
所以,我今天就來說說,一些普通的線上環境的部署步驟,和一些腳本小技巧吧。只希望通過這篇文章,能夠讓大家有一個運維的全局觀!
我將會分幾條線來整理咱們的運維思路!
一、從理論上講,我們應該怎么做?
1.針對的是什么樣的用戶群體,體量大概會有多少?
這是一個部署規劃的前題。為啥呢?
一、如果你針對的是后臺管理員,人數也不多,那么你可能只需要一個服務器就可以了,前后端也都可以部署在同一臺服務器上;如果稍微考慮下單點故障問題,則頂多兩臺服務器搞定!
二、如果針對的是前端普通用戶,那么,往往就會考慮多機部署,前后端分離,單點問題,負載均衡了;至于具體要部署多少臺,則要根據你的用戶情況來定了,當然,前期一般沒必要部署很多臺服務器!更多的考慮是橫向擴展的能力。只要能支持橫向擴展,則短期內,往往不用擔心性能和架構問題!
2.為支持預估的用戶量,大概需要多少的帶寬?
有訪問就會有流量產生,而預估的用戶量,則是一個帶寬資源需求的一個決斷依據!
一般針對前期用戶不太確定的場景,可以先買個 10M 左右的共享帶寬,基本能夠應付;經過一段時間的觀察后,再進行帶寬的變更也可以;
當然,考慮帶寬,自然也會存在一個公網IP的問題,因為流量是從IP進來的。而在IP之前,則是域名的訪問。域名問題則又涉及到DNS,不必細說!
公網IP可以是直接指向機器的,也可以是指向負載均衡器的。如果想要支持橫向擴展,則IP的指向一定是一個負載均衡器。因為只有這樣,當遇到流量突增,或者做活動的時候,才能更快速的進行擴容!
3.數據庫規劃如何?
數據在當下時代,算是重中之重了。機器沒了可以再買,代碼沒了可以再寫,但是數據沒了就完蛋了!
數據庫一般要遵從幾個基本原則: 一、帶寬要大;二、運算速度要快;三、要能承受足夠大的運算空間;(即:帶寬足夠大/cpu核數夠多/內存容量夠大/最大并發連接數/…)
所以,一般不要在數據庫上省錢,能多點就多點!
另外,也不要什么樣的數據都往數據庫(關系型數據庫)存,搞清楚各類型數據庫的強項與弱項,做出明智的選擇。否則會帶來很多不必要的麻煩!
4.應用要基于操作系統來部署還是基于容器來部署?
這是個決策性的問題!基于操作系統的部署,是一種比較傳統和常見的部署方式。優點是,很多系統工具都是完善的,只要你大概知道要部署什么,部署下來一般不會有太多問題,因為這是個完整的系統。
但是,由于系統與系統之間可能不能完全一致,有各種各樣的差異,所以,你在這個機器上運行成功的東西,在另外的機器上則不一定能成功。因此,基于系統的部署將會使我們的問題排查難度大大增加,而且移值性會很差。比如你在機器A上安裝了10個軟件,你可能配置了n個選項,但是,當你在安裝B機器的時候,你并不能很好的利用原有的配置,你還得從頭一個個地來!
因此,有另一個部署方案,基于容器的部署(我這里是基于docker容器的部署)。docker就類似于一個個的虛擬機,但是它更加輕量級,當一個docker部署好后,你可以任意復制到其他機器上運行,看起來很誘人吧。
不過,docker只是入門級容器,對于大量集群容器的管理,還是顯得力不從心,當然你很容易找到另一個方案: Kubernetes (K8s); 你只要花上少許的時間了解下,你就可以應用了!
當然了,使用容器的方案,有沒有什么缺點呢?應該是有的,比如本來可以基于系統的監控方案,因為接入容器后,監控指標則不一定適用了,當然現成的方案還是有的,不過得另外再花點時間研究了。再比如:如果容器出了問題,是否能排查出來,這也是另一個問題!
5.都有些什么樣的基礎設施或者中間件?
想要運行應用程序,自然是先考慮運行環境的。比如:應用需要 nginx 來做http服務器,用 tomcat 來做java web應用服務器,用redis來做緩存中間件,用zk來做應用協調中間件,用rabbitmq來做消息中間件,等等!
因此,要在代碼跑起來之前,先要把這些環境給準備好咯。
準備這些中間件或基礎設施之前,也要問下當下的形勢,是否有高性能高可用應用需求?比如:是否需要集群部署,或者單機部署?往往集群部署又會依賴其他的中間件!也更復雜!
當然,這些都不是事。事兒是在出問題之后,能夠有意識,能夠猜測到問題發生的點!
6.應用代碼應該怎樣部署?
當基礎環境就緒后,就應該讓主角上場了。應用代碼怎么部署?
最簡單的: 通過ftp上傳代碼到服務器上后,一個個部署!這種方案是最原始的,也是在沒有辦法搞更好的方案的時候使用的,不應長期使用;
稍微好點的: 使用集成工具(如jenkins)進行打包,然后上傳一個私有yum鏡像服務器(yum 源)。然后在線進行yum 安裝;這種方式,借助了集成工具,幾個好處:
可以檢測代碼合法性如:單元測試、代碼規范(可能需要插件);
對任何的改動有簡單留檔,可以備查的同時,也為代碼的回滾提供了可能;
減少了手動上傳導致的包破壞的可能性;
適合大規模應用;
再成熟點的: 再往后面,手動 yum 安裝也已經太累了,所以急需一個部署平臺,實現自動化部署;(這里的自動化部署可能就是基于CI集成部署的一種升級版)。總之,大大減小了人工參與程序,提升了效率,同時也保證了質量!當然,這種部署平臺已經經過了嚴格的測試,出錯的可能性也比較小了!
7.服務器的安全性?
不考慮服務器的安全性的應用,無異于自暴自棄。黑客無處不在,不過幸好現在系統也是越來越完善,只要稍加控制,即不那么容易被攻破了。但是如果放棄安全防護,則隨便來一個菜鳥程序員就把你搞死了,那時的損失就大了。推薦:如何設計一個安全的對外接口
網絡安全是個很專業的領域,我不敢造次去談它。不過我們可以簡單的做下防護: 如防火墻、授權操作、病毒庫等等。當然,如果使用xx云服務,則輕松方便多了,在后臺點點設置幾下搞定!
8.服務的可監控性?
無監控,不上線!
這是一個警示,如果線上服務沒有監控,則所有線上的東西,都成了盲區,這對程序員GG們來說,簡直太糟糕了,雖然他們很自信!
監控分兩個方面:一是系統級別的監控;二是應用級別的監控;(一般忽略其他監控: 如網絡)
系統級別的監控一般可以安裝第三方的軟件來解決: 如 zabbix, grafana …
而應用級別的監控,則需要自己擁有一套監控代碼了,而這對初期項目,則往往比較吃力。當然,如果引入一些開源的解決方案也是可以的,比如 ELK, 做到分布式日志中心的作用的同時,也可以根據日志做相應的應用報錯監控!然而這又涉及另外的機器費用和人力成本問題,也顯得不那么簡單了。
而如果使用xx云服務,則往往都會自帶服務器監控的,可以很方便地查看到服務器情況,站在高層次預估應用是否存在潛藏的問題!
如上,就是一些個人覺得的在部署一整套線上環境的時候,需要考慮的事項!從理論上講解了下個人見解,不對之處,請賜教!
二、接下來,我將給到一些實際的操作捷徑或提示?(linux)
1.免密登錄服務器?
在n服務器之間跳轉,如果每次都要求輸入密碼,那確實太煩了。尤其在密碼一般還很不容易記住的情況下!
所以,可以將一臺服務器作為跳板機,在這臺服務器上,可以免密地登錄到允許的n臺子服務器;
操作步驟有二:
# 1. 先使用 ssh-keygen 生成本機的key
ssh-keygen -t rsa # 如果已生成不要重復生成
# 2. 使用 ssh-copy-id 將本機的 key 發送到需要免密登錄的服務器,首次copy時會要求輸入密碼,后續則免密了
ssh-copy-id -i ~/.ssh/id_rsa.pub root@172.1.2.111
2.服務器之間文件(夾)拷貝?
拷貝文件的目的有很多,比如:代碼同步,文件同步,資源同步,甚至是會話同步….
# 1. 使用scp 拷貝文件
scp /home/ol-web.war root@xxx.com:/www/tomcat/wepapps/ # 從本機拷貝到遠程
scp /home/ol-web.war root@xxx.com:/www/tomcat/wepapps/ # 從遠程拷貝到本機
scp -r /www/nginx/html/ root@.2.3.2:/www/nginx/html/ # 從本機拷貝文件夾到遠程
# 2. 使用 rsync 同步文件,(可能需要安裝 rsync 服務)
rsync -av --delete /www/nginx/html/ root@.2.3.1:/www/nginx/html/ # 同步所有屬性,本地刪除的文件也同步遠程刪除
其中,scp一般是系統自帶的命令,而rsync則需要自行安裝服務。
scp復制你可以認為是增量復制,所以遠程文件往往會越來越大,垃圾文件越來越多。
而rsync則是保持兩端完全一致,可能會符合應用場景!但是,別忘了把rsync服務加入到開機啟動項中!
3.快捷使用 ssh 等等命令,使用 tab 鍵進行信息補全?
當使用 ssh / scp 等等命令操作的時候,其操作對象往往 1.2.3.x 這樣的ip顯示,如果不能友好點,那確實太累了!我們可以如下操作,以實現 ssh 也能更好的記憶:
# 在文件 /root/.bashrc 中,添加腳本如下,使自動補全添加 ssh
# auto complete ...
complete -W "$(echo $(grep -v '^$|#' .ssh/config | sort -u | sed 's/^ssh //'))" ssh
# 在文件 /root/.ssh/config 中,添加需要自動補全的服務器,
Host 172.2.3.5 server-api-01
Host 172.2.3.6 server-api-02
# 以上服務器名字需要在 /etc/hosts 文件中添加相應解析
# 而登錄 server時,只需, ssh server-api-01 即可
如上補全工作,無需在所有服務器上進行操作,只需在相應的跳板機上提供功能即可!
4.簡要 saltstack 搭建指南?
salt 是個方便易用的集群管理工具,比如你可以用于批量重啟服務,全局搜索日志等等;
# 1. 安裝, 僅需到相應機器上安裝即可
yum install salt-master salt-minion
# 2. 配置 /etc/salt/master /etc/salt/minion, 最簡單的,只需修改 minion 配置,指向 master 的ip即可;
#指定master,冒號后有一個空格, minion
master: 172.1.2.22
id: server-api-01
user: root
# 3. 啟動所有節點, status, restart
systemctl start salt-master # 162機器可用
systemctl start salt-minion
/etc/init.d/salt-master start # 155機器可用
/etc/init.d/salt-minion start
# 4. 將所有salt-minion 添加到 master 集群管理
salt-key -A
# 5. 登錄跳板機 api_01, 運行salt 操作,執行集群管理工作
salt server-api-02 cmd.run 'lsof -i:80'
salt '*' test.ping
5.簡要集群復制shell腳本?
有時,你可能需要將你的應用發布到n臺服務中,你可以直接改如下shell,也可以依賴于salt這樣的高級工具進行發布!shell 參考如下:
#!/bin/bash
# find out my ip to exclude...
MY_MERCHINE_IP=`ifconfig eth0 |awk -F "[: ]+" '/inet addr/{print }'`;
MERCHINE_IP_LIST="172.1.2.7 172.1.3.4";
for m_ip in $MERCHINE_IP_LIST;
do
if [[ $m_ip !=$MY_MERCHINE_IP ]]; then
echo "- Installing apps to mechine@${m_ip} ...";
# install api apps
scp /www/test/hello-1.0.0-SNAPSHOT.jar root@${m_ip}:/www/test/
rsync -av --delete /www/html/ root@${m_ip}:/www/html/
echo "- Install apps to merchine@${m_ip} done.";
fi;
done;
6.簡要docker搭建指南?
docker 作為一個容器化的基石,一出世就被追棒。包括現在的 k8s ,也是基于docker的。docker 可以讓你在一處搭建,處處運行,從而避免每次新買機器就要搞很久的尷尬局面;其搭建也是很簡單的(簡單應用):
為方便任意發揮,我們可以基于centos這種系統級別的鏡像進行創建自己的image;
# docker 安裝:
yum install docker
service docker start
# 拉取 centos6 的 docker 鏡像
docker pull centos:6
docker images
# 構建一個 image, 創建空目錄,編輯 Dockerfile
vim Dockerfile # 內容可變
FROM centos:6
MAINTAINER oom <w@163.com>
# move all configuration files into container
# RUN yum install -y lsof
# EXPOSE 80
# CMD ["sh","-c","service httpd start;bash"]
# 創建鏡像
docker build -t tmp_image:1.0 .
# 創建并運行容器
docker run -h tmp_container -itd --name tmp_container -v /opt/docker/webapps:/www/webapp tmp_image:1.0
# 進入容器,相當于進入 centos 操作系統
docker exec -it tmp_container bash
# 保存容器修改到images
docker commit -m 'web final.' 49d79fc19eaa tmp_image:1.2
# 備份容器修改后的docker鏡像
docker save > /opt/images/images_final/tmp_image.final.tar tmp_image:1.2
# 恢復你的備份鏡像,即全網發布
# 可以在任何裝 docker 的地方加載保存的鏡像
docker load -i /opt/images/images_final/tmp_image.final.tar
7.定制你的登錄歡迎語?
由于可能存在線上環境與測試環境共存的情況,一不小心的切換錯誤,就可能導致不可挽回的損失。所以,如果我們能在登錄的時候,做一個簡單的提示,那么就會少一點出錯的可能性。所以,訂制你的登錄歡迎語吧!
# 修改登錄歡迎語 vim /etc/motd
*****************************************************************
!!! WARNING: 歡迎來到線上機器: service-api-01 ,請謹慎操作哦 !!!
*****************************************************************
這樣,用戶登錄后,就會清楚的知道自己是在操作生產環境了!
8.更方便的查看nginx的訪問日志?
對于后端的日志而言,往往都是主動打印到某個固定位置,從而開發人員可以直接使用 tail -f xxx.log 進行日志的查看!
然而對于前端的代碼而言,則往往沒有相應的開發日志,唯一可以借助的就是 http 服務器的日志來排查問題了!
所以,比如使用 nginx 作為 http 服務器,那么就應該把盡可能多的有用日志打印出來。那么,如何快速查看 nginx 日志,則是有必要的!比如我們可以這樣:
# vim /usr/bin/log_nginx_host , 使用 log_nginx_host 直接查看所有 nginx 日志
tail -f /var/log/nginx/access.log /var/log/nginx/error.log
如上,將會把訪問日志與錯誤日志一起打印出來,從而快速定位問題!
歡迎在留言區留下你的觀點,一起討論提高。如果今天的文章讓你有新的啟發,學習能力的提升上有新的認識,歡迎轉發分享給更多人。
猜你還想看
阿里、騰訊、百度、華為、京東最新面試題匯集
從上帝視角看Java如何運行
一次項目代碼重構:使用Spring容器干掉條件判斷
IDEA-2020.1 版本針對調試器和代碼分析器的改進,值得期待
關注訂閱號「程序員小樂」,收看更多精彩內容
嘿,你在看嗎?
Grpc的優勢這里我就不說了, 第一它是基于Http2.0協議的, 可以保持客戶端與服務器端長連接, 基于二進制流,也就是字節流, 不是文本流.
? 同時他提供了跨平臺(語言)的開發方案 , 但是他也有成本就是需要定義他的接口規范, 遵循他的一套規范, 也就是說就算你是Java語言, 你不能隨意定義一個接口, 我就能幫你實現RPC , 只是他可以幫助你生成一個符合他規范的接口.
? 我們還是快速體驗一下吧. pom配置在文章最后
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>1.12.0</version>
</dependency>
插件和全部依賴都在文章最后面 . 全局粘貼
idea 介意下載一個 protobuf的插件, 可以有代碼提示. 這里直接去pluging里搜就行了.
我使用的是proto3的版本.
可以參考一下這個文章 https://www.cnblogs.com/tohxyblog/p/8974763.html
注意這個文件是在 你的src/proto/XX.proto 中定義的, 文件目錄必須寫好.
syntax="proto3"; // 協議版本
// 選項配置
option java_package="com.example.grpc.api";
option java_outer_classname="RPCDateServiceApi";
option java_multiple_files=true;
// 定義包名
package com.example.grpc.api;
// 服務接口.定義請求參數和相應結果
service RPCDateService {
rpc getDate (RPCDateRequest) returns (RPCDateResponse) {
}
}
// 定義請求體
message RPCDateRequest {
string userName=1;
}
// 定義相應內容
message RPCDateResponse {
string serverDate=1;
}
使用maven插件, 編譯.
第一個命令執行完. 在 target目錄里找就行了. 第二個命令也就是找就行了. 然后將生成的Java文件拷貝到你的目錄里.就可以了, 類似于Mybatis的mapper插件.
package com.example.grpc.service;
// RPCDateServiceGrpc.RPCDateServiceImplBase 這個就是接口.
// RPCDateServiceImpl 我們需要繼承他的,實現方法回調
public class RPCDateServiceImpl extends RPCDateServiceGrpc.RPCDateServiceImplBase {
@Override
public void getDate(RPCDateRequest request, StreamObserver<RPCDateResponse> responseObserver) {
// 請求結果,我們定義的
RPCDateResponse rpcDateResponse=null;
String userName=request.getUserName();
String response=String.format("你好: %s, 今天是%s.", userName, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
try {
// 定義響應,是一個builder構造器.
rpcDateResponse=RPCDateResponse
.newBuilder()
.setServerDate(response)
.build();
} catch (Exception e) {
responseObserver.onError(e);
} finally {
// 這種寫法是observer,異步寫法,老外喜歡用這個框架.
responseObserver.onNext(rpcDateResponse);
}
responseObserver.onCompleted();
}
}
public class GRPCServer {
private static final int port=9999;
public static void main(String[] args) throws Exception {
// 設置service接口.
Server server=ServerBuilder.
forPort(port)
.addService(new RPCDateServiceImpl())
.build().start();
System.out.println(String.format("GRpc服務端啟動成功, 端口號: %d.", port));
server.awaitTermination();
}
}
public class GRPCClient {
private static final String host="localhost";
private static final int serverPort=9999;
public static void main(String[] args) throws Exception {
// 1. 拿到一個通信的channel
ManagedChannel managedChannel=ManagedChannelBuilder.forAddress(host, serverPort).usePlaintext().build();
try {
// 2.拿到道理對象
RPCDateServiceGrpc.RPCDateServiceBlockingStub rpcDateService=RPCDateServiceGrpc.newBlockingStub(managedChannel);
RPCDateRequest rpcDateRequest=RPCDateRequest
.newBuilder()
.setUserName("anthony")
.build();
// 3. 請求
RPCDateResponse rpcDateResponse=rpcDateService.getDate(rpcDateRequest);
// 4. 輸出結果
System.out.println(rpcDateResponse.getServerDate());
} finally {
// 5.關閉channel, 釋放資源.
managedChannel.shutdown();
}
}
}
以上就是完整的流程. 啟動服務器端, 啟動客戶端打印一下信息 :
服務端日志 :
2020-02-29 11:04:50,991 4689 [LG-3-1] DEBUG .grpc.netty.NettyServerHandler - [id: 0xed01e3fb, L:/127.0.0.1:9999 - R:/127.0.0.1:3994] INBOUND SETTINGS: ack=true
2020-02-29 11:04:51,075 4773 [LG-3-1] DEBUG .grpc.netty.NettyServerHandler - [id: 0xed01e3fb, L:/127.0.0.1:9999 - R:/127.0.0.1:3994] INBOUND HEADERS: streamId=3 headers=GrpcHttp2RequestHeaders[:path: /com.example.grpc.api.RPCDateService/getDate, :authority: localhost:9999, :method: POST, :scheme: http, te: trailers, content-type: application/grpc, user-agent: grpc-java-netty/1.12.0, grpc-accept-encoding: gzip, grpc-trace-bin: ] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false
2020-02-29 11:04:51,125 4823 [LG-3-1] DEBUG .grpc.netty.NettyServerHandler - [id: 0xed01e3fb, L:/127.0.0.1:9999 - R:/127.0.0.1:3994] INBOUND DATA: streamId=3 padding=0 endStream=true length=14 bytes=00000000090a07616e74686f6e79
2020-02-29 11:04:51,172 4870 [LG-3-1] DEBUG .grpc.netty.NettyServerHandler - [id: 0xed01e3fb, L:/127.0.0.1:9999 - R:/127.0.0.1:3994] OUTBOUND HEADERS: streamId=3 headers=GrpcHttp2OutboundHeaders[:status: 200, content-type: application/grpc, grpc-encoding: identity, grpc-accept-encoding: gzip] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false
2020-02-29 11:04:51,189 4887 [LG-3-1] DEBUG .grpc.netty.NettyServerHandler - [id: 0xed01e3fb, L:/127.0.0.1:9999 - R:/127.0.0.1:3994] OUTBOUND DATA: streamId=3 padding=0 endStream=false length=44 bytes=00000000270a25e4bda0e5a5bd3a20616e74686f6e792c20e4bb8ae5a4a9e698af323032302d30322d32392e
2020-02-29 11:04:51,190 4888 [LG-3-1] DEBUG .grpc.netty.NettyServerHandler - [id: 0xed01e3fb, L:/127.0.0.1:9999 - R:/127.0.0.1:3994] OUTBOUND HEADERS: streamId=3 headers=GrpcHttp2OutboundHeaders[grpc-status: 0] streamDependency=0 weight=16 exclusive=false padding=0 endStream=true
2020-02-29 11:04:51,204 4902 [LG-3-1] DEBUG .grpc.netty.NettyServerHandler - [id: 0xed01e3fb, L:/127.0.0.1:9999 - R:/127.0.0.1:3994] INBOUND GO_AWAY: lastStreamId=0 errorCode=0 length=0 bytes=
客戶端日志 :
2020-02-29 11:00:43,480 1814 [LG-1-2] DEBUG .grpc.netty.NettyClientHandler - [id: 0xcdbd6064, L:/127.0.0.1:3817 - R:localhost/127.0.0.1:9999] INBOUND HEADERS: streamId=3 headers=GrpcHttp2ResponseHeaders[grpc-status: 0] streamDependency=0 weight=16 exclusive=false padding=0 endStream=true
你好: anthony, 今天是20-02-29.
2020-02-29 11:00:43,487 1821 [LG-1-2] DEBUG .grpc.netty.NettyClientHandler - [id: 0xcdbd6064, L:/127.0.0.1:3817 - R:localhost/127.0.0.1:9999] OUTBOUND GO_AWAY: lastStreamId=0 errorCode=0 length=0 bytes=
這就是一個Grpc的完整流程.
定義都是一個CS模型, GRPC他看到了未來一定是HTTP2的天下(這是必然的趨勢), 所以它沒有制定自己的協議, 這里指的是應用層協議. 類似于我們的RestTemplate 一樣都是基于http協議.
所以它考慮到的是 JSON ,這種序列化比較慢的序列化方式. 采用了自己開發的一種Protobuf.
這里就說明了 GRPC其實只是解決了序列化的方式, 依靠這個Protobuf, 可以解決一系列問題, 比如接口信息的定義, 等等有很多,
最簡單的例子. 比如我Java中寫了一個echo() 接口, golang如何調用 ? . 這就是難點,
我們可以依靠統一的Protobuf文件生成對應的 Golang和Java的接口, 就可以了, 所以說本質上來說他是做了這點.
我們看看Dubbo做了什么 , 他依靠TCP的可靠性, 自己基于TCP實現了一個應用層協議, dubbo協議. 同時也引用了一堆的序列化方式, 所以整個GRPC也是可行的.
?
感興趣的同學可以做一次抓包, 抓取客戶端請求,分析一個GRPC的請求格式.
*請認真填寫需求信息,我們會在24小時內與您取得聯系。