SD #4: Whatsapp System Design

Problem
Asagidaki ozellikleri (feature) destekleyecek sekilde scalable bir mesajlasma servisi tasarimi yapiniz:

- Birebir mesajlasma (Gonderildi / Iletildi / Goruldu notifikasyonlari)
- Last seen ozelligi

Cozum 

1. Birebir mesajlasma 
Ornegin Bob, Alice'e mesaj gonderiyor olsun. Bunun olabilmesi icin oncelikle Bob'un bir sunucuya bagli olmasi gerekir. 

Client - server baglantisi
Belki de son soyleyenecek seyi en basta soyleyelim. Sunucular ile kullanicilar WebSockets protokolu uzerinden haberlesecekler. Neden? Cunku bir noktada, sunucunun direk olarak client'a mesaj gondermesi gerekiyor. Http ile bu mumkun degildir. Http protokolu sadece clienttan sunucuya istek gonderilmesi ve sunucunun da bir cevap dondurmesi uzerine kuruludur. Durup dururken bir server size mesaj gonderemez. Client tarafinda long polling yapilabilir ama bu da hem realtime olmaz hem de sunucuya gereksiz cok fazla request atilmis olunur.

Client-server baglantisi TCP uzerinde calisan WebSockets ile yapilacak ancak Gateway'den sonraki bizim kendi private networkumuz oldugu icin tamamen farkli mesajlasma protokolleri kullanilabilir.

Sistemi mumkun oldugunca scalable yapmak icin, kullanicilarin ilk muhattap olduklari sunucular stateless olmalidir. Yani bir gateway, mesajin muhattabi olan Alice'in hangi gateway'e bagli oldugunu bilmek zorunda degildir. Hatta Alice hicbir sunucuya bagli olmayadabilir (offline). 


Ilk adimda Bob mesajini yazar ve gondere basar. Bu mesaj gateway #1'e ulasir. Gateway #1, muhattap kisinin yani Alice'in hangi gateway'e bagli oldugunu hatta online olup olmadigini dahi bilmez. Yani state barindirmaz.

Kimin hangi gateway'e bagli oldugunu tutan Sessions Service adindaki servistir. Bu servis te SPF olmamasi icin load balancer arkasinda birden fazla replika uzerinde calismaktadir. Kimin hangi gateway'e bagli oldugu da, sessions service'in query yaptigi persistence layer'da tutulmaktadir. Performans acisindan bu bir redis cluster olabilir. Bu sayede kullanici ve bagli oldugu gateway key-val seklinde kolayca sorgulanabilir ve guncellenebilir. 

Gateway #1, mesaji Sessions Service'e ilettigi anda, geriye bir `sent` cevabi doner. Gateway #1 de bunu tekrar Bob'a gonderir. Boylece Bob ekraninda `Mesaj Gonderildi` ibaresi gorur. (gri tek tik). 

Sessions service, egere mesajlar sunucuda kayitli tutulmasi gerekiyorsa, bunu bir baska persistence layer uzerinde kaydeder. Gerekmiyorsa, bir queue'ya push etmelidir. Muhattabin (Alice) hangi gateway'e bagli oldugunu da key-value store'a sorup ogrendikten sonra, ilgili gateway'e mesaj iletilir. 

Bu gateway de zaten kendisine bagli olan Alice'e mesaji gonderir. Tam bu noktada Gateway #2, sessions service'a "Iletildi" ibaresi geri dondurur. Bu iletildi ibaresini goren sessions service de Bob'un bagli oldugu gateway'e bu iletildi ibaresini gonderir. Bu sayede sonuc olarak Bob, ekraninda mesah `Iletildi` olarak gorur (Gri cift tik). 

Son olarak da, Alice uygulamayi acip da mesaji goruntuledigi zaman, uygulama gateway'e bu sefer bir mesajin kullanici tarafindan okundugu bilgisini gonderir. Hatta bu bilgi, kullanicilarin birbirlerine gonderdikleri mesaj ile ayni formatta olabilir ancak sadece uygulama/sunucu haberlesmesi icin kullanilacak sekilde bir flag'e sahip olabilir. Ayni queue'lerde bekler, ayni sekilde diger uctaki kullaniciya teslim edilir. Ancak bu mesaj kullanicinin okumasi icin degil, uygulamanin okumasi icindir. Bu ornkete de, Alice'ten gonderilen `mesaj okundu` mesaji, Bob'un uygulamasina geldigi anda, Bob mesaji `Okundu` olarak gorecektir. 

Bu trafigi su sekilde ozetleyebiliriz:


 
2. Last seen
Bir kullanici, diger bir kullanicinin en son ne zaman online oldugunu gorebilmelidir. Bunu whatsapp'ta bir dialog'a girdigimizde gorebiliyoruz. Bu da su demek, tum arkadas listesinin en son ne zaman online oldugunu gormekten ziyade, bu servis sadece verilen kullanicinin en son ne zaman online oldugunu gostermelidir. 

Bunu nasil anlayabiliriz? Bir kullanicinin yaptigi aksiyonlar ve bunlarin tarih/zaman bilgisi merkezi bir yerde toplanir ise, en son ne zaman bir is yaptigini enazindan bilebiliriz. Peki su anda online mi? Burada yine bir yaklasimda bulunarak, eger son yaptigi islem son 20 saniye icerisinde ise, bu kisiyi online olarak gosterebiliriz. Eger 20 saniyeden eski ise, bu kisi `Last seen 30 seconds ego` gibi bir ibare gosterebiliriz. 

Bir kullanicinin yaptigi tum aksiyonlari kim biliyor: Gateway. Kullanicidan mesaj gonderme, okuma, profil gorunuleme gibi herhangi bir request geldigi zaman, gateway asenkron olarak Lastseen servisine bu bilgiyi gonderebilir. LastSeen servisi de bagli oldugu bir key-val store uzerinde kullanicinin last-seen tarihini guncelleyebilir. Her kullanici icin timestamp seklinde sadece tek bir alan. Okumasi ve yazmasi da key-val store ile son derece basit, performansli ve scalable olacaktir. 



Burada Bob'un Alice'in lastSeen durumunu sorgulamasi goruluyor. Ayrica, Alice bir mesaj gonderdiginde de lastSeen durumunun guncellenmesi 2. asamada goruluyor. 

Grup mesajlasma ozelligini de onumuzdeki system design postlarinda tartismak dilegi ile. 

Stay hungry, stay foolish, stay healthy :)



Yorumlar

Bu blogdaki popüler yayınlar

Python'da Multithreading ve Multiprocessing

Threat Modeling 1

Encoding / Decoding