教育行業(yè)A股IPO第一股(股票代碼 003032)

全國咨詢/投訴熱線:400-618-4000

Go語言構(gòu)建微服務一站式解決方案

更新時間:2018年06月07日14時27分 來源:傳智播客 瀏覽次數(shù):

1528343999478_1.png

開發(fā)單體式應用

假設你正準備開發(fā)一款與Uber和Hailo競爭的出租車調(diào)度軟件,經(jīng)過初步會議和需求分析,你可能使用傳統(tǒng)的程序框架來生成你的項目,最終的程序架構(gòu)如下圖所示:

1528350583640_2.png

盡管也是模塊化邏輯,但是最終它還是會打包并部署為單體式應用。具體的格式依賴于應用語言和框架。最終程序發(fā)布的時候也會被打包成單一的程序發(fā)布出來。

單體式應用的不足

不幸的是,這種簡單方法卻有很大的局限性。一個簡單的應用會隨著時間推移逐漸變大。在每次的sprint中,開發(fā)團隊都會面對新“故事”,然后開發(fā)許多新代碼。幾年后,這個小而簡單的應用會變成了一個巨大的怪物。這兒有一個例子,我最近和一個開發(fā)者討論,他正在寫一個工具,用來分析他們一個擁有數(shù)百萬行代碼的應用中JAR文件之間的依賴關系。我很確信這個代碼正是很多開發(fā)者經(jīng)過多年努力開發(fā)出來的一個怪物。

一旦你的應用變成一個又大又復雜的怪物,那開發(fā)團隊肯定很痛苦。敏捷開發(fā)和部署舉步維艱,其中最主要問題就是這個應用太復雜,以至于任何單個開發(fā)者都不可能搞懂它。因此,修正bug和正確的添加新功能變的非常困難,并且很耗時。另外,團隊士氣也會走下坡路。如果代碼難于理解,就不可能被正確的修改。最終會走向巨大的、不可理解的泥潭。

另外,復雜而巨大的單體式應用也不利于持續(xù)性開發(fā)。今天,SaaS應用常態(tài)就是每天會改變很多次,而這對于單體式應用模式非常困難。另外,這種變化帶來的影響并沒有很好的被理解,所以不得不做很多手工測試。那么接下來,持續(xù)部署也會很艱難。

單體式應用另外一個問題是可靠性。因為所有模塊都運行在一個進程中,任何一個模塊中的一個bug,比如內(nèi)存泄露,將會有可能弄垮整個進程。除此之外,因為所有應用實例都是唯一的,這個bug將會影響到整個應用的可靠性。

最后,單體式應用使得采用新架構(gòu)和語言非常困難。比如,設想你有兩百萬行采用XYZ框架寫的代碼。如果想改成ABC框架,無論是時間還是成本都是非常昂貴的,即使ABC框架更好。因此,這是一個無法逾越的鴻溝。你不得不在最初選擇面前低頭。

那么如何應對呢?

微處理架構(gòu)——處理復雜事物

許多公司,比如Amazon、eBay和NetFlix,通過采用微處理結(jié)構(gòu)模式解決了上述問題。其思路不是開發(fā)一個巨大的單體式的應用,而是將應用分解為小的、互相連接的微服務。

一個微服務一般完成某個特定的功能,比如下單管理、客戶管理等等。每一個微服務都是微型六角形應用,都有自己的業(yè)務邏輯和適配器。一些微服務還會發(fā)布API給其它微服務和應用客戶端使用。其它微服務完成一個Web UI,運行時,每一個實例可能是一個云VM或者是Docker容器。

比如,一個前面描述系統(tǒng)可能的分解如下:


1528350625344_3.png

每一個應用功能區(qū)都使用微服務完成,另外,Web應用會被拆分成一系列簡單的Web應用(比如一個對乘客,一個對出租車駕駛員)。這樣的拆分對于不同用戶、設備和特殊應用場景部署都更容易。

每一個后臺服務開放一個REST API,許多服務本身也采用了其它服務提供的API。比如,駕駛員管理使用了告知駕駛員一個潛在需求的通知服務。UI服務激活其它服務來更新Web頁面。所有服務都是采用異步的,基于消息的通訊。

微服務架構(gòu)的好處

微服務架構(gòu)模式有很多好處。首先,通過分解巨大單體式應用為多個服務方法解決了復雜性問題。在功能不變的情況下,應用被分解為多個可管理的分支或服務。每個服務都有一個用RPC-或者消息驅(qū)動API定義清楚的邊界。微服務架構(gòu)模式給采用單體式編碼方式很難實現(xiàn)的功能提供了模塊化的解決方案,由此,單個服務很容易開發(fā)、理解和維護。

第二,這種架構(gòu)使得每個服務都可以有專門開發(fā)團隊來開發(fā)。開發(fā)者可以自由選擇開發(fā)技術,提供API服務。當然,許多公司試圖避免混亂,只提供某些技術選擇。然后,這種自由意味著開發(fā)者不需要被迫使用某項目開始時采用的過時技術,他們可以選擇現(xiàn)在的技術。甚至于,因為服務都是相對簡單,即使用現(xiàn)在技術重寫以前代碼也不是很困難的事情。

第三,微服務架構(gòu)模式是每個微服務獨立的部署。開發(fā)者不再需要協(xié)調(diào)其它服務部署對本服務的影響。這種改變可以加快部署速度。UI團隊可以采用AB測試,快速的部署變化。微服務架構(gòu)模式使得持續(xù)化部署成為可能。

最后,微服務架構(gòu)模式使得每個服務獨立擴展。你可以根據(jù)每個服務的規(guī)模來部署滿足需求的規(guī)模。甚至于,你可以使用更適合于服務資源需求的硬件。

微服務架構(gòu)的特性

1. 單一職責

微服務架構(gòu)中的每個服務,都是具有業(yè)務邏輯的,符合高內(nèi)聚、低耦合原則以及單一職責原則的單元,不同的服務通過“管道”的方式靈活組合,從而構(gòu)建出龐大的系統(tǒng)。

2. 輕量級通信

服務之間通過輕量級的通信機制實現(xiàn)互通互聯(lián),而所謂的輕量級,通常指語言無關、平臺無關的交互方式。


1528350653657_4.png

對于輕量級通信的格式而言,我們熟悉的 XML 和 JSON,它們是語言無關、平臺無關的;對于通信的協(xié)議而言,通?;?HTTP,能讓服務間的通信變得標準化、無狀態(tài)化。目前大家熟悉的 REST(Representational State Transfer)是實現(xiàn)服務間互相協(xié)作的輕量級通信機制之一。使用輕量級通信機制,可以讓團隊選擇更適合的語言、工具或者平臺來開發(fā)服務本身。

3. 獨立性

每個服務在應用交付過程中,獨立地開發(fā)、測試和部署。

在單塊架構(gòu)中所有功能都在同一個代碼庫,功能的開發(fā)不具有獨立性;當不同小組完成多個功能后,需要經(jīng)過集成和回歸測試,測試過程也不具有獨立性;當測試完成后,應用被構(gòu)建成一個包,如果某個功能存在 bug,將導致整個部署失敗或者回滾。

1528350688080_5.png

在微服務架構(gòu)中,每個服務都是獨立的業(yè)務單元,與其他服務高度解耦,只需要改變當前服務本身,就可以完成獨立的開發(fā)、測試和部署。


1528350713034_6.png

4. 進程隔離

在微服務架構(gòu)中,每個服務都是獨立的業(yè)務單元,與其他服務高度解耦,只需要改變當前服務本身,就可以完成獨立的開發(fā)、測試和部署。有時候我們會將重復的代碼抽取出來封裝成組件,在單塊架構(gòu)中,組件通常的形態(tài)叫做共享庫(如 jar 包或者 DLL),但是當程序運行時,所有組件最終也會被加載到同一進程中運行。


1528350731300_7.png

在微服務架構(gòu)中,應用程序由多個服務組成,每個服務都是高度自治的獨立業(yè)務實體,可以運行在獨立的進程中,不同的服務能非常容易地部署到不同的主機上。


1528350752831_8.png

既然要介紹微服務,就不得不介紹一下與微服務相關的技術。那么,接下來,我們一一做一下詳細講解。

protoBuf(Google旗下平臺語言無關序列化數(shù)據(jù)協(xié)議)

1528350795113_9.png

protobuf是google旗下的一款平臺無關,語言無關,可擴展的序列化結(jié)構(gòu)數(shù)據(jù)格式。所以很適合用做數(shù)據(jù)存儲和作為不同應用,不同語言之間相互通信的數(shù)據(jù)交換格式,只要實現(xiàn)相同的協(xié)議格式即同一 proto文件被編譯成不同的語言版本,加入到各自的工程中去。這樣不同語言就可以解析其他語言通過 protobuf序列化的數(shù)據(jù)。目前官網(wǎng)提供了 C++,Python,JAVA,GO等語言的支持。

protobuf語法定義

要想使用 protobuf必須得先定義 proto文件。所以得先熟悉 protobuf的消息定義的相關語法。下面就來介紹。

首先我們先定義一個 proto文件,結(jié)構(gòu)如下:

message Article {

required int32 article_id=1;

optional string article_excerpt=2;

repeated string article_picture=3;

}

上面我們主要定義了一個消息,這個消息包括文章 ID,文章摘要,文章圖片。下面給出消息定義的相關說明 :

n message是消息定義的關鍵字。

a) required表示是一個必須字段,必須相對于發(fā)送方,在發(fā)送消息之前必須設置該字段的值,對于接收方,必須能夠識別該字段的意思。發(fā)送之前沒有設置required字段或者無法識別required字段都會引發(fā)編解碼異常,導致消息被丟棄。

b) Optional:表示是一個可選字段,可選對于發(fā)送方,在發(fā)送消息時,可以有選擇性的設置或者不設置該字段的值。對于接收方,如果能夠識別可選字段就進行相應的處理,如果無法識別,則忽略該字段,消息中的其它字段正常處理。---因為optional字段的特性,很多接口在升級版本中都把后來添加的字段都統(tǒng)一的設置為optional字段,這樣老的版本無需升級程序也可以正常的與新的軟件進行通信,只不過新的字段無法識別而已,因為并不是每個節(jié)點都需要新的功能,因此可以做到按需升級和平滑過渡。

c) Repeated:表示該字段可以包含0~N個元素。其特性和optional一樣,但是每一次可以包含多個值。可以看作是在傳遞一個數(shù)組的值

d) int32和string是字段的類型。后面是我們定義的字段名。最后的 1,2,3則是代表每個字段的一個唯一的編號標簽,在同一個消息里不可以重復。這些編號標簽用與在消息二進制格式中標識你的字段,并且消息一旦定義就不能更改。需要說明的是標簽在 1到15范圍的采用一個字節(jié)進行編碼。所以通常將標簽 1到15用于頻繁發(fā)生的消息字段。編號標簽大小的范圍是1到229 – 1。此外不能使用protobuf系統(tǒng)預留的編號標簽(19000 -19999)

當然 protobuf支持更多的類型,比如 bool,double,float,枚舉,也可以是其他定義過的消息類型譬如前面的消息 Article。支持的基本類型如下:


1528350869880_10.png

一般在我們的項目中肯定會有很多消息類型。我們總不能都定義在一個文件中。當一個 proto文件需要另一個 proto文件的時候,我們可以通過 import導入,就像下面這樣:

import "article.proto";

message Book {

//定義消息體

}

protoBuf使用

protobuf的使用方法是將數(shù)據(jù)結(jié)構(gòu)寫入到 .proto文件中,使用 protoc編譯器編譯(間接使用了插件)得到一個新的 go包,里面包含 go中可以使用的數(shù)據(jù)結(jié)構(gòu)和一些輔助方法。

Golang & protoBuf

1. $GOPATH/src/創(chuàng)建 myproto文件夾

2. myproto文件夾中創(chuàng)建 test.proto文件 (protobuf協(xié)議文件 )

syntax = “proto2”;

package myproto;

enum FOO {X = 17;};

message Test {

required string label = 1;

optional int32 type = 2 [default=77];

repeated int64 reps = 3;

optional group OptionalGroup = 4 {

required string RequiredFiled = 5;

}

}

3. 編譯 :執(zhí)行

protoc --go_out=. *.proto

生成 test.pb.go文件

4. 使用 protobuf做數(shù)據(jù)格式轉(zhuǎn)換

package main

import (

"fmt"

"github.com/golang/protobuf/proto"

"myproto"

)

func main() {

test := &myproto.Test{

Label: proto.String("hello"),

Type: proto.Int32(17),

Reps: []int64{1, 2, 3},

Optionalgroup: &myproto.Test_OptionalGroup{

RequiredFiled: proto.String("good bye"),

},

}

//將Struct test 轉(zhuǎn)換成 protobuf

data, err := proto.Marshal(test)

if err != nil {

fmt.Println("marshaling error: ", err)

}

//得到一個新的Test結(jié)構(gòu)體 newTest

newTest := &myproto.Test{}

//將 data 轉(zhuǎn)換成 Test結(jié)構(gòu)體

err = proto.Unmarshal(data, newTest)

if err != nil {

fmt.Println("unmarshaling error: ", err)

}

//將newTest的字符串序列化打出

fmt.Println(newTest.String())

//得到type字段

if test.GetType() != newTest.GetType() {

fmt.Println("type is not equal")

}

//...

}

gRPC(Google定義的PRC協(xié)議標準)


1528350892459_11.png

gRPC是什么?

在 gRPC里客戶端應用可以像調(diào)用本地對象一樣直接調(diào)用另一臺不同的機器上服務端應用的方法,使得您能夠更容易地創(chuàng)建分布式應用和服務。與許多 RPC系統(tǒng)類似, gRPC也是基于以下理念:定義一個服務,指定其能夠被遠程調(diào)用的方法(包含參數(shù)和返回類型)。在服務端實現(xiàn)這個接口,并運行一個 gRPC服務器來處理客戶端調(diào)用。在客戶端擁有一個存根能夠像服務端一樣的方法。 gRPC客戶端和服務端可以在多種環(huán)境中運行和交互 -從 google內(nèi)部的服務器到你自己的筆記本,并且可以用任何 gRPC支持的語言 來編寫。所以,你可以很容易地用 Java創(chuàng)建一個 gRPC服務端,用 Go、 Python、Ruby來創(chuàng)建客戶端。此外, Google最新 API將有 gRPC版本的接口,使你很容易地將 Google的功能集成到你的應用里。


1528350912991_12.png

使用 protocol buffers

gRPC默認使用protoBuf,這是 Google開源的一套成熟的結(jié)構(gòu)數(shù)據(jù)序列化機制(當然也可以使用其他數(shù)據(jù)格式如 JSON)。正如你將在下方例子里所看到的,你用 proto files創(chuàng)建 gRPC服務,用 protoBuf消息類型來定義方法參數(shù)和返回類型。你可以在 Protocol Buffers文檔找到更多關于 protoBuf的資料。

雖然你可以使用 proto2 (當前默認的 protocol buffers版本 ),我們通常建議你在 gRPC里使用 proto3,因為這樣你可以使用 gRPC支持全部范圍的的語言,并且能避免 proto2客戶端與 proto3服務端交互時出現(xiàn)的兼容性問題,反之亦然。

你好 gRPC

現(xiàn)在你已經(jīng)對 gRPC有所了解,了解其工作機制最簡單的方法是看一個簡單的例子。 Hello World將帶領你創(chuàng)建一個簡單的客戶端 —— 服務端應用,向你展示:

n 通過一個protoBuf模式,定義一個簡單的帶有 Hello World方法的 RPC服務。

n 用你最喜歡的語言 (如果可用的話 )來創(chuàng)建一個實現(xiàn)了這個接口的服務端。

n 用你最喜歡的 (或者其他你愿意的 )語言來訪問你的服務端。

go語言實現(xiàn) gRPC遠程調(diào)用

創(chuàng)建一個 protobuf package,如: my_rpc_proto; 在$GOPATH/src/下創(chuàng)建 go_lession/gRPC_test/my_rpc_proto/文件夾里面創(chuàng)建 protobuf協(xié)議文件 helloServer.proto

syntax = "proto3";

package my_rpc_proto;

// The HelloServer service definition.

service HelloServer {

// 第一個遠程調(diào)用接口

rpc SayHello (HelloRequest) returns (HelloReply) {}

// 第二個遠程調(diào)用接口

rpc GetHelloMsg (HelloRequest) returns (HelloMessage) {}

}

// The request message containing the user's name.

message HelloRequest {

string name = 1;

}

// The response message containing the greetings

message HelloReply {

string message = 1;

}

message HelloMessage {

string msg = 1;

}

在當前文件下,編譯 helloServer.proto文件

protoc –go_out=plugins=grpc:./ *.proto

得到 helloServer.pb.go文件

1. gRPC-Server編寫

package main

import (

"fmt"

"net"

pb "go_lession/gRPC_test/my_rpc_proto"

"golang.org/x/net/context"

"google.golang.org/grpc"

)

const (

port = ":18881"

)

type server struct{}

//實現(xiàn)RPC SayHello 接口

func (this *server) SayHello(ctx context.Context, in *pb.HelloRe

quest) (*pb.HelloReply, error) {

return &pb.HelloReply{Message: "hello" + in.Name}, nil

}

//實現(xiàn)RPC GetHelloMsg 接口

func (this *server) GetHelloMsg(ctx context.Context, in *pb.Hell

oRequest) (*pb.HelloMessage, error) {

return &pb.HelloMessage{Msg: "this is from server HAHA!"}, nil

}

func main() {

listen, err := net.Listen("tcp", port)

if err != nil {

fmt.Println("failed to listen : ", err)

return

}

//得到一個gRPC 服務句柄

srv := grpc.NewServer()

//將 server 結(jié)構(gòu)體注冊到 gRPC 服務

pb.RegisterHelloServerServer(srv, &server{})

//啟動監(jiān)聽gRPC服務

if err := srv.Serve(listen); err != nil {

fmt.Println("failed to serve, ", err)

return

}

}

2. gRPC-Client編寫

package main

import (

"fmt"

pb "go_lession/gRPC_test/my_rpc_proto"

"golang.org/x/net/context"

"google.golang.org/grpc"

)

const (

address = "localhost:18881"

clientName = "GreenHat"

)

func main() {

//了客戶端連接服務器

conn, err := grpc.Dial(address, grpc.WithInsecure())

if err != nil {

fmt.Println("did not connetc : ", err)

return

}

defer conn.Close()

//獲取一個 gRPC 句柄

c := pb.NewHelloServerClient(conn)

//遠程調(diào)用 SayHello接口

r1, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: clientName})

if err != nil {

fmt.Println("cloud not get Hello server ..", err)

return

}

fmt.Println("HelloServer resp: ", r1.Message)

//遠程調(diào)用 GetHelloMsg接口

r2, err := c.GetHelloMsg(context.Background(), &pb.HelloRequest{Name: clientName})

if err != nil {

fmt.Println("cloud not get hello msg ..", err)

return

}

fmt.Println("HelloServer resp: ", r2.Msg)

}

運行 server,在運行 client

得到以下輸出結(jié)果:

HelloServer resp: helloGreenHat

HelloServer resp: this is from server HAHA!

Consul(基于Go的服務發(fā)現(xiàn)工具)


1528350939444_13.png

Consul簡介

Consul是什么

Consul是HashiCorp公司推出的開源工具,用于實現(xiàn)分布式系統(tǒng)的服務發(fā)現(xiàn)與配置。 Consul是分布式的、高可用的、可橫向擴展的。它具備以下特性 :

l service discovery:consul通過DNS或者HTTP接口使服務注冊和服務發(fā)現(xiàn)變的很容易,一些外部服務,例如saas提供的也可以一樣注冊。

l health checking:健康檢測使consul可以快速的告警在集群中的操作。和服務發(fā)現(xiàn)的集成,可以防止服務轉(zhuǎn)發(fā)到故障的服務上面。

l key/value storage:一個用來存儲動態(tài)配置的系統(tǒng)。提供簡單的HTTP接口,可以在任何地方操作。

l multi-datacenter:無需復雜的配置,即可支持任意數(shù)量的區(qū)域。

什么是服務發(fā)現(xiàn)

微服務的框架體系中,服務發(fā)現(xiàn)是不能不提的一個模塊。我相信了解或者熟悉微服務的童鞋應該都知道它的重要性。這里我只是簡單的提一下,畢竟這不是我們的重點。我們看下面的一幅圖片:


1528350974460_14.png

圖中,客戶端的一個接口,需要調(diào)用服務A-N??蛻舳吮仨氁浪蟹盏木W(wǎng)絡位置的,以往的做法是配置是配置文件中,或者有些配置在數(shù)據(jù)庫中。這里就帶出幾個問題:

· 需要配置N個服務的網(wǎng)絡位置,加大配置的復雜性

· 服務的網(wǎng)絡位置變化,都需要改變每個調(diào)用者的配置

· 集群的情況下,難以做負載(反向代理的方式除外)


1528351015383_15.png

與之前一張不同的是,加了個服務發(fā)現(xiàn)模塊。圖比較簡單,這邊文字描述下。服務A-N把當前自己的網(wǎng)絡位置注冊到服務發(fā)現(xiàn)模塊(這里注冊的意思就是告訴),服務發(fā)現(xiàn)就以K-V的方式記錄下,K一般是服務名,V就是IP:PORT。服務發(fā)現(xiàn)模塊定時的輪詢查看這些服務能不能訪問的了(這就是健康檢查)??蛻舳嗽谡{(diào)用服務A-N的時候,就跑去服務發(fā)現(xiàn)模塊問下它們的網(wǎng)絡位置,然后再調(diào)用它們的服務。這樣的方式是不是就可以解決上面的問題了呢?客戶端完全不需要記錄這些服務網(wǎng)絡位置,客戶端和服務端完全解耦!


1528351034055_16.png

下面的例子有可能更有助于我們理解服務發(fā)現(xiàn)的形式:

例如郵遞員去某公司一棟大樓投遞快件,向門衛(wèi)詢問員工甲在哪一個房間,門衛(wèi)拿起桌上的通訊錄查詢,告知郵遞員員工甲在具體什么位置。假如公司來了一個員工乙,他想讓郵遞員送過來,就要先讓門衛(wèi)知道自己在哪一個房間,需要去門衛(wèi)那邊登記,員工乙登記后,當郵遞員向門衛(wèi)詢問時,門衛(wèi)就可以告訴郵遞員員工乙的具體位置。門衛(wèi)知道員工乙的具體位置的過程就是服務發(fā)現(xiàn),員工乙的位置信息可以被看作服務信息,門衛(wèi)的通訊錄就是上文中提到的數(shù)據(jù)交換格式,此例中員工乙就是上文的已方,門衛(wèi)就是服務發(fā)現(xiàn)的提供者。

以調(diào)試模式啟動consul:

$ conusl agent –dev –bind=0.0.0.0

go_micro(基于Go的微服務框架)


1528351053368_17.png

依賴

我們需要一個發(fā)現(xiàn)服務器,這里 micro默認使用的 Consul,我們這里用之前安裝部署好的 consul,用來做 go的micro服務發(fā)現(xiàn)

protoBuf作為Server端和Client端的數(shù)據(jù)交換格式。

下載 micro

go get github.com/micro/micro

hello micro

趕緊完成一個go_micro的微服務吧 ~

micro為我們提供的微服務框架如下

這里面有很多角色, Micro API, Customer API, Customer Service等等 ...

其中 Micro API是micro給我們提供的一個工具,是通過 RPC調(diào)用我們模塊的 API和做一些負載均衡的作用,實際上 Customer API, Customer Service是一組微服務, Customer API收到 Micro API轉(zhuǎn)發(fā)的請求后,將 RESTful轉(zhuǎn)換成 protobuf通過 gRPC調(diào)用發(fā)送給 Customer Service做服務處理,然后又將返回 protobuf數(shù)據(jù)轉(zhuǎn)換成 RESTful返回給用戶。

在微服務架構(gòu)中一般稱 API為RPC GateWay

GRPC Gateway

此指南幫助我們使用 go-micro微服務中的 grpc gateway。

grpc-gateway是一個 protoc的一個插件。它基于 gRPC服務定義,并且提供一

個將 RESTful JSON API轉(zhuǎn)換成 gRPC協(xié)議的反響代理服務。

我們使用 go-grpc去完成后臺服務, go-grpc是一個為 client/server將go-micro

和gRPC結(jié)合的一個包裹。

代碼案例

examples/grpc.

Create service proto-創(chuàng)建服務端protobuf

這里,我們的proto文件定義如下:

syntax = "proto3";

service Greeter {

rpc Hello(HelloRequest) returns (HelloResponse) {}

}

message HelloRequest {

string name = 1;

}

message HelloResponse {

string greeting = 2;

}

Write the service

1、 實現(xiàn)自定義接口

2、 初始化一個微服務

3、 注冊Greeter 句柄

4、 啟動服務

package main

import (

"context"

"fmt"

micro "github.com/micro/go-micro"

proto "github.com/micro/examples/service/proto"

)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {

rsp.Greeting = "Hello " + req.Name

return nil

}

func main() {

// Create a new service. Optionally include some options here.

service := micro.NewService(

micro.Name("greeter"),

)

// Init will parse the command line flags.

service.Init()

// Register handler

proto.RegisterGreeterHandler(service.Server(), new(Greeter))

// Run the server

if err := service.Run(); err != nil {

fmt.Println(err)

}

}

Run service

go run examples/service/main.go

Output

2016/03/14 10:59:14 Listening on [::]:50137

2016/03/14 10:59:14 Broker Listening on [::]:50138

2016/03/14 10:59:14 Registering node: greeter-ca62b017-e9d3-11e5-9bbb-68a86d0d36b6

Define a client-編寫客戶端

下面是客戶端訪問微服務的代碼:

package main

import (

"context"

"fmt"

micro "github.com/micro/go-micro"

proto "github.com/micro/examples/service/proto"

)

func main() {

// Create a new service. Optionally include some options here.

service := micro.NewService(micro.Name("greeter.client"))

service.Init()

// Create new greeter client

greeter := proto.NewGreeterClient("greeter", service.Client())

// Call the greeter

rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "John"})

if err != nil {

fmt.Println(err)

}

// Print response

fmt.Println(rsp.Greeting)

}

Run the client

go run client.go

Output

Hello John

QA

1 Go語言除了能開發(fā)區(qū)塊鏈還能開發(fā)哪些領域?

Go語言作為一個開發(fā)效率高,天生支持高并發(fā),同時又具備媲美C語言性能的語言,在未來一定是后端開發(fā)語言的最具有潛力的編程語言。目前很多企業(yè)的服務器架構(gòu)也逐步在用Go語言重構(gòu)。

Go語言目前主要涉及的領域有:高并發(fā)服務器開發(fā)、分布式開發(fā)、微服務開發(fā)、Web框架及應用開發(fā)、和區(qū)塊鏈開發(fā)。

高并發(fā)服務器開發(fā):

不用解釋了,Go天生語法的并發(fā)支持和Goroutine協(xié)程的輕量級與調(diào)度器的優(yōu)化,目前很多游戲公司主要服務開發(fā)語言最優(yōu)選擇一定是Golang.

分布式開發(fā):

我們知道的兩個分布式虛擬化明星:Docker、Kubernetes他們的開發(fā)實現(xiàn)語言都是Go語言。有人說是Docker捧紅了分布式,實際上很多人并不知道,是Go捧紅了Docker生態(tài)。

微服務開發(fā):

Go的微服務框架居多,加上Docker對go的支持最好,所以go也是微服務開發(fā)的首選語言。

go的微服務框架有go-micro,go-kit。服務發(fā)現(xiàn)有go實現(xiàn)的Consul。微服務通信的RPC機制有google實現(xiàn)的gRPC,其中通信協(xié)議protobuf也是對go無縫銜接的。

Web框架及應用開發(fā):

對于web,大家可能會想到java的Spring、python的Django。但是可能并不知道Go的Beego和Gin、Echo等web框架正在逐步侵蝕大型互聯(lián)網(wǎng)公司。很多公司已經(jīng)通過Beego來搭建web后臺服務,因為Go的天生網(wǎng)絡處理的流暢,讓開發(fā)者在構(gòu)建大型web的時候,更加喜歡了Go語言。

區(qū)塊鏈開發(fā):

我們所遇見的區(qū)塊鏈應用項目或者相關框架幾乎都是Go語言實現(xiàn),或者對Go的支持最好。主流的Hyperledger Fabric 和以太坊也是目前企業(yè)正在大規(guī)模使用的開發(fā)框架。go的這種開發(fā)效率高和高性能,對于區(qū)塊鏈這種注重網(wǎng)絡通信和信息安全的技術,更是不可或缺的。

2 Go語言難易程度如何?

Go語言學習起來完全可以零基礎入門。Google在創(chuàng)建Go語言的最初定義為:簡單快樂的開發(fā)高性能系統(tǒng)語言??梢奼o語言并不是很難。


本文版權歸傳智播客C/C++與網(wǎng)絡攻防學院所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明作者出處。謝謝!

作者:傳智播客C/C++與網(wǎng)絡攻防培訓學院

首發(fā):http://c.itcast.cn/?

0 分享到:
和我們在線交談!