Merhaba,
Bu içeriğimizde web ve mobil uygulamalarında notification sistemleri oluşturmak isteyen geliştiriciler için Amazon tarafından sunulmuş olan SNS(Simple Notification Service) servisini inceleyecek ve bir Asp.NET Core uygulamasında nasıl yapılandırılabileceğini ve bir notification’ın alınabilmesi için nasıl subscribe olunabileceğini vs. pratiksel olarak tecrübe ediyor olacağız. O halde buyurun başlayalım…
Amazon SNS(Simple Notification Service) Nedir?
Amazon SNS, Amazon Web Services(AWS) tarafından sunulan cloud tabanlı ve oldukça hızlı, esnek, tamamen yönetilen bir mesaj yayma servisidir. SNS, pub-sub modelini kullanarak uygulamalar arasında yahut uygulamalardan kullanıcılara bildirim gönderilmesini sağlamakta ve bu niteliğinden dolayı özellikle distributed sistemlerde ve microservice yapılanmalarda tercih edilmektedir.
Amazon SNS; mobil cihazlar, e-posta, SMS, HTTPS endpoint’leri ve diğer AWS servisleri gibi farklı kanallara bildirim göndermek amacıyla tercih edilmekte ve ayrıca sistem olaylarına yanıt olarak otomatik bildirimler üretebilmektedir. Misal olarak bir uygulama hatası meydana geldiği taktirde geliştiriciye uyarı gönderebilmekte ve böylece önemli durumlara karşın hazır kıta olunabilmesini ve anlık reaksiyon alınabilmesini sağlamaktadır. Tüm bunların dışında farklı sistemler, diller veya teknolojiler arasında hızlı ve güvenilir mesajlaşma sağlayabilmektedir.
SNS’in en önemli özelliği hızlı bir şekilde ölçeklendirilebiliyor olmasıdır.
Bizler Amazon SNS’i genellikle; kullanıcılara uygulamada gerçekleşen önemli olaylar için bildirim gönderme maksatlı kullanmaktayız. Bunun dışında uygulamaya dair güncellemeler, promosyonlar veya haberler hakkında da bildirimler gönderirken yahut uygulamanın veya sistem olaylarının izlenme sürecinde olası kritik durumlara karşın notification verirken tercih etmekteyiz.
Kısaca Amazon SNS; pub/sub modelini uygulamakta, mesajları çeşitli hedeflere yönlendirebilmekte, IOS, Android ve diğer platformlar için bildirimleri desteklemekte ve kullandıkça öde modeli ile maliyetlendirilmektedir.
Amazon SQS İle SNS’in Farkları Nelerdir?
Amazon SQS ile SNS, farklı kullanım senaryolarına yönelik olarak tasarlanmış olan AWS mesajlaşma servisleridirler. Temel farkları ve kullanım senaryolarındaki ayrışmaları aşağıdaki tablo üzerinden net bir şekilde ortaya koyalım;
| Özellik | Amazon SNS | Amazon SQS |
|---|---|---|
| Mesajlaşma Modeli | Publish Subscribe | Queue Based(Kuyruk Temelli) |
| Mesaj Dağıtımı | Bir mesaj birçok aboneye dağıtılmaktadır. | Bir mesaj yalnızca bir tüketici tarafından işlenmektedir. |
| Kullanıcılar | Abonelerdir(subscriber) ve birden fazla abone olabilir. | Tüketicilerdir(consumer) ve yalnızca bir tane olabilir. Kuyruk yahut mesaj tüketicisi de denebilir. |
| Teslimat Yöntemi | Mesaj aboneye aktif olarak gönderilir. Push |
Tüketici mesajı kuyruktan iradesiyle çeker. Pull |
| Mesaj Yönlendirme | HTTP(S), Lambda, SQS, e-posta, SMS | Yalnızca kuyruktaki tüketicilere. |
| Kullanım Amacı | Yayınlanan mesajların birden çok hedefe bildirim mahiyetinde iletilmesidir. | Bir kuyruk üzerindeki mesajların sıralı bir şekilde tüketici tarafından işlenmesidir. |
| Mesaj Sırası | FIFO(First-In-First-Out) | FIFO(First-In-First-Out) ve Standart kuyruk seçenekleri mevcuttur. |
| Zaman Aşımı & Saklama | Mesajlar anlık olarak iletilir. Saklanmazlar! | Mesaj belirli bir süre(1dk ile 14 güne kadar) kuyrukta bekletilebilir. |
| Başka AWS Servisleriyle Entegrasyon | Lambda, HTTP(S), e-posta, SMS, SQS ile entegrasyon mümkündür. | Lambda ve diğer tüketicilerle entegrasyon mümkündür. |
Anlayacağınız; SNS, pub-sub modeliyle çalışmakta ve bir olay gerçekleştiğinde mesaj yayınlayarak subscribe olan tüm uygulamalara göndermektedir. SQS ise kuyruk tabanlı bir mesajlaşma sistemidir ve mesajları sırayla kuyruğa atarak ve bir tüketici tarafından bu mesajlar kuyruktan tek tek alınarak işlenmektedir.
| Amazon SNS Örnek Senaryo | Amazon SQS Örnek Senaryo |
|---|---|
| E-ticaret uygulamasında bir sipariş verildiğinde, bu sipariş bilgisi SNS ile yayımlanarak envanter yönetim sistemine, müşteriye ve ilgili diğer departmanlara SMS ile bildirim gönderir. | Bir online video platformunda kullanıcı bir video yüklediğinde, bu video işlem kuyruğuna eklenir ve işlemci sırayla her videoyu işleyip yayınlar. Yükleme talepleri hızlıca kuyrukta toplanırken, işleme işlemi doğal olarak daha yavaş bir hızda ilerleyecektir. |
İşte bu yapılarından dolayı SNS ve SQS sıklıkla birlikte kullanılmakta ve esasında davranışsal açıdan birbirlerini tamamlayarak bir bütün arz etmektedirler. SNS ile olaylar yayılırken, bu yaygın mesajların SQS kuyruklarına yönlendirilerek bekletilebilmesi ve gerektiğinde sıralı bir şekilde işlenebilmesi mümkündür. Bunu şöyle bir örnek üzerinden daha da somutlaştırabiliriz; bir sipariş verildiğinde SNS, hem muhasebe hem de envanter sistemine bir mesaj gönderecektir. Diyelim ki, muhasebe sistemi işlemi hemen/anında işleyebiliyor olsun amma velakin envanter sistemi aşırı yoğun olduğundan dolayı işlenme sürecinin yavaş ilerlediğini düşünelim. İşte bu durumda envanter sisteminde mesajları kuyruğa atmamız ve yoğunluğa göre işlememiz gerekecektir. İşte tam da burada SNS ile SQS’in kümülatif kullanılması gerecektir.
Amazon SNS, bir olay gerçekleştiğinde yayınlayacağı mesajı Fanout Exchange‘i kullanarak tüm subscriber’lara iletecektir. Haliyle bu bir push mekanizmasıdır ve yeni mesajlar yayınlanır yayınlanmaz abonelere otomatik olarak iletilecektir. Oysa SQS pull tabanlı bir servistir ve bu da, mesajları işlemeye hazır olduklarında kuyruktan alacakları anlamına gelecektir. Yukarıdaki satırlarda da ifade etmeye çalıştığımız üzere SQS kuyrukları, bir tüketici tarafından işlenene kadar mesajları depolamak için kullanılmaktadır. Lakin SNS’in tabiatı gereği mesaj depolama durumu söz konusu değildir.
SNS realtime mesajlaşma için, SQS ise asenkron mesajlaşma için tasarlanmıştır. O yüzden mesaj teslimatı SNS’de anında olmalıyken, SQS’de ise gecikmeli olabilmektedir.
Amazon SNS – Publisher-Subscriber Architecture
Distributed sistemlerde oldukça önemli bir iletişim modeli olan Publisher-Subscriber Architecture Amazon SNS’de aşağıdaki diyagramda olduğu gibi işlem akışına sahiptir;
Amazon SNS Topic Oluşturma
Evet, artık sıranın her zaman olduğu gibi pratiksel incelemeye geldiğini söyleyebiliriz. Şimdi ilk olarak AWS’de SNS servisine erişelim ve bir topic’in nasıl oluşturulduğunu inceleyelim. Bunun için Amazon Management Console üzerinden aşağıdaki gibi SNS servisini aramamız yeterli olacaktır.
Sayfayı biraz aşağıya indirdiğimizde SNS’in topic mesajları için sağladığı güvenlik katmanı olan ‘Encryption’ yapılandırmasını göreceksiniz. Devamında ise varsayılan değerleri koruyacak erişim politikalarına ya da veri güvenliğine dair ayarları.
Asp.NET Core – SNS Topic’ine Mesaj Yayınlama(Publishing)
Evet, şimdide olayı pratiksel olarak bir örnek üzerinden seyrediyor olacağız. Haliyle bir mesaj yayıncısı olarak hareket edecek ve subscriber’lara SNS mesajlarını gönderecek olan Asp.NET Core uygulaması oluşturacağız. Bunun için ilgili uygulamaya aşağıdaki kütüphanelerin yüklenmesi gerekmektedir.
Install-Package AWSSDK.SimpleNotificationService
Install-Package AWSSDK.Extensions.NETCore.Setup
Kütüphanelerin yüklenmesinin ardından uygulamaya aşağıdaki gibi gerekli servisleri yükleyelim.
. . . builder.Services.AddDefaultAWSOptions(builder.Configuration.GetAWSOptions()); builder.Services.AddAWSService<IAmazonSimpleNotificationService>();
Burada opsiyonel bir şekilde uygulamanın appsettings.json dosyasında aşağıdaki gibi profile ve region bilgilerini tanımlayabiliriz.
"AWS": {
"Profile": "default",
"Region": "ap-south-1"
}
Ben önceki AWS içeriklerimde olduğu gibi development makinemi AWS CLI Profile’ını kullanarak authentication yapacak şekilde yapılandırdığım için bu kısımları es geçiyorum.
Evet, altyapıyı kurduğumuza göre artık notification mesajımızı tasarlayabiliriz. Bunun için aşağıdaki gibi bir ürünün oluşturulmasını abonelere duyuracak bir senaryo üzerinde hareket edelim istiyorum ve bu minvalde ‘ProductCreatedNotification’ sınıfını tasarlıyorum.
public interface INotification
{
}
public sealed record ProductCreatedNotification(int Id, string Name, string Description) : INotification
{
}
Artık tüm temel kurulumu tamamladığımıza göre publisher’ımızın bir mesajı publish etmesini sağlayacak endpoint’i oluşturalım.
.
.
.
var app = builder.Build();
const string topicName = "product-topic";
app.MapPost("/create-product", async (CreateProductRequest createProductRequest, IAmazonSimpleNotificationService snsService) =>
{
ProductCreatedNotification productCreatedNotification = new(
createProductRequest.Id,
createProductRequest.Name,
createProductRequest.Description);
//Topic Arn, SNS Topic'inin benzersiz kimliğine karşılık gelmektedir.
string topicArn = string.Empty;
//Topic elde ediliyor.
Topic topic = await snsService.FindTopicAsync(topicName);
//Topic var mı yok mu kontrol ediliyor.
if (topic is null)
{
//Topic yoksa oluşturuluyor.
CreateTopicResponse createTopicResponse = await snsService.CreateTopicAsync(topicName);
//Oluşturulan topic'in id'si elde ediliyor.
topicArn = createTopicResponse.TopicArn;
}
else
//Topic varsa id'si elde ediliyor.
topicArn = topic.TopicArn;
//Mesaj publish'i oluşturuluyor.
PublishRequest publishRequest = new()
{
TopicArn = topicArn,
Message = JsonSerializer.Serialize(productCreatedNotification),
Subject = nameof(ProductCreatedNotification)
};
//Mesaj publish ediliyor.
await snsService.PublishAsync(publishRequest);
});
.
.
.
Yukarıdaki çalışmaya göz atarsanız eğer /create-product endpoint’ine gelen istek neticesinde ‘CreateProductRequest’ içerisindeki verilere karşılık bir ürünün oluşturulduğunu varsayarak Amazon SNS notification çalışması gerçekleştirmiş bulunuyoruz. Burada dikkat edilmesi gereken husus, mesajın yayınlanacağı topic’e dair kontrollü bir şekilde davranışın şekillendirilmesidir. Eğer topic varsa id’sini alıyoruz, yoksa da oluşturup ardından id’sini elde ediyoruz. Burada bir topic’in id’sinden kastedilenin TopicArn olduğu aşikar. Zaten örnek kod bloğunda da gerekli açıklamayı yaptığımızı görüyorsunuz. Evet, bizlerin Amazon SNS’de belirli bir topic üzerinden mesaj yayınlayabilmesi için ilgili topic’in id’si olan TopicArn değerine ihtiyacımız vardır. Dolayısıyla bu değeri elde ettikten sonra mesajımıza karşılık gelen ‘ProductCreatedNotification’ türünden oluşturulan instance’ı serialize edip ‘PublishRequest’ nesnesine TopicArn değeri ile birlikte vererek mesajı yayınlıyoruz.
Şimdi bu çalışma neticesinde uygulamayı derleyip çalıştıralım ve Postman üzerinden aşağıdaki test isteğinde bulunalım.
{
"id": 1,
"name": "Kitap",
"description": "Okumalık"
}
E-Posta Aboneliği Tasarlayalım
Amazon SNS, yayınlanmış olan mesajların bir kopyasını bizlere mail olarak gönderebilmektedir. Bunu deneyimlemek ve sistemin çalışıp çalışmadığını test edebilmek için Gmail üzerinden mevcut bir e-posta hesabını kullanalım. Tabi bunun için öncelikle Amazon SNS’in Subscriptions sekmesine gelip aşağıdaki gibi oluşturduğumuz ‘product-topic’i dinleyecek olan bir abone oluşturalım.
Haliyle yukarıdaki satırlarda Postman üzerinden yapılan isteği tekrar yapalım ve abone olarak belirtilen e-posta’nın posta kutusunu gözlemlemeye başlayalım. (Beklenen mailler spam’e düşebilir)
Lambda Aboneliği Tasarlayalım
Şimdide AWS Lambda üzerinden SNS topic’imize bir abonelik oluşturalım. Tabi şu ana kadar AWS Lambda’ya dair bir tecrübeniz yoksa öncelikle aşağıda referans edilen makaleleri okumanızı tavsiye ederim;
- .NET 7 – AWS Lambda İle Serverless Computing
- .NET – Lambda Authorizer İle Amazon API Gateway’in Güvenliğini Sağlama
- AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)
Şimdi Visual Studio üzerinden aşağıdaki gibi Simple SNS Function template’inde bir Lambda projesi oluşturalım.
private async Task ProcessRecordAsync(SNSEvent.SNSRecord record, ILambdaContext context)
{
context.Logger.LogInformation($"Processed record Subject : {record.Sns.Message} | Message : {record.Sns.Message}");
// TODO: Do interesting work based on the new message
await Task.CompletedTask;
}
Tabi AWS’de log demek CloudWatch‘a kayıt demektir. Haliyle buradaki tetiklenmeyi oradan takip edeceğiz. Şimdi oluşturduğumuz bu Lambda’yı AWS’ye publish edelim.AdministratorAccess‘in atandığından emin olunmalıdır. Ayrıca seçilen rolünde CloudWatch erişimi olduğundan da emin olunmalı.
Unutmayın! Lambda function üzerinden CloudWatch’a bir log atılabilmesi için ‘CloudWatchLambdaInsightsExecutionRolePolicy’ ve ‘CloudWatchLogsFullAccess’ rollerinin lambda’yla ilişkilendirilmiş olması gerekmektedir.
Amazon SNS – Filter Policy
Amazon SNS’de yayınlanmış olan mesajlar varsayılan olarak tanımlanmış olan tüm subscriber’lara gönderilecektir. Bizler istersek bu mesajları subscriber seviyesinde filtreleyebilir ve istediğimiz abonelerde istediğimiz mesajları elde edebiliriz. Bunun için oluşturduğumuz SNS publisher servisimizin mesaj yayınlama kodunda aşağıdaki gibi küçük bir eklemenin yapılması yeterlidir.
.
.
.
PublishRequest publishRequest = new()
{
TopicArn = topicArn,
Message = JsonSerializer.Serialize(productCreatedNotification),
Subject = nameof(ProductCreatedNotification)
};
#region SNS Filter Policy
publishRequest.MessageAttributes.Add("Scope", new MessageAttributeValue
{
DataType = "String",
StringValue = "Email"
});
#endregion
await snsService.PublishAsync(publishRequest);
.
.
.
Dikkat ederseniz gönderilecek mesaja dair esasında bir scope belirlemekteyiz. Bu scope üzerinden aboneleri ilişkilendirerek gerekli mesaj filtrelemesini gerçekleştireceğiz. Yayınlanacak mesajın hangi servise gönderileceğini belirleyebilmek için Amazon SNS topic’ine subscribe olmuş olan servislerden istediğinize aşağıdaki gibi filter policy olarak eklemeniz yeterli olacaktır. Bunun için ekran görüntüsünde olduğu gibi SNS topic’i üzerinden ‘Subscriptions’ sekmesine ve oradan da ilgili subscriber’a tıklanmalı ve açılan sayfada ‘Subscription filter policy’ kategorisindeki ‘Edit’ butonuna tıklayarak ‘Subscription filter policy’ alanından istenilen mesaj filtrelemesi gerçekleştirilmelidir.
Retries
Amazon SNS, abonelere mesaj gönderilmesinde bir sorun olduğu taktirde otomatik olarak yeniden deneyecektir. Hatta hatırlarsanız eğer içeriğimizin ilk satırlarında teslimat politikaları(delivery policy)ndan bahsetmiştik. Eğer ki bir SNS topic’inin teslimat politikalarını gözlemlemek isterseniz buna ilgili topic’in aşağıdaki görselde olduğu gibi ‘Delivery Policy (HTTP/S)’ sekmesinden erişebilirsiniz.
Amazon SNS – Dead Letter Queues
Dead Letter Queues, Amazon SNS’de abonelere teslim edilemeyen mesajların tutulabilmesi için geliştirilmiş bir SQS kuyruk yapısıdır. DLQ’nun kurulabilmesi için yapılması gereken Amazon SQS üzerinden aşağıdaki gibi bir kuyruk oluşturmaktır.
.
.
.
{
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:ap-south-1:905418427199:product-dead-letter-queue",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:sns:ap-south-1:905418427199:product-topic"
}
}
.
.
.
Ve bu politikayı ilgili kuyruğu editleyerek ‘Access policy’ kısmından aşağıdaki gibi verebiliriz;
{
"Version": "2012-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Sid": "__owner_statement",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::905418427199:root"
},
"Action": "SQS:*",
"Resource": "arn:aws:sqs:ap-south-1:905418427199:product-dead-letter-queue"
},
{
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:ap-south-1:905418427199:product-dead-letter-queue",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:sns:ap-south-1:905418427199:product-topic"
}
}
}
]
}
Dikkat ederseniz ilk statement default olarak gelirken, ikincisi bizim oluşturduğumuz politikaya karşılık gelmektedir. Artık SNS topic’inden lambda servisine mesaj gönderme sürecinde herhangi bir kusur meydana gelirse bu DLQ kuyruğuna gönderilebilecektir.
Nihai Olarak…
Özellikle anlık haberleşme sağlayacak olan yazılımlar için oldukça kritik ve önem arz eden Amazon SNS servisini oldukça detaylı ve kapsamlı bir şekilde incelemiş ve kısmen deneyimlemiş bulunuyoruz. SQS ve SNS’e dair burada son kez vurgulanması gereken nüansa özet mahiyetinde temas edip içeriğimizi noktalamak istiyorum.
Amazon SQS’de consomer kuyruktaki mesajları iradesiyle çekerken, Amazon SNS’de subscriber’lara mesajlar direkt gönderilir/eriştirilir. İşte bundan dolayı Amazon SQS bir kuyruk yapısıyken, Amazon SNS daha çok bir anında bildirim yapısı(yani notification) sistemidir.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…
Not : Örnek çalışmaya aşağıdaki github adresinden erişebilirsiniz.
https://github.com/gncyyldz/AmazonSNS.Example
