img

مقدمه‌ای برای GRPC

/
/
/

فراخوان رویه از دور(RPC) در طول دهه ها به عنوان مکانیزمی برای پردازش های داخلی ارتباطات در برنامه ها استفاده شده است. سرویس گیرنده(client) با درخواستی که دارد، با یک stub که در پشت صحنه marshalling/unmarshalling داده ی دریافتی یا برگشتی را انجام می دهد، ارتباط برقرار می کند. برای درخواست دهنده(client) به نظر می رسد که این سرویس به صورت محلی انجام می پذیرد.
در دهه ی اخیر، ما شاهد ظهور API های عمومی و استانداردهایی نظیر REST برای ساخت سرویس های مبتنی بر HTTP بوده ایم. هر دوی XML و JSON اغلب به عنوان قالبی برای داده دریافتی یا بازگشتی این سرویس ها استفاده می شوند. به دلیل فراوانی این سرویس ها و روند رو به رشد روی کار آمدن ریز-سرویس ها (micro-services)، برای ساخت سرویس هایی پرقدرت و سریع تاخیر(latency) به یک دغدغه ی اساسی تبدیل گشته است.
برای حل این مشکل، گوگل برای مدتی در حال کار بر روی ایجاد پروتکل های ارتباطی بهینه، و سرویس های رابط کاربری بوده است. علاوه بر اینها، گوگل در جهت ایجاد پیوند در میان چندین زبان، برای استفاده در سرویس دهنده ها و سرویس گیرنده ها نیز هزینه کرده است. گوگل بعدها این خدمات را به صورت متن باز در اختیار همگان قرار داد که منجر به پیدایش پروژه ی gRPC گردید. این پروژه کمک می کند که سرویس هایی را بتوان با چندین زبان نوشت، که قابلیت افزودن پشتیبانی، برای متعادل نمودن بار ترافیکی، بررسی سلامت و درستی آزمایی را داشته باشند.
مدل gRPC در شکل پائین نمایان می باشد.

 

مقدمه‌ای برای GRPC

این سرویس، متدهای آن و پیام هایش، توسط تعریف هایی جداگانه، که به عنوان ProtocolBuffers شناخته می شوند ایجاد می گردد. این تعاریف سپس توسط سرور، به وسیله ی یکی از زبان های پشتیبانی شده پیاده می شود. اغلب زبان های برنامه نویسی مدرن، مثل جاوا، پایتون، C#، Node.js، و غیره پشتیبانی می شوند. شما می توانید پیوندهای سرور را با ابزارهای پیش ساخته و یا حتی به صورت پویا و داینامیک پیاده سازی کنید.
در سمت سرویس گیرنده(client)، شما می توانید gRPC stub را با یک زبان سرویس گیرنده ی دلخواه خود ایجاد کنید، و آن stub را به طور مستقیم در سرویس گیرنده خود جهت فراخوانی سرویس استفاده کنید.

 

چرا gRPC؟
gRPC چندین مزیت دارد، که در نظر گرفتن آنها در برنامه خالی از لطف نیست. بعضی از آنها مثل:
* gRPC بر مبنای HTTP/2 ساخته شده، که برای ما پروتکل های پرسرعت ارتباطی را به ارمغان می آورد که می تواند از مزیت های جریان دو طرفه، هم تافتن و غیره استفاده کند.
* آخرین ورژن از ProtocolBuffer، یعنی version 3، تعداد بسیار بیشتری زبان را پشتیبانی می کند.
* داده ی ProtocolBuffer، فرمتی دو دویی دارد و، از این رو به حافظه ی کمتری نسبت به داده های اصلی در فرمت های JSON/XML دارد که در حال حاضر پر طرفداران ترین نوع داده می باشند. این مطلب می تواند تفاوت چشمگیری برای مشکل تاخیر ایجاد کند، اگر در API خود با این مورد دست به گریبان هستید.

 

gPRC و CNCF
gRPC چیزی حدود بیش از یکسال پیش توسط گوگل منتشر گردید و از آن موقع تا به حال، شتاب فزاینده ای در جهت استفاده از آن در صنعت به عنوان پیوند در میان ارتباطات ریز-سرویس ها به وجود آمده است، علی الخصوص در مواقعی که تاخیر مسئله ای کلیدی باشد. اخیرا نیز gPRC توسط Cloud Native Computing Foundation(CNCF)، به عنوان پروژه اصلی قلمداد شده، که قدم بزرگی به سمت فراگیرتر شدن gRPC محسوب می شود. این تکنولوژی سبب شده است که مثال هایی چون Kubernetes، Prometheus، و دیگران به هم پیوند بخورند، که به عنوان اساس برنامه های از پایه ابری (cloud) محسوب می شوند.

 

Wire Protocol – ProtocolBuffers
ProtocolBuffer ها هم زبانی برای تعریف رابط محسوب می شوند، و هم یک قالب پیام، که اغلب برای تعریف رابط سرویس استفاده می شود، یعنی اینکه متدهای سرویس کدام ها هستند و چه پیام هایی رد و بدل می شوند. قالب های پیام نیز همچنین غالبا توسط بخش مخصوص خودشان تعریف می شوند.
این فایل تعریف پروتکل، این قابلیت را دارد که برای تولید پیوند، هم برای سرویس دهنده، و هم برای سرویس گیرنده، به کار برود، یا اینکه شما اختیار بارگذاری تعریف را به صورت پویا داشته، و می توانید اجرا را آماده سازی کنید. ProtocolBuffer ها اکنون در دو ورژن proto2 و proto3 در دسترس هستند، اما ما از نسخه ی proto3 استفاده خواهیم کرد، که از دامنه ی وسیع تری از زبان ها پشتیبانی می کند.
بهترین راه درک protocolBuffer ها از طریق مثالی است که ما در خلال این مقاله خواهیم ساخت. این مقاله شامل پیاده سازی سرورها و سرویس گیرنده ها خواهد بود. ما سرویسی را خواهیم ساخت که OSFY Stats نامیده می شود. این سرویس دو متود را ارائه می دهد، یکی برای گرفتن مقاله برتر از وب سایت OSFY، و دیگری برای گرفتن آمار از یک مقاله ی به خصوص، مثل تعداد بازدیدها، و امثال آن خواهد بود. ما پیاده سازی واقعی را بعدا ارائه نخواهیم داد، بلکه هدف از این تمرین، بیشتر یادگیری ایجاد مشخصات و قالب پیام در کنار استاندارد ProtocolBuffer ها می باشد.
فایل proto(osfy_stats.proto) در زیر هویدا می باشد:

Syntax = “proto3”;
Package osfy_stats;
//Service. Define the methods that the grpc server can expose
To the client.
Service OSFYStatsService {
rpc toparticles (TopArticlesRequest) returns
(TopArticlesResponse);
rpc articleStats (ArticleStatsRequest) returns
(ArticleStatsResponse);
}

//Message Type definition for TopArticlesResponse
message TopArticleResponse {
repeated Article articles = 1;
}
//Message Type definition for Article
message Article {
int32 id = 1;
string title = 2;
string url = 3;
}
//Message Type definition for ArticleStatsRequest
message ArticleStatsRequest {
Int32 id = 1;
}
//Message Type definition for ArticleStatsRequest
message ArticleStatsRequest {
Int32 id = 1;
}
//Message Type definition for ArticleStatsResponse
message ArticleStatsResponse {
int32 id = 1;
int32 numViews = 2;
int32 numLikes = 3;
int32 numComments = 4;

اجازه دهید مختصری به بررسی فایل proto بپردازیم:
* در بالای فایل، ما ورژن ProtocolBuffers را تعیین می کنیم، به علاوه ی سرویسی که درون بسته ای به نام osfy_stats قرار دارد.
* سپس ما سرویسی به نام OSFYStatsService را تعریف کرده، و دو متودی را که این سرویس ارائه می دهد را تعیین می کنیم، که toparticles و articleStats نام دارند.
* قالب پیام های ورودی و خروجی تعیین شده اند، و قالب پیام برای هر درخواست و پاسخ درون فایل یکسانی تعریف شده است. توجه داشته باشید که تعریف ProtocolBuffers از انواع گوناگون از مقیاس ها(int32, float و string) و دیگر چیزهای پیچیده ای چون تکرارپذیرها، درهم تنیده ها و غیره پشتیبانی می کند. اعداد یگانه ای که ملاحظه می کنید، مثل، ۱، ۲، ۳، و غیره، از فرمت دودویی برای کدبندی و کدگشایی آنها استفاده می شود.
* متود toparticles تعداد مقالات بالایی را که دلخواه ما هستند را گرفته و آرایه ای از این مقاله ها را تحویل می دهد، که هر مقاله شامل field های چون ID، عنوان و URL می شود.
* متود articleStats،ID هر مقاله را به عنوان ورودی گرفته، و پیامی محتوی آماری مثل تعداد بازدیدها، لایک ها و کامنت ها را تحویل می دهد.

پیاده سازی سرور
اکنون که ما سرویس را تعریف کرده ایم، زمان آن است که به پیاده کردن سرور بپردازیم. ما برای این کار از Node.js استفاده خواهیم کرد، و فرض بر آن است که شما محیط Node.js را نصب و در دسترس بر روی رایانه ی خود دارید.
ما به تعداد اندکی کتابخانه ی node نیازمنیدیم که بر روی رایانه ما نصب باشند و شما با استفاده از npm قادر به نصب آنها خواهید بود:

$ npm install grpc
$ npm install grpcli

حالا، اجازه دهید نگاهی داشته باشیم به پیاده سازی سمت سرور.
فایل server.js در زیر مشخص می باشد:

const grpc = require(‘grpc’);

const proto = grpc.load(‘osfy_stats.proto’);
const server = new grpc.Server();

let top_article = [
{ id:20000 , title: ‘T1’, url: ‘URL1’ },
{ id:20001, title: ‘T2’, url: ‘URL2’ },
{ id:2002, title: ‘T3’, url: ‘URL3’},
{ id:2003, title: ‘T4’, url: ‘URL4’},
{ id:2004, title: ‘T5’, url: ‘URL5’}
];
//define the callable methods that correspond to the methods
defined in the protofile
server.addProtoService(proto.osfy_stats.OSFYStatsService.service, {
toparticles(call, callback) {

if (call.request.numResults < 1 || call.request.numResults > 5) {
callback(new Error(‘Invalid number of Results provided.
It should be in the range of [1-5]’));
} else {
var topresults = top_article.slice(0, call.request.numResults);
callback(null, {articles:topresults });
}
},
articleStats(call, callback) {
let article_id = call.request.id;
//make some calls to actual API

let numViews = 1000;
let numLikes = 30;
let numComments = 5;

callback(null, {
id:article_id,
numViews,
numLikes,
numComments
});
}
});
//Start the server
server.start();
console.log(‘OSFY Stats GPRC Server is now on port->’, ‘۰٫۰٫۰٫۰:۵۰۰۰۰’);

 

اجازه دهید مختصری به بررسی کد بپردازیم:
* ما فایل تعریف proto را بارگذاری کرده و یک نمونه از سرور را می سازیم.
* برای نمونه ی سرور، ما فقط سرویس proto.osfy_stats.OSFYStatsService.service را پیونده می دهیم و پیاده سازی دو متود articleStats و toparticles را ارائه می دهیم.
* ما ماکتی از پیاده سازی دو متود اصلی را ارائه می دهیم و، در واقعیت شما بایستی به analytics API خود متصل باشید.
* برای آغاز به کار سرور، تمام آنچه که ما بایستی انجام دهیم اجرای فرمان زیر است، که نشان می دهد که آیا سرور کار می کند یا خیر:

$ node server.js
OSFY Stats GRPC Server is now running on port-> 0.0.0.0:50000

 

آزمایش سرویس
برای آزمودن سرویس، می توانیم از ماژولnode، یعنی grpcli، که آن را قبلا نصب کرده ایم استفاده کنیم. برای اجرای grpcli، و اشاره ی آن به فایل proto و سروری که در حال اجراست، فرمان زیر را استفاده کنید:

grpcli –f osfy_Stats.proto – -ip=127.0.0.1 – -port=50000 –i

این فرمان ارتباط را ایجاد می کند، و سپس ما می توانیم از لیست rpc استفاده کنیم و متودها را فراخوانی کرده تا سرویس خود را آزمایش کنیم. فراخوانی های نمونه در زیر نمایش داده شده اند:

$ grpcli -f osfy_stats.proto – -ip=127.0.0.1 – -port=50000 -i
Package: osfy_stats
Service: OSFYStatsService
Host: 127.0.0.1
Port: 50000
Secure: No
[grpc+insecure://127.0.0.1:50000]# rpc list
toparticles(TopArticleRequest) {
return ArticleStatsResponse;
}
articleStats(ArticleStatsRequest) {
return ArticleStatsResponse;
}
[grpc+insecure://127.0.0.1:50000]# rpc call articleStats
{“id”:۱}
Info: Calling articleStats on OSFYStatsService
Response:
{
“id”: ۱,
“numViews”: ۱۰۰۰,
“numLikes”: ۳۰,
“numComments”: ۵
}
[grpc+insecure://127.0.0.1:50000]#

استفاده از سرویس gRPC
اکنون که ما سرویسمان را آزمایش کرده ایم، می توانیم کد سرویس گیرنده ی خود را به صورت زیر بنویسیم. این کد مفهومش این است که ما ابتدا فایل proto را بارگذاری می کنیم و سپس سرویس گیرنده ای را برای سروری که در حال اجرا است، ایجاد می کنیم. زمانی که سرویس گیرنده متصل شد، می توانیم مستقیما متود های سرویس را به گونه ای که در زیر مشاهده می کنید، فراخوانی کنیم:

const grpc = require(‘grpc’);
const proto = grpc.load(‘osfy_stats.proto’);

const client = new proto.osfy_stats.OSFYStatsService(‘localhost:50000’, grpc.credentials.
createInsecure());

client.toparticles({“numResults”:۲}, (error, response) => {
if (!error) {
console.log(“Total Article: “ + response.articles.length);
for (article of response.articles) {
console.log(article.id+ “ “ + article.title + “ “ +
article.url);
}
} else {
Console.log(“Error: “, error.message);
}
});
client.articleStats({“id”:۲}, (error, response) => {
if (!error) {
console.log(“Article ID : “ + response.id + “ Views :
“ + response.numViews + “ Likes : “ + response.numLikes + “ Comments : “ + response.numComments );
} else {
Console.log(“Error:”, error.message);
}
});

شما می توانید سرویس گیرنده را اجرا کرده، و شاهد فراخوانده شدن دو عمل محیا شده توسط سرویس باشید. خروجی که خواهید دید، به شکل زیر است:

$ node client.js
Article ID: 2 Views : 1000 Likes: 30 Comments : 5
Total Articles : 2
۲۰۰۰۰ T1 URL1
۲۰۰۰۱ T2 URL2

 

پیوندهای سایر زبان ها
شاهد بودیم که چگونه می شود، رابط کاربری سرویس را توسط قالب ProtocolBuffers تعریف کنیم، و سپس دیدیم که با استفاده از Node.js می شود برای توسعه ی پیوند های، هم سمت سرور و هم سمت سرویس گیرنده استفاده نمود. مزیت gRPC این است که سمت سرور شما می تواند با زبان به خصوصی تعریف شود، مثلا با Node.js، اما پیوند سرویس گیرنده می تواند با زبان دیگری، مثلا با python، java و یا هر زبان دیگری که پشتیبانی می گردد، نوشته شود. برای دیدن لیست زبان هایی که پشتیبانی می شوند، (http://www.grpc.io/docs/) را بررسی کنید، و زبان دلخواه خود را انتخاب کنید.
معماری های مدرن، توصیه می کنند که برنامه های یک تکه را به چندین به ریز-سرویس تقسیم کنید تا برنامه خود را با توجه به این سرویس ها پیاده سازی نمایید. این امر سبب ایجاد حجم عظیمی از درخواست های میان-سرویسی می شود که موجب پدید آمدن موضوع تاخیر می گردد، که برای داشتن سرویسی پرسرعت و بهینه حتما بایستی مرتفع گردد. gRPC هم wire transfer protocol بهینه ای را به ارمغان می آورد، و هم امکان استفاده از چندین زبان برای ایجاد پیوند را همراه با خود دارد. با انتخاب gRPC به عنوان یک پروژه مهم در Cloud Native Computing Foundation، شانس اینکه در آینده توسعه دهندگان بیشتری برای پروژه های خود از gRPC استفاده کنند، بسیار بالا می باشد.

 

منابع

[۱] gRPC.io home page: www.grpc.io [2] gRPC Documentation: http://www.grpc.io/docs/
[۳] Protocol Buffers Documentation: https://developers.google.
com/protocol-buffers/docs/overview
[۴] gRPC Community: http://www.grpc.io/community/
[۵] Cloud Native Computing Foundation: https://www.cncf.io/

نظر بدهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

It is main inner container footer text