MessagePack Nedir?Serialize/Deserialize Yöntemleri Neden Önemlidir?

Emre Balcı
Nov 5 · 4 min read

Bir koşucu hayal edin...

Ayakkabısı eski püskü, sürekli koşmaktan yıpranmış ve koşarken ayağını acıtan taşlar yüzünden düşen ama yılmadan yoluna devam etmeye çalışan bir koşucu. Belki üstündeki forması çok iyi, hiç terletmiyor hatta koşarken çok rahat fakat üstündeki bu formanın performansına herhangi bir katkısı ne yazık ki yok.

Şimdi de bu koşucumuzu takım arkadaşlarıyla birlikte bir bayrak yarışının son koşucusu olduğunu hayal edelim. Her ne kadar ondan önce koşan takım arkadaşları çok hızlı koşmuş olsa da bitiş çizgisine takımı götürecek olan bu koşucudur. Bu koşucu yeterince iyi koşmazsa takım kaybedebilir.

  • Serialize/Deserialize Nedir?

Kısaca bahsedecek olursak serialize ya da serialization, bir datayı kolayca ulaşılabilir hala getirmek ya da bir datayı platform bağımsız hale getirmektir(json,xml,binary).

Bu durumda deserialize ise: Ulaşılabilir hale gelmiş datayı tekrardan hangi dilde yazıyorsak o dildeki objeye çevirmektir.

  • Peki Neden Önemli?

Bir yazılım projesini yukarıda bahsettiğim gibi bayrak yarışı gibi örneklendirecek olursak:

Projemizdeki servislerin her biri bayrak taşıyan koşucu misali gayet iyi şekilde çalışıyor olsun. Veri tabanı bağlantıları kusursuz. Cache mekanizmalarımız mükemmel bir şekilde işliyor olsun. Sonunda oluşturduğumuz veriyi client tarafına aktaracağımız zaman bir serialize işlemine tabi tutmamız gerekecek. Eğer buradaki serialize işlemi yavaş olursa response süresini uzatacak ve bu da performansı etkileyecek. Hatta bilgilerimizi redis gibi cache de yada NoSql veritabanlarından birinde tutuyorsak,serialize yönteminize göre performansınız daha çok etkilenmektedir.

  • Peki Serialize/Deserialize Yöntemlerinden Hangisi Neden Seçilmeli?

Aslında bu sorunun yanıtı tamamen projenin gereksinimleri ve verinizin büyüklüğüne göre değişir.

Örneğin: Küçük bir veriyi serialize edip, bir dosyaya yazdığınızı ve bu dosyayı müşteriye mail olarak ileten bir uygulamanız olsun. Buradaki veri küçük olduğundan ve dosyaya yazdığınız verinin anlamlı bir veri olmasını istediğinizden dolayı Json kullanmak mantıklı olacaktır.

Fakat aynı örneğin tersini düşünelim verimiz çok büyük fakat uygulamamız bu sefer serialize edip redise atacak. Bu sefer redise attığımız verinin anlamlı bir halde olmasına gerek yok. Çünkü redisden çekerken zaten bu veriyi deserialize edeceğimizden dolayı anlamlı bir objeye dönmüş olacaktır. Bu durumda performansı düşünerek en hızlı serialize hangi kütüphane yapıyorsa o seçilebilir.

Gelin birlikte messagepack, protopuf, byte, json serialize yöntemlerini benchmark yapacak olan programı yapalım.

Bunun için terminalden dotnet new console -n benchmark_test komutuyla yeni bir console uygulaması yaratalım.

Uygulamamızı oluşturduktan sonra gerekli olan paketleri yükleyelim.

- dotnet add package BenchmarkDotnet
- dotnet add package MessagePack
- dotnet add package Newtonsoft.Json
- dotnet add package protobuf-net

İlgili nuget paketlerini yükledikten sonra serialize işlemleri için örnek datalara ihtiyacımız var. Bunun için ilgili linkten bir tane büyük boyutlu bir json oluşturup projemize dahil edelim.

Oluşturduğumuz jsonları deserialize etmemiz için jsonların modeline ihtiyacımız var. Bunun için Model adında bir class oluşturuyoruz.

İsterseniz json verinizi .net tarafındaki classlara çeviren online bir tool olan json2csharp’ı kullanabilirsiniz.

  • Serializable : Byte serialize/deserialize işlemlerimiz için gerekli olan attribute.
  • MessagePackObject: MessagePack serialize/deserialize işlemlerimiz için gerekli olan attribute.

MessagePack serialize/deserialize işlemleri için bütün propertylerine Key attribute’nun verilmesi gerekiyor. Eğer kullanılan base attribute MessagePack(true) şeklinde kullanırsa Key attributelerine gerek kalmaz.

  • ProtoContract: Protobuf serialize/deserialize işlemlerimiz için gerekli olan attribute.

Protobuf’ın modelinizdeki propertylerin hangilerini serialize/deserialize etmesini istiyorsak, ProtoMember attribute’nu vermemiz gerekiyor.

Modeli oluşturduktan sonra Benchmark işlemini gerçekleştirecek olan classımızı oluşturarak devam edelim. Bunun için BigDataSerializerBenchmark adında bir class açıyoruz.

BenchmarkDotNet kütüphanesinin yardımıyla basit bir benchmark yapıyoruz.

[SimpleJob(RunStrategy.Monitoring, targetCount: 100)]: Bu classa bir iş atamış oluyoruz. O da class içerisinde belirttiğimiz methodları 100 er kez çağıracak ve bunun benchmarkını monitör etmesini sağlayacak.

LoadDataset: Bu methodumuzun GlobalSetup attribute almasındaki amaç: Benchmark işlemi başlamadan önce gerekli ayarların yapılmasını sağlamak. Örneğimizde big_data.json adındaki dosyayı desearilize edip modelliyoruz. Böylece diğer methodlarda ilgili model serialize/deserilize işlemlerine tutulabilmesini sağlıyoruz.

[Benchmark]: Bu attribute sayesinde ilgili methodların benchmarka dahil olup olmadığını söylemiş oluyoruz.

Benchmark classımızı hazırladığımıza göre şimdi sonuçları gösterme işlemine geçebiliriz. Bunun için Program.cs dosyamıza gidiyoruz.

Artık projeyi çalıştırıp sonuçların nasıl olduğuna bakabiliriz.

NOT: BenchmarkDotNet kütüphanesi belirttiğimiz classın benchmarkını çıkartması için projemizin Realese modunda çalışmasını beklemektedir.

Bunun için dotnet run -c Release komutunu kullanarak projeyi çalıştırıyoruz.

Benchmark sonucu. Median bilgisi diğer zamanlardaki verilerin ortalaması şeklindedir.

Benchmark sonucu bize gösteriyor ki MessagePack diğer serialize yöntemlerine göre çok çok daha hızlı olurken, Protobuf ile oluşturulan data diğer serialize yöntemlerine göre çok çok daha az boyutta.

Tabi yukarıda da söylediğim gibi hangi serialize yöntemini kullanacağınız size ve tabi projenizin ihtiyacına göre değişmektedir.

Yaptığımız bu projeye buradan ulaşabilirsiniz.

  • Peki Bence Neden MessagePack?

Çalıştığım projede yaptığımız bir apide saniyede atılan istek sayısı oldukça fazla, response süremiz ise çok uzundu. Bu isteklerin sonucundan dönen veride ciddi anlamda büyüktü. Bundan dolayı bu api de performans sorunları yaşamaya başlamıştık. Benchmark yaptığımızda en çok serialize/deserialize işlemlerinde zaman kaybettiğimizi gördük.

Verilerimizin tamamını redisden çekiyorduk. Haliyle redise yazarken veya redisden veriyi alırken serialize/deserialize işlemlerine tabi tutuyorduk. Başlarda serialize/deserialize yöntemi olarak json kullanmıştık. Fakat verimiz çok büyüktü serialize/deserialize işlemlerinde ciddi performans kaybı yaşıyorduk.

Sonrasında serialize/deserialize yönteminibyte olarak değiştirmeye karar verdik. Json’a göre byte’a çevirmemiz fark yaratmıştı. Fakat dönen verimiz daha da büyümeye başlayınca performans anlamında hala sıkıntılarımızın olduğunu gözlemledik.

Bunun üzerine serialize/deserialize yöntemleri hakkında araştırma yapmaya başladım. Birçok kaynak messagepack den bahsediyordu. Hem serialize/deserialize işlemlerindeki hızı, hem de serialize işlemleri sonrasında çıkan verinin boyutu ciddi anlamda küçültüyordu. Bunun üzerine messagepack’i denemeye karar verdik. Sonuç şaşırtıcıydı. Başlarda sadece bu işlemler için ortalama 1000ms bulurken, messagepackde bu süre ortalama 19ms bulmuştu. Gerçekten gözle görülür bir fark vardı.


Okuduğunuz için teşekkür ederim.

Sağlıcakla kalın…

Emre Balcı

Written by

Back-end Developer (at) Demirören Teknoloji https://www.linkedin.com/in/emre-balci/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade