Nginx Rate Limiting Explained With Animated Gifs

One of the best features of Nginx is Rate Limiting. It helps us to prevent some attacks that aims to make our system unresponsive. Despite Nginx has a few parameters to set for rate limiting, it can be misconfigured easily. In this post, I will try to explain these options with animated gifs, and hopefully, you will have no doubts about these settings. If you want to have a background, you can read their blog post here.

Before starting, I need to tell that Nginx tracks requests at millisecond granularity, so when you define a limit like 2r/s (two requests per second), It will be 1 request per 500 ms on Nginx side.

Let’s start talking about settings.

Defining just rate limit

I will use rate 2r/s for the sake of simplicity. In this case, only one request will be forwarded in 500ms intervals by nginx. If there are more requests in this interval they will be rejected.

nginx rate limiting

Let’s make things a bit complicated 🙂

Rate limit with a burst

Sometimes It may be a bad idea rejecting all concurrent requests. We may want to create some buffer to allow getting more requests than rate limit. In this case, we need to set burst variable in our settings. Let me show you how 2r/s burst = 5 setting runs. You can think burst = 5 will create a 5 items length queue for us.

In this example we will send 7 concurrent requests first, then we will send 3 additional concurrent requests.

nginx rate limitin burst

Rate limit with a burst and nodelay

Burst option is great for making our application more responsive but it will also make it slow. Because user will need to wait requests in queue to be completed. We can solve this problem by providing nodelay keyword. With this keyword, in queue one slot will be kept for each request but different than previous sample, requests will be forwarded immediately. In this sample, again, we will send 7 concurrent requests first then 3 additional concurrent requests.

2rs burst 5 nodelay

2 stage rate limiting

We have one more very helpful option to set. 2 stage rate limiting helps us getting first requests without rejecting and applying rate limit consecutive request. This time we will provide delay = 3 setting with a burst = 5. You can think this setting as give me a queue with a 5 length but have no delay first 3 requests. After first concurrent requests, all consecutive requests will be delayed to fit rate limit we defined.

nginx rate limiting burst delay

I hope this post helps you to understand nginx rate limiting better and make your applications more robust and responsive : )

ASP.Net Core, Cookie Expiration and Mysterious Logout on IIS

Working with cookie expirations on Asp.Net Core may be a bit confusing. Although settings are simple, varierity of settings can mislead you.

IsPersistent

First setting I want to mention is IsPersistent. When it is set to true, It will be kept even if browser closed (persistent cookie). As opposite when it is set to false, cookie will be cleared when the browser is closed. (session cookie)

ExpireTimeSpan

This settings helps us to set expiration date of the ticket stored in cookie. For example, the setting below will make the ticket in the cookie invalid after 15 mins.

options.ExpireTimeSpan = TimeSpan.FromMinutes(15);

SlidingExpiration

Sometimes we want to extend expire timespan if client uses the application actively. With this setting, It will be reset expiration time if client make a request after more than half of the expiretimespan interval passed.

If a browser send a request with a cookie that has expired ticket, server will ignore it.

ExpiresUtc

ExpiresUtc setting helps you to set an absolute expiration to cookie. This settings overrides ExpireTimeSpan setting value. This setting will also ignore SlidingExpirationSetting.

ExpiresUtc = DateTime.UtcNow.AddMinutes(20)

Another important point is that when you set ExpiresUtc, If you don’t set IsPersistent setting, cookie will be created as session cookie.

Mysterious Logout on IIS Server

Despite all of these settings you may experience that users are loging out after some minutes eg 20mins. Most probably you will not catch this behaviour on local while developing your application. It is related with some settings on IIS.

To fix this behaviour, first you need to go to advanced settings of application pool.  You will see a setting called “Idle Time-out (minutes)” and must set as 0. Its default value is 20mins. It means that if no new request comes for 20 mins, worker process will be shut down.

When an app restarted or worker process restarted and If the keys related with authentication kept in memory;

Cookie based authentication tokens will be invalid and users will need to log in again.

So to keep keys persistent, we need to set one more setting on advanced settings of Application Pool; Load User Profile must be set to True. So keys will be stored in a folder on operation system. (%LOCALAPPDATA%/ASP.NET/DataProtection-Keys)

Sources: https://docs.microsoft.com/en-au/aspnet/core/host-and-deploy/iis/?view=aspnetcore-3.1

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-3.0#absolute-cookie-expiration

 

Sharing sessions between subdomains – Asp.Net Mvc Apps on IIS

Sometimes, you need to share sessions between different apps on different sub domains. There are some steps to achieve this behaviour and I will try to explain them today.

If we want apps to behave like single app on different subdomains, firstly they must use same cookies. With shared cookies, users won’t have to logged in for each app. They will be able to logged in / out only once for all apps.  In order to share cookies we need to add a setting under system.web section in webconfig for cookies:

<httpCookies domain=".yourmaindomain.com"/>

With this setting, any subdomain under yourmaindomain.com use the same cookies. But there is one more step here, all apps have to same machinekey setting on webconfig. Machinekey attribute is used while encrypting and decrypting the data for the webapplication in ASP.NET.

Before move further, Lets create two websites on our web server.

iis create web site

After creating two websites, for one, select MachineKey feature and click Generate Keys. Copy Validation Key and Decryption Key. Then open other app’s Machine Key feature and paste copied values to related fields.

These values will be pasted to a web config attribute too.

<machineKey validationKey="XXXXX" decryptionKey="XXXXX" validation="SHA1" decryption="AES" />

This attribute will be under system.web section in webconfig.

These changes helps us to use shared cookies without any problem. But to achieve our goal completely, we need to do one more thing. We have to store session state in database, so all applications will share same session data. By adding setting below to web config and editing to connection string, all session data will be shared.

<sessionState 
            mode="SQLServer"
            sqlConnectionString="data source=127.0.0.1;user id=username;password=strongpassword"
            cookieless="false" 
            timeout="20"/>

 

Elasticsearch Refresh API vs Flush API

Refresh api and flush api may seem producing same results, but they have differences about performance and persistency.

As we talked in the previous post, each elasticsearch shard is a Lucene index. To understand refresh api and flush api in elasticsearch, we need to talk about two lucene command, reopen and commit.

Reopen command, like its name refer, re open an index when it is called. After indexing some documents by calling reopen command, you can make documents searchable. This command creates a new segment in memory and write documents from memory buffer into new segment. But still these operations are done in memory. Documents will be lost if some problems occurs in server.

Commit command, on the other hand, merges documents from different segments and write them into the disk. So, documents become persistent. But these operations are source consuming and expensive.

Elasticsearch Refresh API calls lucene’s reopen command and makes documents searchable. Refresh api call creates new segments because of lucene nature.

Like we mentioned above, refresh api call is a reopen operation and it is in memory. Data will be lost on server failures. To prevent this, elasticsearch writes data into translog (one translog per shard) at the same time with writing into memory buffer. Translog datas are fsynced to disk. So they provide persistency even if documents disappear in memory.

With some intervals or if translog file is big enough, data  on the the translog committed to lucene index and becomes persistent. Implicitly, flush api is called and a commit is done. You can call flush api to make a lucene commit explicitly.

In short, refresh api just makes documents searchable in memory. But flush api makes lucene commit and make documents persistent. Flush api must be called carefully because of its expensive operations.

 

Elasticsearch Basics

Last time I was working with Elasticsearch, I thought that writing a post about refresh api usage on bulk operations may help newcomers. But then I realized that it is better to explain elasticsearch api basics and refresh api first.

In this post I will talk about Elasticsearch basics.

Elasticsearch, with the words of itself, is a distributed, RESTful search and analytics engine. It is built on Apache Lucene. Apache Lucene creates and manages inverted indexes and Elasticsearch gets its power from searching indexes instead of searching texts. Inverted indexes keep a list of all unique words in a document and for each word, list of the documents that contains this word.

Elasticsearch is near real time search platform. After you add some documents to an index, it will be ready for search in seconds. (1 second in default).

To understand Elasticsearch structure well, we can compare the terms with RDMS terms.

ES RDMS
Index Table
Document Row
Field Column

At the past, It is told that  ES Type is similar to RDMS Table and ES Index is similar to RDMS Database. But Types are removed in new versions of Elasticsearch.

Personally, I am adding prefixes to Index Names and these prefixes provide me a logical database.

New records in Elasticsearch is called Document and storing new document is called Indexing. Indexes contains one or more Documents and Documents contains one or more Fields.

When you insert a new document, it is firstly added to a memory buffer and Translog. At this level, new documents are not be able to search and it is just in memory. Translog (transaction log) helps elasticsearch to recover datas that has not committed yet and exists in memory in case of crash.

The reason that why Lucene commit is not used instead of Translog is Lucene commits are heavy operations and doing Lucene commit after every document insert/delete/update will decrease performance of the app drastically. To prevent this performance decrease, first data written to Translog and fsynced to Translog with some interval or after requests. These can be changed by settings.

Translog file datas are committed with some intervals to Lucene. So to big translog files are prevented and new translog is created. Commit to Lucene operation can be done with Flush API, we will talk about it in the next post.

translog

 

After the first refresh request to Index (We will talk about fresh api in the next post too), documents that is in Memory Buffer,copied to a new segment in memory again. From now on, documents are searchable.

segment

We will talk about persistence problem, refresh api and flush api in the next post.

Let’s continue with Elasticsearch architecture a bit more.

Elasticsearch can be scaled horizontally by adding new nodes to clusters. A cluster is group of servers that keep your data. It organizes your indexing and searching operations between nodes.

As we talked just before, a node is a server as a part of cluster and it joins the searching and indexing operations. You can add any number of nodes to a cluster.

Shards

An elasticsearch index is comprised of shards. A shard is a lucene index and it cannot be breakable. If you have only one shard in your elasticsearch index and your data is too much for your server capacity, It will  cause problems. Shards can be hosted different nodes so you can separate your elastic search indexes to different nodes. Pros of shards:

  • Split content into different nodes
  • Scale horizontally
  • Improve performance

Segments

Shards contain segments that are actualy data structures with inverted indexes. Datas are kept in segments. Every indexing operation creates new segments. These segments are searched sequentially. Therefore, If there are too many segments it will decrease the performence. To prevent this, elasticsearch merges similar size segments into bigger segments. This merge operation is done by some cpu and i/o operations that effects bulk indexing operation’s performance. To prevent this, it is a good advice disabling merges before bulk operations.

Segments are immutable, so if you update a document, it is marked as deleted and new document is created. Documents that is marked as deleted, is deleted completely by merge operations.

Replicas

Replicas are copy of primary shards but still shards. They are not stored in the same nodes with primary shards. So, they provide that if some server failures or connection problems occur, elasticsearch continues to response requests over replicas.

In first time bulk indexing, setting number of replicas to 0 will improve performance but you may loose your data if some server failure occurs while indexing. After the bulk operation completed. You can set the number of replicas whatever you want.

In this post, I tried to make a introduction Elasticsearch world, If you have any comment or questions, please share below. I will talk about refresh api and flush api in my next post.

Thanks 🙂

Content Language Of the Blog

Hi all,

After a long time silence, I am here again 🙂 But with a small difference. From now on, I have decided to post in English. Because the past blogs are my history and I think that they will be helpful for some new programmers out there, I won’t delete or hide them. Maybe I will translate them into English in the future.

But that’s all for now.

 

Yazılım Geliştirmeyi Nasıl Öğrenirim?

savasci

Gerek e-posta ile gerekse sosyal medya üzerinden gelen sorulardan bir tanesi “Yazılım geliştirmeyi nasıl öğrenirim?” ya da bir başka deyişle “Nasıl iyi yazılımcı olurum?”. Ünlü olmadığımdan olsa gerek arada geliyor sorular 🙂 Ama çok sorulan bir soru olduğunu düşünüyorum. Ben de bakış açım doğrultusunda açıklamaya çalışayım.

Bir metafor kullanarak daha iyi açıklayabileceğimi düşünüyorum. Öncelikle Orta Çağ’da yaşayan bir genç olduğunuzu düşünün. Tek hayaliniz iyi bir savaşçı olmak. Ve savaşçı olmanız için de ilk olarak silahınızı seçmelisiniz. Silahınız sizin arkadaşınız olacak, düşmanlarınızı alt etmeniz için ona ihtiyacınız var. Onun her özelliğini tam olarak kavramalı, öğrenmelisiniz. İleride savaş alanında hiç önemsemediğiniz bir özelliği hayatınızı kurtarabilir.

Silahınızı tam anlamıyla tanıdıktan sonra, küçük alıştırmalar yapmaya başlayabilirsiniz. Ama tabii ki bu alıştırmaları savaş alanında ya da gerçek insanlara karşı yapmayacaksınız. Tahta bir hedef ya da bir korkuluk kullanabilirsiniz. Bu sırada diğer savaşçılar sizin hatalarınıza yada yapamadıklarınıza gülebilirler. Kulaklarınızı bu seslere tıkamalısınız. Unutmayın hiç kimse iyi bir savaşçı olarak doğmadı.

Artık silahınızı tanıyorsunuz ve tahta hedeflerle uzun süre çalıştınız. Savaş eğer tahta hedeflerle yapılsaydı belki de en iyi savaşçı siz olacaktınız. Hatta öyle ki, gerçek savaşçılara karşı bile çok iyi savaşabileceğinizi düşünüyorsunuz. İşte tam bu sırada kendinize yanında çalışmak için iyi bir savaşçı bulmalısınız. İyi ya da kötü her savaşçıdan bir şeyler öğrenirsiniz ama ne kadar çetin bir savaşa çıkacağınızı bilemezsiniz, o yüzden imkanınız varsa iyi bir savaşçı bulun. Onun stratejilerini, neyi neden yaptığını takip edin, sorgulayın, öğrenin. Sürekli nasıl ve neden sorularını sorun. Var olan bu stratejilere kendi yorumlarınızı katmaya çalışın. Artık gerçek hedeflerle alıştırma yapıyorsunuz ve savaşlarda küçük de olsa sizin de katkınız oluyor.

Bu savaşlarda yaptığınız işler dikkat çekmeye başladı. Artık daha büyük görevler almaya hatta küçük birlikleri yönetmeye başladınız. Tebrikler, artık siz de bir savaşçısınız. Ama asla unutmamanız gereken bir nokta var. Son katıldığınız savaştaki kadar iyisiniz. Sürekli alıştırmalar yapmaya, yeni stratejiler öğrenmeye devam etmelisiniz. İyi bir savaşçı olarak kalmanın tek yolu, çalışmaya devam etmektir. Eğer silahınızı değiştirmek isterseniz, yeni silahınızın özelliklerini öğrenmeniz çoğu zaman yeterli olacaktır. Sonrasında stratejilerinizi, taktiklerinizi yeni silahınızla kullanmaya devam edebilirsiniz.

Her adım uzun zaman alacaktır ama sonunda istediğiniz gibi iyi bir savaşçı olacaksınız.

Tıpkı bu savaşçı gibi, yazılımcı olmak isteyen birisi de öncelikle kullanmak istediği dili seçmelidir ve bu dilin özelliklerini kavramalıdır. Sonrasında uzun süre alıştırmalar yapmalı, ticari olmayan projeler geliştirmeli. Yazılım geliştirme pratiğini ilerletmelidir.

Artık bir sonraki aşamaya geçebilir. Tecrübesiz bir arkadaş iş arıyorsa benim önerim küçük veya orta ölçekli şirketlere başvurması ya da büyük şirketin yazılım geliştirme konusunda kendisine faydalı olacağına ikna olması. Evet tecrübesiz olmanız sizi çok zorlayacaktır ama gerçekten isteğinizi, yaptığınız çalışmaları – projeleri gösterirseniz şu günlerde iş bulabileceğinizi düşünüyorum. Zor ya da kolay.

Asıl çalışma ise işi bulduktan sonra başlıyor. İş yerinizdeki tecrübeli yazılımcıları, neyi neden yaptıklarını takip etmelisiniz. Bu ‘eski’ çalışanların yöntemlerini yanlış buluyorsunuzdur belki de ama onlar sizden çok daha fazla hata çözdü, çok daha fazla algoritma kurdu ve çok daha fazla çözüm geliştirdi. O yüzden onların söylediklerini dikkate alın ama önerilerinizi söylemekten de çekinmeyin. Unutmayın kimse mükemmel değildir.

Bundan sonrası size kalıyor, her gün kendinizi geliştirmeli yeni teknolojiler öğrenmeli ve çalışmaya devam etmelisiniz. Unutmayın son yazdığınız kod kadar iyisiniz.

Faydalı olması dileğiyle 🙂

 

 

 

 

 

 

WCF Bindings

Daha önce de karşıma çıkan wcf binding seçimi ile ilgili bir görsel bu. Arşiv olması ve en azından fikir vermesi açısından paylaşmak istedim.

choosebindings

Yabancılarla Konuşma! – Law Of Demeter

strangerdangerNesne yönelimli programlamanın kıyısından köşesinden bir ilişkiniz olduysa eğer encapsulation, abstraction, loosely coupling gibi terimleri duymuşsunuzdur. Bu terimler aslında kolay gibi gözüken ama gerçekleştirmesi, özellikle kodlar ve istekler büyüdükçe, o kadar da kolay olmayan şeylerden bahsederler.

Bugün bunların gerçekleştirilmesinde bize yardımcı olan, kimilerine göre bir pattern kimilerine göre bir pratik olan Law of Demeter’dan (LoD) bahsedeceğim. Özetle LoD başlıkta belirttiğim gibi “Yabancılarla Konuşma!” der.  Bu pratiğe göre bir nesneye ait metod aşağıdaki dört şekilde metod çağırmaldır.

  1. Nesnenin kendisine ait metodlar.
  2. Metoda parametre ile gelen nesnelere ait metodlar.
  3. Metodun içerisinde oluşturulmuş bir nesneye ait metodlar.
  4. Nesnenin direk erişimi olan nesne ve özelliklere ait metodlar.

Bu maddeleri kısaca birer kod parçacığı ile gösterecek olursak.

  1. Nesnenin kendisine ait metodlar.
    public class OrnekSinif
    {
    	public void AcikIslemYap()
    	{
    		islemYap(); // Nesnenin kendi metodunu çağırıyor, LoD 1
    	}
    	private void islemYap()
    	{
    	}
    }
  2. Metoda parametre ile gelen nesnelere ait metodlar.
    public class OrnekSinif
    {
    	public void AcikIslemYap(DigerSinif digerSinif)
    	{
    		digerSinif.BaskaIslemYap(); // Parametre ile gelen nesnenin metodunu çağırıyor, LoD 2
    	}
    }
  3. Metodun içerisinde oluşturulmuş bir nesneye ait metodlar.
    public class OrnekSinif
    {
    	public void AcikIslemYap()
    	{
    		DigerSinif digerSinif = new DigerSinif(); 
    		digerSinif.BaskaIslemYap(); // Metod içerisinde oluşturulmuş nesnenin metodunu çağırıyor, LoD 3
    	}
    }
  4. Nesnenin direk erişimi olan nesne ve özelliklere ait metodlar.
    public class OrnekSinif
    {
    	DigerSinif digerSinif = new DigerSinif();
    	public void AcikIslemYap()
    	{
    		digerSinif.BaskaIslemYap(); // Nesnenin direk erişimi olan nesnenin metodunu çağırıyor, LoD 4
    	}
    }

Eğer kodlar içerisinde aşağıdaki gibi zincirleme bir metod çağrımı görüyorsanız. Bazı istisnalar olsa da büyük bir ihtimalle LoD’a uymayan bir kod yazmış bulunuyorsunuz.

nesne.GetirDigerNesne().DigerNesneninMetodu()

Daha anlaşılır olması adına şöyle de yazabiliriz.

hesap.OkuMusteri().OkuIletisimAdresi().OkuIlce()

Tabii LoD’u sadece zincirleme metod çağrımına karşı olan bir pratik olarak düşünmek doğru olmaz. LoD temelde şuna dayanır:

Bir bilgiyi nesnenin dışarısından çekmek yerine nesnenin kendisinden almalısınız.

Yukarıdaki örnek üzerinden düşünecek olursak hesap nesnesi OkuMusteri’den dönen Musteri nesnesi üzerinden dönen IletisimAdresi üzerinden Ilce’ye ulaşıyor. Eğer hesap nesnesinde bir ilçe bilgisi gerekiyor ise dış dünyanın öncelikle müşterinin okunduğunun sonrasında IletisimAdresinin okunduğunun (belki de ileride değişecek, ResmiAdres okunacak) bilgisine ihtiyacı yok. Onlar sadece hesaptaki ilçe bilgisini istiyorlar. Bu durumda aşağıdaki gibi bir kullanım tercih edilebilir.

hesap.OkuIlce()

Yeni OkuIlce metodu kendi içerisinde IletisimAdresini ya da ResmiAdresi seçebilir. Bu değişiklik metod kullanıcılarını etkilemeyecektir.

Tabii, diğer pattern ve pratiklerde olduğu gibi LoD’un kullanımının tercih edileceği ya da vazgeçilmesinin gerekeceği durumlar olacaktır. Bunun kararının verilmesi için biraz acı ve biraz tecrübe gerekecektir. 🙂 Ancak geliştirme sırasında LoD’u göz önünde bulundurmak oldukça fayda sağlayacaktır.

 

 

 

 

CodeBroad

logo-trnsprnt-lnkdin

Önceki gönderilerime bakınca neredeyse 3-4 senedir, senede bir paylaşım ancak yapabilmişim. Artık daha fazla yazacağıma dair söz vermiyorum 🙂 İşlerin ve hayatın yoğunluğu içerisinde çok fazla fırsatım olmuyor. Sadece daha fazla paylaşımı umut edebilirim 🙂

Bu seferki paylaşımın sebebi hayatımdaki köklü bir değişim. Yıllardır devam eden bordrolu çalışma hayatıma geçtiğimiz aylar itibari ile son verdim. İstifam sonrasında yıllardır hayalini kurmuş olduğum şeyi gerçekleştirdim ve CodeBroad (http://www.codebroad.com)’u kurdum. Ve en azından şimdilik her şey çok güzel devam ediyor.

Bundan sonra teknik konularda paylaşım yapmaya devam etmeyi umuyorum. Ama bunun dışında iş tarafında da paylaşımlarım olacaktır muhtemelen. Umarım az da olsa birilerini faydası olur.