Python multi-processing gRPC server

gRPC server yazacagiz ve serverimizin cok guclu (o da ne demekse) olmasini istiyoruz. Bu yuzden, bir sekilde gelen requestleri paralel olarak isleyebilen bir yapiya ihtiyacimiz var. Python threading malum, CPU intensif isler icin uygun degil cunku GIL sebebiyle ayni anda birden fazla Python kodu calistirilamiyor. Dolayisi ile mevzubahis CPU gerektiren islemler ise, Python threading aslinda tek thread gibi davraniyor. 

Bu durumda official ornege bakabiliriz. Tamam Python threading'de GIL engeli var ama multi-process yapar isek boyle bir engel yok. Ne de olsa her bir process kendi GIL'ine sahip olacak. Ama burada da yuku processlere nasil dagitaracagimiz problemi akillara geliyor. 






Port Sharing
Resmi ornekte, yuk dagitma islemini butun process'leri ayni porta bind ederek saglamislar. Bu sayede yuk TCP katmaninda, isletim sisteminin Kernel seviyesinde yapilmis oluyor. Port uzerine gelen istekler, TCP katmani tarafindan bu portu dinleyen processlere bir round-robin yapisi seklinde dagitiliyor. Gayet makul ve islevsel. Bu sekilde bir portu kullanmak istersek, portu acarken SO_REUSEPORT opsiyonunu belirtmemiz gerekiyor. 





Verilen resmi ogreni denedim, calistirdim. Gayet guzel sonuc veriyor. Gelen requestlere farkli processlerin cevap verdigini loglardan farkli PID'lere sahip olduklarini gorebiliyoruz.Bu durumda CPU intensive islemler bile gerceklestirebiliriz. GIL, bak isine kardesim.


Windows?  
Tabi ki hayat bu kadar kolay olsaydi pek zevki olmazdi. Ayni kodu Windows'ta claistirmaya calistigimizda hemen bir problem ile karsilasiyoruz ki, Windows'ta SO_REUSEPORT opsiyonu yok! 

Kendilerince guvenlik gibi bir aciklamalari var. Bunun yerine SO_REUSEADDR seklinde bir secenek gelistirmisler. Direk olarak SO_REUSEPORT opsiyonunu bu opsiyon ile degisitip denedigimizde ise sonuc yine husran oluyor. Goruyoruz ki, farkli processler'de olusturmaya calistigimiz gRPC serverlari ayni port'a bind olamiyorlar. Burada problem gRPC server implementasyonundan mi yoksa Windows'un tam olarak portu share edememesinden mi kaynakladndigini anlamak icin bir deney yaptim. 


Windows'un Sucu Yok
En son soylenecek olan seyi en basta soylemek gerekirse, Windows'in SO_REUSEADDR opsiyonu da ayni Linux'un SO_REUSEPORT opsiyoni gibi portu share edebiliyor. Bunu denemek icin cok basit bir TCP server ve client yazdim. Server kismi birden fazla process olusturuyor ve her birinde SO_REUSEADDR opsiyonu set edilmis sekilde socket aciliyor. Socketler tabi ki ayni porta bagli. Clien'tan gelen requestlerin gayet guzel bir sekilde process'lere dagitildigini goruyoruz. 


Google Yapma Bunu
Demek ki sorun gRPC tarafinda. Ayarlara bakinca daha da iyi anliyoruz ki, gRPC server olustururken verdigimiz 'grpc.so_reuseport' secenegi mevcut kodun calistigi sistem sadece SO_REUSEPORT opsiyonu olup olmadigina bakiyor. Eger yok ise, bu opsiyonu set etmiyor ve birden fazla gRPC server ayni port uzerinde kullanilamiyor. 

Baska sekillerde de belki yuk processler uzerine dagitilabilir ama isleri cok da karmasiklastirmak istemiyoruz. 

Sonuc olarak Linux uzerinde multi-processing gRPC server mumkun iken Windows uzerinde mumkun olmuyor. 

Peki bu ne kadar bir problem? Bunu ileriki testlerimizde daha iyi gorecegiz. 

Simdilik hoscakalin.







Yorumlar

Bu blogdaki popüler yayınlar

Python'da Multithreading ve Multiprocessing

Threat Modeling 1

Encoding / Decoding