因爲gRPC主要是谷歌開發的,因爲一些已知的緣由,gRPC跑demo仍是不那麼順利的。單獨寫這一篇,主要是gRPC安裝過程當中的坑太多了,記錄下來讓你們少走彎路。php
主要的坑:html
go mod
增長映射規則到github倉庫,github下載也是龜速。本文講解gRPC demo的同時,會介紹如何解決這些坑。本文對應的Github地址:https://github.com/52fhy/grpc-sample 。該倉庫存儲了demo示例,以及部分系統編譯好的二進制包,你們以爲有些步驟裏耗時實在太長了,能夠直接clone該倉庫,複製二進制包到對應目錄(僅限測試開發,生產環境仍是老老實實本身編譯吧)。java
gRPC命令行工具編譯須要使用 GCC4.8及以上版本。CentOS6系列的內置版本是GCC4.7。node
使用
gcc --version
能夠查看版本。python
若是你的系統GCC版本>=4.8,能夠忽略本節。若是僅使用golang、java,請忽略本節。c++
注:不建議你們下載GCC源碼包或者使用yum下載GCC4.8及以上版本,緣由:
1) 源碼包安裝真的是很是很是的慢 2) yum 源下載速度慢的像蝸牛。下面的SCL安裝方法是推薦你們用的,安裝好後原來的版本還能用。git
若是須要升級gcc至4.8或更高版本,建議直接採用安裝SCL
源以後安裝devtoolset-6
(devtoolset-6目前gcc版本爲6.3),由於devtoolset-4
及以前的版本都已經結束支持,只能經過其餘方法安裝。github
升級到gcc 6.3:golang
yum -y install centos-release-scl yum -y install devtoolset-6-gcc devtoolset-6-gcc-c++ devtoolset-6-binutils scl enable devtoolset-6 bash
須要注意的是scl命令啓用只是臨時的,退出shell或重啓就會恢復原系統gcc版本。若是要長期使用gcc 6.3的話:shell
echo "source /opt/rh/devtoolset-6/enable" >>/etc/profile
這樣退出shell從新打開就是新版的gcc了。其它版本同理。
升級到gcc 7.3:
yum -y install centos-release-scl yum -y install devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-binutils scl enable devtoolset-7 bash
已經中止支持的devtoolset4(gcc 5.2)及以前版本的安裝方法,可能比較慢,你們感興趣的話能夠嘗試。
升級到gcc 4.8:
wget http://people.centos.org/tru/devtools-2/devtools-2.repo -O /etc/yum.repos.d/devtoolset-2.repo yum -y install devtoolset-2-gcc devtoolset-2-gcc-c++ devtoolset-2-binutils scl enable devtoolset-2 bash
升級到gcc4.9:
wget https://copr.fedoraproject.org/coprs/rhscl/devtoolset-3/repo/epel-6/rhscl-devtoolset-3-epel-6.repo -O /etc/yum.repos.d/devtoolset-3.repo yum -y install devtoolset-3-gcc devtoolset-3-gcc-c++ devtoolset-3-binutils scl enable devtoolset-3 bash
升級到gcc 5.2:
wget https://copr.fedoraproject.org/coprs/hhorak/devtoolset-4-rebuild-bootstrap/repo/epel-6/hhorak-devtoolset-4-rebuild-bootstrap-epel-6.repo -O /etc/yum.repos.d/devtoolset-4.repo yum install devtoolset-4-gcc devtoolset-4-gcc-c++ devtoolset-4-binutils -y scl enable devtoolset-4 bash
若是僅使用golang、java,請忽略本節。
gRPC分C、JAVA、GO、NodeJS版本,C版本包括C++, Python, Ruby, Objective-C, PHP, C#,這些語言都是基於C版本開發的,共用代碼庫一個代碼庫。
若是使用C版本的gRPC,最終要從源碼裏編譯出下列工具:
grpc_cpp_plugin grpc_csharp_plugin grpc_node_plugin grpc_objective_c_plugin grpc_php_plugin grpc_python_plugin grpc_ruby_plugin
這些工具做爲插件供proto編譯器使用。須要先下載 grpc/grpc
github上的源碼。
git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc cd grpc git submodule update --init make && sudo make install # 生成的插件路徑 ll ./bins/opt/ # 複製到bin目錄 cp -r ./bins/opt/* /usr/local/bin/
這裏有2個坑:
一、grpc/grpc
倉庫比較大,鑑於國內訪問的網速,建議使用國內鏡像。碼雲(https://gitee.com)提供了同步更新的鏡像地址:
git clone https://gitee.com/mirrors/grpc-framework grpc
這樣下載速度提升了很多。
二、git submodule update
這個命令實際就是在下載.gitmodules
文件裏定義的第三方依賴項到third_party目錄,這個依賴項有不少,你們能夠打開.gitmodules
文件查看下詳情。依賴的倉庫都在github上,下載沒幾個小時是下載不下來的,就等着慢慢下載吧。
回頭想一想,咱們花費了不少時間,結果只是爲了獲得grpc的proto編譯插件。
福利:Mac下已編譯完成的二進制包:https://files.cnblogs.com/files/52fhy/bins.tar.gz 。下載以上文件解壓,將
bins/opt/
裏的全部文件複製到/usr/local/bin/
。
若是僅使用golang、java,請忽略本節。
PHP暫時不支持做爲grpc的服務端。做爲客戶端是能夠的,須要機器安裝:
其中protoc
和protobuf c擴展
已經在 Protobuf 小試牛刀 介紹過了,這裏再也不贅述。上一小節裏若是安裝成功,那麼grpc_php_plugin
也是有了的。下面介紹如何安裝PHP版的gRPC庫。
安裝grpc c擴展:
要求:GCC編譯器須要4.8及以上版本。可使用pecl安裝:
pecl install grpc
也能夠指定版本:
pecl install grpc-1.12.0
或者下載源碼(http://pecl.php.net/package/grpc)安裝:
wget http://pecl.php.net/get/grpc-1.21.3.tgz tar zxvf grpc-1.21.3.tgz && cd grpc-1.21.3 phpize ./configure make make install
grpc/grpc
代碼庫裏也有PHP擴展的C源碼,在grpc/src/php/ext/grpc
目錄,進去也能夠直接編譯。
編譯完成後在php.ini裏添加,使用php --ri grpc
能夠查看信息。
安裝完C擴展後,還須要使用composer安裝grpc的庫:
composer require grpc/grpc
一共定義了三個文件:
└── proto ├── GreeterService.proto ├── Response.proto └── User.proto
其中 User
做爲 Model定義,Response
用於 RPC統一返回定義,GreeterService
則是服務接口定義。
限於篇幅,proto文件詳見 https://github.com/52fhy/grpc-sample 倉庫的proto
目錄。
GreeterService.proto
文件內容以下:
syntax = "proto3"; package Sample.Model; //namesapce import "User.proto"; import "Response.proto"; service Greeter { // Sends a greeting rpc SayHello (User) returns (Response) {} }
這裏面定義了一個service
,至關於定義了一個服務接口,咱們把方法名、參數定義好了,後面須要去實現它。因爲gRPC不支持PHP做爲服務端,這裏咱們使用Golang做爲服務端。
首先須要使用proto工具編譯出golang的代碼:
mkdir -p Pb_Go #編譯 cd proto protoc --go_out=plugins=grpc:../Pb_Go/ *.proto cd -
若是提示
protoc-gen-go
找不到,請根據文章介紹(http://www.javashuo.com/article/p-bntooahh-d.html。
執行成功,會在 Pb_Go
目錄裏生成Go代碼:
Pb_Go ├── GreeterService.pb.go ├── Response.pb.go └── User.pb.go
若是須要生成PHP客戶端的代碼,則須要使用grpc php的命令行工具grpc_php_plugin
,前面小結若是執行成功,這個工具已經有了。而後:
out=output/php mkdir -p $out #編譯 cd proto protoc --php_out=../$out --grpc_out=../$out --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin *.proto cd - # 修改命名空間 cd $out mv GPBMetadata Sample/Model/ find . -name '*.php' ! -name example.php -exec sed -i "" -e 's#GPBMetadata#Sample\\Model\\GPBMetadata#g' -e 's#\\Sample\\Model\\GPBMetadata\\Google#\\GPBMetadata\\Google#g' {} \;
上面是在Mac下操做的,命令和Linux有些不一樣。CentOS下gRPC編譯工具未編譯。
最終生成的文件:
├── output │ └── php │ └── Sample │ └── Model │ ├── GPBMetadata │ │ ├── GreeterService.php │ │ ├── Response.php │ │ └── User.php │ ├── GreeterClient.php │ ├── Response.php │ ├── User.php │ └── UserList.php
注意:編譯那裏若是咱們不加--grpc_out=../$out --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin
,生成的PHP類是沒有GreeterClient
的。這個文件是gRPC編譯工具自動生成的,用於鏈接gRPC服務端。
咱們用Golang寫服務端。上面雖然生成了Golang的部分代碼,但真正的服務尚未寫呢。
首先咱們新建個main.go,代碼很少,我直接貼出來:
package main import ( "fmt" "log" "net" "time" pb "grpc-sample/Pb_Go" "golang.org/x/net/context" "google.golang.org/grpc" ) const ( addr = ":50051" ) // server is used to implement helloworld.GreeterServer. type server struct{} // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, u *pb.User) (*pb.Response, error) { return &pb.Response{ErrCode: 0, ErrMsg: "success", Data: map[string]string{"name": "Hello " + u.Name}}, nil } func main() { lis, err := net.Listen("tcp", addr) if err != nil { log.Fatalf("failed to listen: %v", err) } fmt.Printf("%s server start at %s\n", time.Now(), addr) s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{}) s.Serve(lis) }
而後就能夠編譯了。
有個大坑:go build main.go
的時候會先下載go.mod
裏定義的依賴(依賴比較多,詳情查看:https://github.com/52fhy/grpc-sample/blob/master/go.mod),其中下面這條很是慢,倉庫太大了,雖然重定向到github:
replace google.golang.org/api => github.com/googleapis/google-api-go-client v0.6.1-0.20190616000641-99157d28da34
爲了快速下載,我在碼雲上作了鏡像,地址:gitee.com/52fhy/google-api-go-client 。改了以後下載快多了。
編譯成功後,生成了二進制文件main
。咱們能夠直接運行:
$ ./main 2019-06-30 17:16:07.752508 +0800 CST m=+0.028838467 server start at :50051
爲了測試咱們寫的服務是否正常,能夠寫測試用例:
test_client.go
package main import ( "context" "google.golang.org/grpc" pb "grpc-sample/Pb_Go" "testing" ) func TestExec(t *testing.T) { conn, err := grpc.Dial(":50051", grpc.WithInsecure()) if err != nil { t.Errorf("dial error: %v\n", err) } defer conn.Close() // 實例化客戶端 client := pb.NewGreeterClient(conn) // 調用服務 user := pb.User{} user.Id = 1 user.Name = "test" result, err := client.SayHello(context.Background(), &user) if err != nil { t.Errorf("grpc error: %v\n", err) } t.Logf("Recevied: %v\n", result) }
運行:
$ go test -v client_test.go === RUN TestExec --- PASS: TestExec (0.01s) client_test.go:29: Recevied: errMsg:"success" data:<key:"name" value:"Hello test" > PASS ok command-line-arguments 0.021s
運行有點慢,感受依賴的庫多了。
使用gRPC PHP客戶端,確保你已經安裝了:
示例:
client_test.php
<?php use Grpc\ChannelCredentials; use Sample\Model\User; use Sample\Model\UserList; use Sample\Model\GreeterClient; ini_set("display_errors", true); error_reporting(E_ALL); require_once "autoload.php"; $user = new User(); $user->setId(1)->setName("test"); $client = new GreeterClient("192.168.99.1:50051", [ 'credentials' => ChannelCredentials::createInsecure(), //不加密 // 'timeout' => 3000000, ]); //分別是響應、狀態對象 list($reply, $status) = $client->SayHello($user)->wait(); if (!$reply) { echo json_encode($status); return; } //序列化爲string echo $reply->serializeToJsonString(true) . PHP_EOL; echo $reply->getErrCode() . PHP_EOL; //errCode echo $reply->getErrMsg() . PHP_EOL; //errMsg //data foreach ($reply->getData() as $key => $value) { echo $key . "-" . $value . PHP_EOL; }
運行後輸出:
$ php tests/client_test.php {"errMsg":"success","data":{"name":"Hello test"}} 0 success name-Hello test
一、CentOS6使用 go mod獲取第三方依賴包unknown revision xxx錯誤
解決:其實go mod調用鏈中會用到一些git指令,當git版本比較舊時,調用失敗產生錯誤,並給出歧義的提示信息。方法就是升級git版本,CentOS6自帶的git是1.7版本。升級完畢後,再嘗試go mod。
快速升級方法:
centos6:
# 安裝yum源 wget http://opensource.wandisco.com/centos/6/git/x86_64/wandisco-git-release-6-1.noarch.rpm && rpm -ivh wandisco-git-release-6-1.noarch.rpm ## 安裝git 2.x yum install git -y ## 驗證 git --version git version 2.14.1
二、PHP報錯:Fatal error: Class 'Google\Protobuf\Internal\Message' not found
解決:請安裝PHP的protobuf c擴展。
三、PHP報錯:Fatal error: Class '\Grpc\BaseStub' not found
解決:使用composer require grpc/grpc
安裝grpc。另外對應的grpc C擴展也要安裝。
四、下載 github release包很慢怎麼辦?
解決:下載Mac版 Free Download Manager
下載工具能夠解決Github 下載緩慢或失敗問題。速度嗖嗖的。
一、爲CentOS 六、7升級gcc至4.八、4.九、5.二、6.三、7.3等高版本
http://www.vpser.net/manage/centos-6-upgrade-gcc.html
二、centos 6.x/7.x使用yum升級git版本 - 夜空
https://blog.slogra.com/post-721.html
三、Protobuf 小試牛刀 - 飛鴻影
http://www.javashuo.com/article/p-bntooahh-d.html