Sidecar Pattern چیست؟
الگوی ماشین کناری برای ترویج تفکیک نگرانی ها در معماری میکروسرویس ها استفاده می شود. این الگو به ما اجازه میدهد تا پردازشهایی را به یک ماژول جداگانه بارگذاری کنیم که همراه با مؤلفه اصلی سرویس مستقر میشود. الگوی کاروان کناری گاهی اوقات به عنوان الگوی تجزیه نامیده می شود.
چرا در معماری Microservices مفید است؟
به طور کلی، در معماری میکروسرویس ها، مواردی مانند ثبت، نظارت، پیام رسانی، ردیابی، رمزگذاری و رمزگشایی، پیکربندی و مدیریت استثناها ماژول های رایجی هستند که باید در هر سرویس پیاده سازی کنیم و به دلیل محدودیت زمانی ممکن است دوباره همان کد را تکرار کنیم. دوباره در سراسر خدمات این یک عمل بد در نظر گرفته می شود و پیچیدگی کلی برنامه افزایش خواهد یافت.
با استفاده از الگوی سایدکار، میتوانیم این نوع مشکل را با حذف کدهای اضافی در میان سرویسها و ایجاد مؤلفهها یا سرویسهای مجزا از بین ببریم و آن را به اندازه کافی عمومی کنیم تا بتوان آن را دوباره استفاده کرد.
![](http://pezhvak24.ir/dl/codenevis/firstcode/article/microservices-design-using-sidecar-pattern/Images/sidecar1.png)
رویکرد راه حل
جزئیات طراحی در واقع بسیار ساده است. نکته کلیدی در اینجا این است که شما باید ماژول را به اندازه کافی برای نیازهای فوری خود بنویسید، در حالی که برای سایر بخش های سیستم خود به اندازه کافی عمومی باشد.
لازم نیست که یک ماژول/سرویس سایدکار بخشی از برنامه اصلی شما باشد، بلکه به آن متصل باشد. هر جا برنامه والد می رود می رود و می تواند از زمان اجرا مشابهی مانند mocroservies استفاده کند.
هنگامی که آن را مستقر می کنیم، عملکرد باید ظاهر شود و مانند نوعی پلاگین کار می کند و با برنامه سرویس اصلی بازی می کند. اگر آن بخش از عملکرد به جای دیگری نیاز داشته باشد، ما به سادگی مرجع خودروی کناری را به سرویس اضافه می کنیم و عملکرد مورد نیاز را به ارث می برد.
با الگوی سایدکار، ما می توانیم سایدکار را به عنوان یک ماژول مرتبط با هر سرویس قابل اجرا مستقر کنیم.
![](http://pezhvak24.ir/dl/codenevis/firstcode/article/microservices-design-using-sidecar-pattern/Images/sidecar2.png)
بیایید در نظر بگیریم، ما سه میکروسرویس داریم. ما اولین خودروی جانبی خود را به نام ورود به هر سرویس اضافه کردیم. هنگامی که استقرار را انجام می دهیم، آن را به عنوان بخشی از سرویس والد آپلود می کنیم. بنابراین همه اینها در یک فرآیند واحد اجرا می شوند اما ماژول های بسیار متمایز هستند. و ما همه جا از مزایای سایدکار بهره می بریم در حالی که در هر سرویس کد نمی نویسیم.
به طور مشابه، ما یک sidecar دیگر به نام configuration اضافه کرده ایم و آن را برای هر سرویس اعمال می کنیم. اما برای دو مورد از سرویسهای ما، کارت فرعی پیامرسانی اعمال شد. این قدرت سایدکار است.
مزیت این رویکرد این است که شما کارکرد کناری را انتخاب می کنید و جایی را که می خواهید عملکرد را اعمال کنید و به سادگی آن را اعمال می کنید. تا زمانی که سایدکار شما به اندازه کافی کلی نوشته شده باشد، می توانید آن را در هر جایی اعمال کنید و آن سرویس به طور خودکار این عملکرد را از طریق یک فرآیند واحد به ارث می برد. در نتیجه، پیچیدگی و افزونگی در کد را با انتزاع کردن عملکردهای مشترک مرتبط با زیرساخت در یک لایه دیگر کاهش میدهد.
نمونه پیادهسازی الگوی Sidecar در میکروسرویسهای مبتنی بر هسته ASP.NET
من 3 پروژه میکروسرویس به نام دانشجویان، دوره ها و پرداخت ها را در ASP.NET Core ایجاد کردم. من همچنین یک کتابخانه کلاس به عنوان یک پروژه مشترک ایجاد کردم و بسته های NuGet مورد نیاز را اضافه کردم. در اینجا، ما مقادیر پیکربندی برنامه را از Azure Key Vault در هر سرویس می خوانیم، فقط برای اینکه نشان دهیم الگوهای سایدکار چگونه کار می کنند.
![](http://pezhvak24.ir/dl/codenevis/firstcode/article/microservices-design-using-sidecar-pattern/Images/Config1.png)
پیاده سازی زیر برای روش توسعه IWebHostBuilder در SidecarExtensions.cs است. این یک روش عمومی برای پیکربندی است که در هر سرویس استفاده خواهد شد.
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Common {
public static class SidecarExtensions {
public static IWebHostBuilder UseKVConfiguration(this IWebHostBuilder webHostBuilder) {
webHostBuilder.ConfigureServices(services => {
IConfigurationRoot configuration = LoadKeyVaultSettings();
services.AddSingleton < IConfiguration > (configuration);
});
return webHostBuilder;
}
public static IConfigurationRoot LoadKeyVaultSettings() {
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true).AddEnvironmentVariables().Build();
var sc = new ServiceConfiguration();
configuration.Bind(sc);
var configBuilder = new ConfigurationBuilder();
if (sc.KeyVault != null && !string.IsNullOrEmpty(sc.KeyVault.Uri)) {
if (!string.IsNullOrEmpty(sc.KeyVault.ClientId) && !string.IsNullOrEmpty(sc.KeyVault.Secret)) {
configBuilder.AddAzureKeyVault(sc.KeyVault.Uri, sc.KeyVault.ClientId, sc.KeyVault.Secret);
}
}
return configBuilder.AddJsonFile("appsettings.json", optional: true).AddEnvironmentVariables().Build();
}
public class ServiceConfiguration {
public KeyVaultInfo KeyVault {
get;
set;
}
}
public class KeyVaultInfo {
public string Uri {
get;
set;
}
public string ClientId {
get;
set;
}
public string Secret {
get;
set;
}
}
}
}
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Common {
public static class SidecarExtensions {
public static IWebHostBuilder UseKVConfiguration(this IWebHostBuilder webHostBuilder) {
webHostBuilder.ConfigureServices(services => {
IConfigurationRoot configuration = LoadKeyVaultSettings();
services.AddSingleton < IConfiguration > (configuration);
});
return webHostBuilder;
}
public static IConfigurationRoot LoadKeyVaultSettings() {
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true).AddEnvironmentVariables().Build();
var sc = new ServiceConfiguration();
configuration.Bind(sc);
var configBuilder = new ConfigurationBuilder();
if (sc.KeyVault != null && !string.IsNullOrEmpty(sc.KeyVault.Uri)) {
if (!string.IsNullOrEmpty(sc.KeyVault.ClientId) && !string.IsNullOrEmpty(sc.KeyVault.Secret)) {
configBuilder.AddAzureKeyVault(sc.KeyVault.Uri, sc.KeyVault.ClientId, sc.KeyVault.Secret);
}
}
return configBuilder.AddJsonFile("appsettings.json", optional: true).AddEnvironmentVariables().Build();
}
public class ServiceConfiguration {
public KeyVaultInfo KeyVault {
get;
set;
}
}
public class KeyVaultInfo {
public string Uri {
get;
set;
}
public string ClientId {
get;
set;
}
public string Secret {
get;
set;
}
}
}
}