1. Giriş
Bu codelab'de, Go ile yazılmış bir rota eşleme uygulamasının temelini oluşturan bir istemci ve sunucu oluşturmak için gRPC-Go'yu kullanacaksınız.
Eğitimin sonunda, haritada belirli koordinatlarda bulunan yerin adını veya posta adresini almak için gRPC kullanarak uzak bir sunucuya bağlanan bir istemciniz olacak. Tam teşekküllü bir uygulama, bir rota üzerindeki önemli yerleri listelemek veya özetlemek için bu istemci-sunucu tasarımını kullanabilir.
Hizmet, istemci ve sunucu için standart kod oluşturmak üzere kullanılacak bir Protocol Buffers dosyasında tanımlanır. Böylece, bu işlevselliği uygularken zamandan ve emekten tasarruf edersiniz.
Oluşturulan bu kod, yalnızca sunucu ile istemci arasındaki iletişimin karmaşıklıklarını değil, aynı zamanda veri serileştirme ve seri durumdan çıkarma işlemlerini de ele alır.
Neler öğreneceksiniz?
- Hizmet API'sini tanımlamak için Protocol Buffers'ı kullanma.
- Otomatik kod oluşturma kullanarak bir Protokol Arabellek tanımından gRPC tabanlı istemci ve sunucu oluşturma.
- gRPC ile istemci-sunucu iletişimi hakkında bilgi sahibi olmanız gerekir.
Bu codelab, gRPC'ye yeni başlayan veya gRPC hakkında bilgi tazelemek isteyen Go geliştiricilerin yanı sıra dağıtılmış sistemler oluşturmakla ilgilenen herkes için hazırlanmıştır. Daha önce gRPC deneyimi gerekmez.
2. Başlamadan önce
Ön koşullar
Aşağıdakileri yüklediğinizden emin olun:
- Go toolchain sürümü 1.24.5 veya daha yeni olmalıdır. Yükleme talimatları için Go'nun Başlangıç bölümüne bakın.
- Protokol arabelleği derleyicisi,
protoc
, 3.27.1 veya sonraki sürümler. Yükleme talimatları için derleyicinin yükleme kılavuzuna bakın. - Go ve gRPC için protokol arabelleği derleyici eklentileri. Bu eklentileri yüklemek için aşağıdaki komutları çalıştırın:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
PATH
değişkeninizi, protokol arabelleği derleyicisinin eklentileri bulabilmesi için güncelleyin:
export PATH="$PATH:$(go env GOPATH)/bin"
Kodu alın
Bu codelab, tamamen sıfırdan başlamanız gerekmemesi için uygulamanın kaynak kodunun tamamlayabileceğiniz bir iskeletini sağlar. Aşağıdaki adımlarda, protokol arabellek derleyici eklentilerini kullanarak standart gRPC kodu oluşturma da dahil olmak üzere uygulamanın nasıl tamamlanacağı gösterilmektedir.
Bu kaynak kodunu GitHub'dan .ZIP arşivi olarak indirin ve içeriğini çıkarın.
Alternatif olarak, bir uygulamayı yazmayı atlamak istiyorsanız tamamlanmış kaynak kodu GitHub'da mevcuttur.
3. Hizmeti tanımlama
İlk adımınız, Protocol Buffers'ı kullanarak uygulamanın gRPC hizmetini, RPC yöntemini, istek ve yanıt mesajı türlerini tanımlamaktır. Hizmetinizde sunulacaklar:
- Sunucunun uyguladığı ve istemcinin çağırdığı
GetFeature
adlı bir RPC yöntemi. GetFeature
yöntemi kullanılırken istemci ile sunucu arasında değiştirilen veri yapıları olanPoint
veFeature
mesaj türleri. İstemci, sunucuya gönderdiğiGetFeature
isteğinde harita koordinatlarınıPoint
olarak sağlar ve sunucu, bu koordinatlarda bulunan her şeyi açıklayan ilgili birFeature
ile yanıt verir.
Bu RPC yöntemi ve mesaj türleri, sağlanan kaynak kodun routeguide/route_guide.proto
dosyasında tanımlanır.
Protocol Buffers genellikle protobuf olarak bilinir. gRPC terminolojisi hakkında daha fazla bilgi için gRPC'nin Temel kavramlar, mimari ve yaşam döngüsü başlıklı makalesine bakın.
Mesaj türleri
Kaynak kodun routeguide/route_guide.proto
dosyasında önce Point
mesaj türünü tanımlayın. Point
, haritadaki bir enlem-boylam koordinat çiftini temsil eder. Bu codelab'de koordinatlar için tam sayıları kullanın:
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
1
ve 2
sayıları, message
yapısındaki her alan için benzersiz kimlik numaralarıdır.
Ardından, Feature
mesaj türünü tanımlayın. Bir Feature
, Point
ile belirtilen bir konumdaki bir şeyin adı veya posta adresi için string
alanını kullanır:
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
Hizmet yöntemi
route_guide.proto
dosyasında, uygulamanın hizmeti tarafından sağlanan bir veya daha fazla yöntemi tanımlayan RouteGuide
adlı bir service
yapısı bulunur.
rpc
yöntemini RouteGuide
tanımının içine ekleyin.GetFeature
Daha önce açıklandığı gibi, bu yöntem belirli bir koordinat kümesinden bir konumun adını veya adresini arar. Bu nedenle, belirli bir Point
için GetFeature
işlevinin Feature
döndürmesini sağlayın:
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
Bu, tekli bir UPÇ yöntemidir: İstemcinin sunucuya istek gönderdiği ve yanıtın geri gelmesini beklediği basit bir UPÇ'dir (yerel bir işlev çağrısı gibi).
4. İstemci ve sunucu kodunu oluşturma
Ardından, protokol arabelleği derleyicisini kullanarak .proto
dosyasından hem istemci hem de sunucu için standart gRPC kodunu oluşturun. routeguide
dizininde şunu çalıştırın:
protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ route_guide.proto
Bu komut aşağıdaki dosyaları oluşturur:
- Uygulamanın mesaj türlerini oluşturma ve verilerine erişme işlevlerini içeren
route_guide.pb.go
. route_guide_grpc.pb.go
: İstemcinin hizmetin uzak gRPC yöntemini çağırmak için kullandığı işlevleri ve sunucunun bu uzak hizmeti sağlamak için kullandığı işlevleri içerir.
Ardından, istemci bir istek gönderdiğinde sunucunun yanıt verebilmesi için sunucu tarafında GetFeature
yöntemini uygulayacağız.
5. Hizmeti uygulama
Sunucu tarafındaki GetFeature
işlevi, asıl işin yapıldığı yerdir: Bu işlev, istemciden bir Point
mesajı alır ve bilinen yerlerin listesinden ilgili konum bilgilerini Feature
mesajıyla döndürür. İşlevin server/server.go
'daki uygulanışı:
func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
for _, feature := range s.savedFeatures {
if proto.Equal(feature.Location, point) {
return feature, nil
}
}
// No feature was found, return an unnamed feature
return &pb.Feature{Location: point}, nil
}
Bu yöntem, uzak bir istemciden gelen istek üzerine çağrıldığında işleve, UPÇ çağrısını açıklayan bir Context
nesnesi ve bu istemci isteğinden gelen bir Point
protokol arabellek nesnesi iletilir. İşlev, aranan konum için bir Feature
protokol arabelleği nesnesi ve gerekirse bir error
döndürür.
Yöntemde, belirli bir Point
için uygun bilgilerle bir Feature
nesnesi doldurun ve ardından gRPC'ye RPC ile ilgilenmeyi bitirdiğinizi ve Feature
nesnesinin istemciye döndürülebileceğini bildirmek için nil
hatasıyla birlikte return
.
GetFeature
yöntemi, istemcilerden gelen konum araması isteklerinin bu işleve yönlendirilebilmesi için routeGuideServer
nesnesinin oluşturulup kaydedilmesini gerektirir. Bu işlem main()
bölümünde yapılır:
func main() {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
var opts []grpc.ServerOption
grpcServer := grpc.NewServer(opts...)
s := &routeGuideServer{}
s.loadFeatures()
pb.RegisterRouteGuideServer(grpcServer, s)
grpcServer.Serve(lis)
}
main()
bölgesinde adım adım neler oluyor?
lis, err := net.Listen(...)
kullanarak uzak istemci isteklerini dinlemek için kullanılacak TCP bağlantı noktasını belirtin. Varsayılan olarak uygulama, sunucu çalıştırılırken komut satırında--port
anahtarı iletilerek veyaport
değişkeniyle belirtildiği gibi50051
TCP bağlantı noktasını kullanır. TCP bağlantı noktası açılamazsa uygulama ölümcül bir hatayla sonlanır.grpc.NewServer(...)
kullanarak gRPC sunucusunun bir örneğini oluşturun ve bu örneğigrpcServer
olarak adlandırın.- Uygulamanın API hizmetini temsil eden bir yapı olan
routeGuideServer
içins.
adlı bir işaretçi oluşturun. - Diziyi
s.loadFeatures()
iles.savedFeatures
,GetFeature
üzerinden aranabilecek konumlarla doldurun. GetFeature
için RPC çağrılarının uygun işleve yönlendirilmesi amacıyla API hizmetini gRPC sunucusuna kaydedin.- İstemci istekleri için engelleme beklemesi yapmak üzere bağlantı noktası ayrıntılarımızla sunucuda
Serve()
işlevini çağırın. Bu işlem, süreç sonlandırılana veyaServe()
işlevi çağrılana kadar devam eder.Stop()
loadFeatures()
işlevi, koordinat-konum eşlemelerini server/testdata.go
kaynağından alır.
6. İstemciyi oluşturma
Şimdi istemci kodunu uygulayacağınız yer olan client/client.go
dosyasını düzenleyin.
Uzak hizmetin yöntemlerini çağırmak için öncelikle sunucuyla iletişim kuracak bir gRPC kanalı oluşturmamız gerekir. Bunu, istemcinin main()
işlevinde sunucunun hedef URI dizesini (bu örnekte yalnızca adres ve bağlantı noktası numarası) grpc.NewClient()
'ya ileterek oluştururuz:
conn, err := grpc.NewClient("dns:///"+*serverAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("fail to dial: %v", err)
}
defer conn.Close()
serverAddr
değişkeniyle tanımlanan sunucunun adresi varsayılan olarak localhost:50051
'dir ve istemci çalıştırılırken komut satırındaki --addr
anahtarıyla geçersiz kılınabilir.
İstemcinin, TLS veya JWT kimlik bilgileri gibi kimlik doğrulama kimlik bilgileri gerektiren bir hizmete bağlanması gerekiyorsa istemci, gerekli kimlik bilgilerini içeren bir DialOptions
nesnesini grpc.NewClient
için parametre olarak iletebilir. RouteGuide
hizmeti herhangi bir kimlik bilgisi gerektirmez.
gRPC kanalı ayarlandıktan sonra, Go işlev çağrıları aracılığıyla RPC'ler gerçekleştirmek için bir istemci stub'ına ihtiyacımız vardır. Stub, uygulamanın .proto
dosyasından oluşturulan route_guide_grpc.pb.go
dosyası tarafından sağlanan NewRouteGuideClient
yöntemi kullanılarak alınır.
import (pb "github.com/grpc-ecosystem/codelabs/getting_started_unary/routeguide")
client := pb.NewRouteGuideClient(conn)
Hizmet yöntemlerini arama
gRPC-Go'da RPC'ler, engelleme/eşzamanlı modda çalışır. Bu, RPC çağrısının sunucunun yanıt vermesini beklediği ve yanıt ya da hata döndüreceği anlamına gelir.
Simple RPC
Basit RPC GetFeature
'yi çağırmak, bu durumda client.GetFeature
olan yerel bir yöntemi çağırmak kadar kolaydır:
point := &pb.Point{Latitude: 409146138, Longitude: -746188906}
log.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude)
// Call GetFeature method on the client.
feature, err := client.GetFeature(context.TODO(), point)
if err != nil {
log.Fatalf("client.GetFeature failed: %v", err)
}
İstemci, daha önce oluşturulan sap üzerinde yöntemi çağırır. Yöntemin parametreleri için istemci bir Point
istek protokolü arabelleği nesnesi oluşturur ve bu nesneyi doldurur. Ayrıca, gerekirse RPC'mizin davranışını değiştirmemize olanak tanıyan bir context.Context
nesnesi de iletirsiniz. Örneğin, çağrı için bir zaman sınırı tanımlayabilir veya devam eden bir RPC'yi iptal edebilirsiniz. Çağrı hata döndürmezse istemci, sunucudan gelen yanıt bilgilerini ilk dönüş değerinden okuyabilir:
log.Println(feature)
Sonuç olarak, istemcinin main()
işlevi şu şekilde görünmelidir:
func main() {
flag.Parse()
// Set up a connection to the gRPC server.
conn, err := grpc.NewClient("dns:///"+*serverAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("fail to dial: %v", err)
}
defer conn.Close()
// Create a new RouteGuide stub.
client := pb.NewRouteGuideClient(conn)
point := &pb.Point{Latitude: 409146138, Longitude: -746188906}
log.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude)
// Call GetFeature method on the client.
feature, err := client.GetFeature(context.TODO(), point)
if err != nil {
log.Fatalf("client.GetFeature failed: %v", err)
}
log.Println(feature)
}
7. Deneyin
Uygulamanın çalışma dizininde aşağıdaki komutları çalıştırarak sunucu ve istemcinin birbirleriyle doğru şekilde çalıştığını onaylayın:
- Sunucuyu bir terminalde çalıştırın:
cd server go run .
- İstemciyi başka bir terminalden çalıştırma:
cd client go run .
Aşağıdakine benzer bir çıkış görürsünüz. Zaman damgaları, netlik için çıkarılmıştır:
Getting feature for point (409146138, -746188906)
name:"Berkshire Valley Management Area Trail, Jefferson, NJ, USA" location:<latitude:409146138 longitude:-746188906 >
Getting feature for point (0, 0)
location:<>
8. Sırada ne var?
- gRPC'nin işleyiş şeklini Introduction to gRPC (gRPC'ye Giriş) ve Core concepts (Temel kavramlar) başlıklı makalelerden öğrenebilirsiniz.
- Temel bilgiler eğitimini inceleyin.
- API referansını inceleyin.