์ตœ๊ทผ์— Hyperledger Fabric ๊ธฐ๋ฐ˜์˜ ๋ธ”๋Ÿญ์ฒด์ธ์„ ๊ณต๋ถ€ํ•˜๋‹ค ๋ณด๋‹ˆ Fabric์ด ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์—์„œ ์ „๋ฐ˜์ ์œผ๋กœ gRPC๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์„œ gRPC์— ๋Œ€ํ•ด์„œ ๊ถ๊ธˆ์ ์ด ์ƒ๊ฒจ์„œ ํฌ์ŠคํŒ…ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

gRPC๋Š” ๊ตฌ๊ธ€์—์„œ ๋ฐœํ‘œํ•˜์˜€๊ณ  HTTP ๊ธฐ๋ฐ˜ ์›๊ฒฉ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ•ด์ฃผ๋Š” ์ฆ‰, RPC(Remote Procedure Call) ํ”„๋ ˆ์ž„์›Œํฌ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
RPC๋Š” ๋„คํŠธ์›Œํฌ ์ƒ ์›๊ฒฉ์— ์žˆ๋Š” ์„œ๋ฒ„์˜ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํ”„๋กœํ† ์ฝœ๋กœ IDL(Interface Definition Language)๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•œ ํ›„ ์ด์— ํ•ด๋‹นํ•˜๋Š” Skeleton ๊ณผ Stub ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ ํ˜ธ์ถœํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด๋ผ๊ณ  ๋ณด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ตœ๊ทผ์—๋Š” HTTP๋ฅผ ํ™œ์šฉํ•œ SOAP, RESTful ๋“ฑ์ด ๋งŽ์ด ํ™œ์šฉ๋˜์–ด์„œ RPC๋Š” ๊ฑฐ์˜ ์‚ฌ์šฉ์ด ๋˜์ง€ ์•Š์œผ๋‚˜ ์š”์ฒญ/์‘๋‹ต์„ ์œ„ํ•œ ๊ทœ์•ฝ์ด ๋ช…์‹œ์ ์ด์ง€ ์•Š๋‹ค๋Š” ๋‹จ์ ์œผ๋กœ ์ธํ•ด ๋‹ค์‹œ RPC์˜ ๋ฐฉ์‹์„ ์ฑ„์šฉํ•œ ํ”„๋ ˜์ž„์›Œํฌ๋“ค์ด ๋‚˜์˜ค๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.
gRPC๋Š” ์ž๋ฐ”,C/C++ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Node.js, Python, Ruby, PHP, Go, Android ๊ธฐ๋ฐ˜, Objective-C ๋“ฑ ๋‹ค์–‘ํ•œ ์–ธ์–ด๋“ค์„ ์ง€์›ํ•จ์œผ๋กœ ์„œ๋ฒ„๊ฐ„ ๋ฟ๋งŒ์ด ์•„๋‹ˆ๋ผ ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ ๋ชจ๋ฐ”์ผ ์•ฑ์—์„œ๋„ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ RPC ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ gRPC ์ƒ˜ํ”Œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ข€ ๋” ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
(์ด ๊ธ€์—์„œ๋Š” golang ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.)

> ์—ฌ๊ธฐ์„œ ์„ค๋ช…ํ•˜๋Š” ๋‚ด์šฉ์€ gRPC ์‚ฌ์ดํŠธ์˜ Golang ๊ธฐ๋ฐ˜ Quick start์˜ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

1. ์‚ฌ์ „ ์ค€๋น„ ์‚ฌํ•ญ

golang ๊ธฐ๋ฐ˜์œผ๋กœ gRPC๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด ๋‹น์—ฐํžˆ golang์ด ์„ค์น˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  gRPC๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ๊ฐ„ ์ง๋ ฌํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š”๋ฐ ๊ตฌ์กฐํ™”๋œ ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ™”ํ•˜๊ธฐ ์œ„ํ•ด์„œ Protocol Buffers ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ํ•จ๊ป˜ ์„ค์น˜ํ•˜์—ฌ ์ค๋‹ˆ๋‹ค.

1.1 Golang ์„ค์น˜

๋‹ค์Œ์˜ ์‚ฌ์ดํŠธ๋ฅผ ์ฐธ์กฐํ•˜์—ฌ golang ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. (์ด ๋ฌธ์„œ์—์„œ๋Š” Linux/MacOS ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.)

๋‹ค์šด๋กœ๋“œ ๋ฐ›์€ ์••์ถ•ํŒŒ์ผ์„ ๋‹ค์Œ์˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

tar -C /usr/local -xzf <๋‹ค์šด๋กœ๋“œ ๋ฐ›์€ ์••์ถ•ํŒŒ์ผ>

์••์ถ•์„ ํ‘ผ ํ›„ ์ ์ ˆํ•œ ์œ„์น˜์— go ์†Œ์Šค๊ฐ€ ์œ„์น˜ํ•  ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ ํ›„ $HOME/.profile์— ๋‹ค์Œ์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

$HOME ์•„๋ž˜์— work๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ

mkdir $HOME/work
export GOROOT=/usr/local/go
export GOPATH=$HOME/work
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

์—ฌ๊ธฐ๊นŒ์ง€ ์„ค์น˜๋ฅผ ์™„๋ฃŒํ•˜์˜€์œผ๋ฉด ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ •์ƒ๋™์ž‘ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ € ๋‹ค์Œ์˜ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

mkdir -p $GOPATH/src/hello

๊ทธ๋ฆฌ๊ณค hello.go ํŒŒ์ผ๋ช…์œผ๋กœ ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}

์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜์˜€์œผ๋ฉด ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.

cd $GOPATH/src/hello
go build

์ปดํŒŒ์ผ์ด ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๋œ ํ›„ ๋‹ค์Œ์˜ ๋ช…๋ น์„ ํ†ตํ•ด์„œ ์‹คํ–‰ํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

./hello
hello, world

1.2 gRPC ์„ค์น˜

๋‹ค์Œ์˜ ๋ช…๋ น์„ ํ†ตํ•ด์„œ gRPC๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

go get google.golang.org/grpc

1.3 Protocol Buffers ์„ค์น˜

๋‹ค์Œ์˜ ๊ฒฝ๋กœ์—์„œ Protocol Buffers ์••์ถ•ํŒŒ์ผ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. https://github.com/google/protobuf/releases – ๋‹ค์šด๋ฐ›์•„์•ผ ํ•  ์••์ถ•ํŒŒ์ผ๋ช…์€ protoc-<๋ฒ„์ „>–<ํ”Œ๋žซํผ>.zip ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.
๋‹ค์šด๋ฐ›์€ ์••์ถ•ํŒŒ์ผ์€ ์ ๋‹นํ•œ ์œ„์น˜์— ํ’€์–ด์„œ ํ•ด๋‹นํ•˜๋Š” ์œ„์น˜๋ฅผ PATH์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ €์˜ ์„ค์ • ์˜ˆ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ Golang ๊ธฐ๋ฐ˜์˜ protoc ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

2. ์ƒ˜ํ”Œ์„ ํ†ตํ•ด ์ดํ•ดํ•˜๊ธฐ

1.2 ํ•ญ๋ชฉ์—์„œ gRPC ๋ฅผ ์„ค์น˜ํ•˜์˜€์œผ๋ฉด ๊ทธ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ์— examples ๋“ค์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์ค‘ helloworld๋ฅผ ํ†ตํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
๊ทธ ์œ„์น˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

cd $GOPATH/src/google.golang.org/grpc/helloworld

์œ„์˜ ๋””๋ ‰ํ† ๋ฆฌ ํ•˜์œ„์—๋Š” greeter_client, greeter_server, helloworld ์˜ ์„ธ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ๋ณด์ž…๋‹ˆ๋‹ค.
๊ทธ ์ค‘ helloworld ํ•˜์œ„์—” .proto ํŒŒ์ผ์ด ์กด์žฌํ•˜๋ฉฐ ์ด ํŒŒ์ผ์ด gRPC ์„œ๋น„์Šค๊ฐ€ ๋ช…์‹œ๋˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์— ์กด์žฌํ•˜๋Š” ํŒŒ์ผ์„ ๊ธฐ์ค€์œผ๋กœ protoc ๋ช…๋ น์„ ํ†ตํ•ด .pb.go ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๋ฉฐ ์ด ํŒŒ์ผ์€ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์ฝ”๋“œ์™€ ํ•จ์ˆ˜ ํ˜ธ์ถœ์‹œ ์ฃผ๊ณ ๋ฐ›์„ ๋ฉ”์„ธ์ง€ ํƒ€์ž…์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ฝ”๋“œ๋ฅผ ๋นŒ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์œ„์น˜๋Š” “$GOPATH/src/google.golang.org/grpc/helloworld” ์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

go run greeter_server/main.go

๊ทธ๋ฆฌ๊ณ  ํ„ฐ๋ฏธ๋„์„ ํ•˜๋‚˜ ๋” ์—ด์–ด์„œ ๋‹ค์Œ์˜ ๋ช…๋ น์œผ๋กœ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

go run greeter_client/main.go

์‹คํ–‰๊ฒฐ๊ณผ “Greeting: Hello world” ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜์˜ค๋ฉด ์ •์ƒ ์‹คํ–‰๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

gRPC ์„œ๋น„์Šค ์—…๋ฐ์ดํŠธ

์•ž์„œ ์‹คํ–‰ํ•œ ๋ช…๋ น์€ SayHello๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ˜ธ์ถœํ•˜๋ฉด ์„œ๋ฒ„์—์„œ ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ›์•„์„œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ถœ๋ ฅํ•˜๋Š” ๋‚ด์šฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์— SayHelloAgain์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด .proto ํŒŒ์ผ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

helloworld.proto ํŒŒ์ผ์˜ ์œ„์น˜

$GOPATH/src/google.golang.org/grpc/examples/helloworld/helloworld/helloworld.proto
// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  // Sends another greeting
  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

๋‹ค์Œ์œผ๋กœ gRPC ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld

์„œ๋ฒ„ ๋ฐ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•œ ํ›„ ์‹คํ–‰ํ•˜์—ฌ ์ˆ˜์ •๋œ ๋‚ด์šฉ์ด ๋ฐ˜์˜๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  • ์„œ๋ฒ„์ฝ”๋“œ ์—…๋ฐ์ดํŠธ – greeter_server/main.go
func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    return &pb.HelloReply{Message: "Hello again " + in.Name}, nil
}
  • ํด๋ผ์ด์–ธํŠธ ์—…๋ฐ์ดํŠธ – greeter_client/main.go
r, err = c.SayHelloAgain(context.Background(), &pb.HelloRequest{Name: name})
if err != nil {
    log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)

์ฝ”๋“œ ์ˆ˜์ •๋˜์—ˆ์œผ๋ฉด ์‹คํ–‰ํ•˜์—ฌ ๋™์ž‘์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  • ์„œ๋ฒ„ ์‹คํ–‰
go run greeter_server/main.go
  • ํด๋ผ์ด์–ธํŠธ ์‹คํ–‰
go run greeter_client/main.go

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹คํ–‰๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

3. ์ •๋ฆฌํ•˜๋ฉฐ

์—ฌ๊ธฐ๊นŒ์ง€ ์ƒ˜ํ”Œ์„ ํ†ตํ•ด์„œ ์•„์ฃผ ๊ฐ„๋‹จํžˆ gRPC๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•œ๋‹ค๋Š” ๊ฒƒ๋งŒ ๋ง› ๋ดค์Šต๋‹ˆ๋‹ค.
์•ž์œผ๋กœ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด์„œ ์ข€ ๋” gRPC์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

2 ๊ฐœ์˜ ๋Œ“๊ธ€"gRPC ์•Œ์•„๋ณด๊ธฐ 01ํŽธ"

  1. Reo Dongmin Lee 4์›” 01, 2017

    ์ข‹์€๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

    • ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค^^ ์ด ๋ธ”๋กœ๊ทธ ๋‚ด์— ๋‹ค์–‘ํ•œ ์ฃผ์ œ์˜ ์œ ์šฉํ•œ(๊ฐœ๋ฐœ์ž์—๊ฒŒ) ํฌ์ŠคํŒ…๋“ค์ด ๋งŽ์ด ์žˆ์œผ๋‹ˆ ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰ํ•ด์„œ ์ฝ์–ด๋ณด์„ธ์š”:) ์ข‹์€ ํ•˜๋ฃจ ๋ณด๋‚ด์‹œ๊ตฌ์š”!

ํ† ๋ก  ์ฐธ๊ฐ€

์ด๋ฉ”์ผ์€ ๊ณต๊ฐœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•„์ˆ˜ ์ž…๋ ฅ์ฐฝ์€ * ๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค