Merhabalar, bu yazımızdaki konumuz günümüzde giderek popülaritesini artıran ve yaygınlaşan, çoğu zaman monolitik uygulamarın yerini alan, Uygulamaların tek bir yapı üzerinde geliştirmek yerine birçok uygulamanın (servisin) kendilerine ait veritabanlarıyla birlikte birbirleriyle konuşmasını temel alan biri olan api gateway katmanı.
Öncelikle mikroservis mimarisine yukarıda kabaca değinmiş olduk. Birden fazla uygulamacıktan oluşan bu yapıda requestlerin ilgili servislere iletilmesi ihtiyacı ortaya çıkıyor. Örneğin, bir e-ticaret uygulaması düşünün sepet ve ödeme için ayrı servislerin oluğunu düşünelim. Kullanıcı ürünü sepetine ekleyecek ve sepette eklediği ürünler toplam tutarı yer alacaktır. Kullanıcı ürünleri almaya karar verip sepetini onayladığında karşısına gelen ödeme penceresinde toplam tutarın gelmesi sepet servisi ile ödeme servisi arasındaki iletişim sayesinde gerçekleşiyor ve bu iletişim esnasında sepet işlemleri için sepet servisine, ödeme için ödeme servisine requestler ayrı ayrı gönderilmeden tek bir entry point üzerinden iletiliyor. Tam olarak bu iletme işlemini yapan yapılara api gateway olarak adlandırabiliriz. Api gateway katmanını, mikroservis mimarisiyle oluşturulmuş bir çok uygulamadan oluşan yapımızdaki servislerin önünde yer alan bir proxy katmanı gibi düşünebiliriz. Bu noktada temel görevi için uygulamamıza farklı noktalardan gelen requestlerin ilgili servislerin endpointine iletmek ve gerektiğinde birden çok servisten gelen cevabın sonucunu geri dönebilmek diyebiliriz.
.Net core mikroservis yapısı için Microsoftun görselleştirdiği yapıya bir göz atalım ve api gatewayın diğer özelliklerini kısaca açıklayalım son olarakta, .Net Core ile Ocelot kullanarak örnek bir uygulama geliştirelim.
Routing: Client tarafından gelen requestlerin ilgili mikroservise iletilmesini sağlar.
Caching: mikroservislerden gelen cevapları(response) cacheleyerek, veri için her seferinde servisin endpointine gitmek yerine cache’ten getirebilmesine olanak sağlar.
Logging: Mikroservislere giden ve dönen cevapları loglayabilir, monitorize edebiliriz.
Authentication/Authorization: Mikroservislere giden tüm requestler ve dönen responselar tek bir katman üzerinden (api gateway) gerçekleşeceğinden mikroservis uygulamalarımız için authentication ve authorization yönetimini merkezi(tek) bir noktadan sağlar
Rate Limiting: Servislere giden requestlerin kaynağını belirleyebilir, gelen request sayılarını limitleyebiliriz.
Tüm bu özelliklere daha fazlasını ekleyebiliriz ancak kısaca temel olduğunu düşündüğüm özelliklere böylece değinmiş olduk. Şimdi gelin birlikte .Net Core ile Ocelot Api Gateway kullanarak örnek bir proje yapalım.
Senaryomuz: Müşteriler ve ürünler adında iki adet servisten oluşan yapımız olsun ve bu servislere ocelot üzerinden call edebilim ve konfigürasyonları gerçekleştirelim.
öncelikle servislerimizi şu komutlarla oluşturalım;
dotnet new webapi -o ProductApi
dotnet new webapi -o CustomerApi
dotnet new webapi -o OcelotGateway
daha sonra product servisi için ProductsController adında bir controller oluşturup tüm ürünleri getiren ve id parametresine göre ürünleri getiren iki adet metodu şu şekilde oluşturalım;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok(new string[] {"Laptop", "Mobile Phone", "Pen" "NoteBook", "Brush"});
}
[HttpGet("{id}")]
public IActionResult Get(int id)
{
return Ok(new string[] {"Pen", "NoteBook", "Brush"});
}
}
}
aynı yöntemle customer servisi için müşterilerimizi dönen metodu oluşturduğumuz CustomersController altında şu şekilde yazalım;
[ApiController]
[Route("api/[controller]")]
public class CustomersController : ControllerBase
{
[HttpGet]
public IActionResult Get(){
return Ok(new string[] {"Customer1", "Customer2"});
}
}
servilerimizin çalışacağı portları ayarlamamız gerekmekte, bunu için launchSettings.json, Program.cs veya appsettings.json ile kolayca gerçekleştirebiliriz, örneğimizde launchSettings.json üzerinden ilerleyeceğiz. Customer api için launchSettings.json dosyamızdaki CustomerApi kısmında applicationUrl değişkenimizi şu şekilde düzenleyelim.
"CustomerApi": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:5003;http://localhost:5002",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
Aynı adımları ProductApi servisimiz içinde gerçekleştirdiğimizde launchSettings.json dosyasındaki ProductApi kısmı şöyle gözükecektir.
"ProductApi": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:5005;http://localhost:5004",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
Bu sayede servislerimizi çalıştırdığımızda launchSettings üzerinde belirttiğimiz portlar üzerinden yayın yapacaklar.
Sıra geldi Ocelot için gerekli konfigürasyonları OcelotGateway projesi üzerinde gerçekleştirmeye, öncelikle projemize Ocelot paketini package manager yardımıyla dahil edelim.
Install-Package Ocelot -Version 16.0.0
Startup.cs içinde configure metodu içinde konfigurasyonu gerçekleştirelim. (burada Ocelot asenkron olarak çalışacak şekilde, Configure metodu asenkron yapılabilir veya app.UseOcelot.Wait(); şeklinde kullanabiliriz. Kullanım ihtiyacına göre her iki yapılandırmayıda kullanmak mümkündür.)
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
...
...
// app.UseOcelot().Wait(); // waitable or await like after this
await app.UseOcelot();
}
OcelotGateway katmanımızın çalışacağı portu launchSettings.json içinden değiştirelim;
"OcelotGateway": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
tüm bunlardan sonra asıl Gateway konfigürasyonlarını yapacağımız kısma geçebiliriz, bunun için OcelotGateway projemizin ana dizininde ocelot.json adında konfigürasyonlarımızın yer alacağı dosyayı oluşturalım ve şu şekilde gerekli konfigürasyonları gerçekleştirelim.
{
"Routes": [
{
"DownstreamPathTemplate": "/api/customers",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5002
}
],
"UpstreamPathTemplate": "/customers",
"UpstreamHttpMethod": [ "Get" ]
},
{
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5004
}
],
"UpstreamPathTemplate": "/{url}",
"UpstreamHttpMethod": [ "Get" ]
},
{
"DownstreamPathTemplate": "/api/products",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5004
}
],
"UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": [ "Get" ]
},
{
"DownstreamPathTemplate": "/api/products/{id}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5004
}
],
"UpstreamPathTemplate": "/products/{id}",
"UpstreamHttpMethod": [ "Get" ],
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "1m",
"PeriodTimespan": 60,
"Limit": 10
}
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:5000"
}
}
ocelot.json dosyasındaki konfigürasyonları açıklayacak olursak;
DownstreamPathTemplate: mikroservisimizin endpointini ifade eder.
DownstreamScheme: isteklerin http şemaları üzerinden gerçekleşeceğini ifade eder.
DownstreamHostAndPorts: mikroservisimizin yayın yaptığı ve daha önce launchSettings.json üzerinden ayarladığımız port ve host’u ifade eder.
UpstreamPathTemplate: mikroservise giden requestlerin Ocelor üzerinden hangi path çaığırıldığında gerçekleşeceğini ifade eder.
UpStreamHttpMethod: mikroservise giden http isteklerinin türünü belirler.
RateLimitOptions: Rate limiting için Limit, Period, PeriodTimespan gibi konfigürasyonları ve özelleştirmeleri yapabileceğimiz kısımdır.
GlobalConfiguration: Ocelotun global konfigürasyonlarının yapıldığı kısımdır.
{
"DownstreamPathTemplate": "/api/customers",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5002
}
],
"UpstreamPathTemplate": "/customers",
"UpstreamHttpMethod": [ "Get" ]
}
Customer api için bu konfigürasyonu incelediğimizde https://localhost:5002/api/customers CustomerApi endpoitini Ocelot üzerinden https://localhost:5000/customers ile çağırılacağını ifade etmektedir. Ancak konfigürasyonumuzu şu şekilde de gerçekleştirebilirdik.
{
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5002
}
],
"UpstreamPathTemplate": "/{url}",
"UpstreamHttpMethod": [ "Get" ]
}
bu konfigürasyonda görüldüğü üzere DownstreamPathTemplate ve UpstreamPathTemplate {url} değişkenlerini paylaşmaktalar, bu da demek oluyorki; https://localhost:5002/api/customers endpointini çağırmak için ocelot üzerinde https://localhost:5000/api/customers urline gidilmelidir. bu sayede mikroservisteki routing ocelot üzerinde de aynı şekilde map edilmiş oluyor.
{
"DownstreamPathTemplate": "/api/products/{id}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5004
}
],
"UpstreamPathTemplate": "/products/{id}",
"UpstreamHttpMethod": [ "Get" ],
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "1m",
"PeriodTimespan": 60,
"Limit": 10
}
}
mikroservis üzerine url parametrelerini veya querystring göndermek için yukarıdaki konfigürasyonu kullanarak tüm parametreleri geçebilir veya değişken üzerinden ({id}) gibi belirli parametrelerin iletimini belirli bir url üzerinden sağlayabiliriz. Ayrıca ek olarak Ratelimiting için gerekli ayarlamaları gerçekleştirerek whitelist ve blacklist adresleri ekleyebiliriz.
Sonuç olarak github üzerinden paylaştığım projeyi klonlayarak komut satırı üzerinden;
...\OcelotGateway> dotnet run
...\ProductApi> dotnet run
...\CustomerApi> dotnet run
komutlarıyla çalıştırarak yazıda bahsedilen tüm senaryoları deneyebilir ve ocelotun request ve responselar sırasında ürettiği logları inceleyebilirsiniz.
Son olarak api gateway yapısı mikroservis miamarisinde bir çok olanak sağlamasının yanı sıra;
- Client tarafından tüm istekler bir noktaya (api gateway) yapılacağından olası bir kesinti veya aksama durumunda tüm sistemin etkilenebilmesi,
- Api gateway, örnek uygulamada yazdığımız gibi kendi başına(ayrı) bir proje olacağından geliştirme, bakım ve yönetim maliyetlerini birlikte getirmesi,
gibi dezavantaj olarak söz edilebilecek durumlarında olduğundan bahsetmek yerinde olacaktır diye düşünüyorum.
Bir yazının daha sonuna gelmiş bulunuyoruz. Bu yazıda sizlere kısaca mikroservis mimarisindeki api gateway pattern’i ve temel özelliklerini anlatmaya çalıştım, bir sonraki yazıda görüşmek dileğiyle hoşça kalın.
Projenin kaynak kodlarına ve bu yazıyı yazarken yararlandığım kaynaklara aşağıdaki bağlantılardan ulaşabilirsiniz.
Source Code:
Sources:
Be First to Comment