ProtoBuf Nedir?

Selamlar,

Bu makalede google trafından geliştirilen, Json ve Xml Serialization’a göre çok daha performanslı çalışan  Binnary Serialization Protobuf’i inceleyeceğiz. Gerçek ismi Protocol Buffers olan, Google’ın kendi içindeki veri iletisiminde de bolca kullandığı bir veri transfer protokolüdür.

Bir uygulamının performansı göz önüne alındığında, ilk önce en çok kullanılan yani yoğun olarak işlem yapılan dinamikleri monitör edilir. Ve bilin bakalım karşınıza performans canavarı ilk ne çıkar :) Tabii ki Json.NET – Newtonsoft :) Evet kullanımı kolay ama yoğun ve büyük projelerde kesinlikle terk edilmelidir. Alternatiflerinin çokluğu ile kafanız karışabilir. Ve kabul etmek gerekirse var olan bir sisteme, yeni bir serlization kütüphanesi getirmek biraz zahmetlidir. Ama aşağıdaki grafikden de anlaşıldığı gibi, bu kadar büyük bir performans farkı çekilen tüm zahmete deymektedir.

Image Source: https://i2.wp.com/maxondev.com/wp-content/uploads/2015/02/serialization_speed_large.png?w=600&ssl=1

Protobuf C, C#, Haskell, Perl, Ruby,C++, Java ve Python gibi birçok dili third party toolar ile desteklemektedir. Tam listeye buradan erişebilirsiniz. Biz bu makalede C# .Net Core üzerinde protobuf’ı inceleyeceğiz.

Yukarıda görüldüğü gibi yeni oluşturulan protobuf isimli .Net Core Console bir application’a, aşağıdaki komut ile Protobuf .Net  kütüphanesi indirilmiştir.

Önce gelin modellerimizi oluşturalım.

Base Model Human.cs: Esas “Person” adında oluşturulacak bir sınıfın, türetildiği  Base bir sınıftır.

Yukarıda dikkat edilecek bazı konular, aşağıda detaylıca anlatılmıştır:

  1. [ProtoContract] : Modellerin bu attribute ile işaretlenmiş olması gerekmektedir. Anlamı, bu modelin protobuf ile Serializa veya Deserializa olacağı anlamına gelmektedir.
  2. [ProtoInclude(100, typeof(Person))] : Bu sınıfdan inherit olacak sınıflar, gene burada tanımlanmalıdırlar. İşte yazılmış bir projeye, protobuf implementasyonun zorluğu burada başlar. Bu tanımlamada amaç, protobuf işlem yapacağı sınıfı bir bütün olarak görür. İlgili sınıfın tüm propertylerine, türetildiği sınıflar dahil olmak üzere, bu tanımlama ile erişir. Buradaki “100” sayısı, ilgili base sınıfa ait unique verilmiş bir sayı olması gerekmektedir.
  3. [ProtoMember(1)] : Protobuf ile transfer edilecek her bir property, bu attribute ile o sınıfa ait unique bir sayı ile işaretlenmelidir. Örneğin base Human class’ı için Surname (1) ve BirthDate(2) sayısı ile işaretlenmişlerdir.

Friends: Person sınıfının gene bir property’si olarak kullanılacak, bir başka sınıftır. Aşağıda görüldüğü gibi, bu da “[ProtoContract]” attribute’ü ile işaretlenmiştir. Ve yine protobuf ile işlem yapılacak tüm propertyleri, unique bir şekilde “[ProtoMember(x)]” attribute’ü ile işaretlenmiştir Buradaki “X”, ilgili sınıfta ait her bir kolon için unique olan bir sayıdır.

Gender: Gender, birazdan tanımlanacak Person sınıfının bir propery’si olan enum tipidir.

Person: Sıra geldi person sınıfına. Bu sınıf gene “[ProtoContract]” ile işaretlenmiştir. Ve yukarda tanımlanan “Human” sınıfından türetilmiştir. Her bir propertysi “[ProtoMember(X)]” ile işaretlenmiş ve her bir kolonu için unique bir sayı verilmiştir. Ayrıca bir propertysi de yine yukarıda tanımlanan List of Friend’dir.

Program.cs: Aşağıda görüldüğü gibi “List<Person>” tipinde bir PersonList tanımlanmıştır. Amaç, mümkün olduğunca gerçek hayatta kullanılabilecek karışık bir tipi serializa etmektir.

  • İlk eklenen Person sınıfı Friends propertyleri ile beraber complex bir sınıftır. Diğer 2 sınıf, sırf diziye birden çok sınıf eklensin diye konulmuştur.
  • “using (var stream = new MemoryStream())” : Protobuf “List<Person>”‘ı Serialize edip, bu stream’e atar. Daha sonra “bye[ ]” dizisine çevirir.
  • “ProtoBuf.Serializer.Serialize()” Protobuf serialize işlemi.
  • “ProtoBuf.Serializer.Deserialize<T>” : Protobuf deserialize işlemi. Kendisine gelen stream’i “T” tipine çevirir.
    • “var stream = new MemoryStream(bytePersonList)” : “byte[ ]” dizisine çevrilen “bytePersonList”, Protobuf ile deserialize edilmek için tekrardan “stream”‘e çevrilir.
  • Tekrardan Deserialize edilen “ListPerson” gezilerek, ekrana basılmıştır.

Şimdiye kadar Protobuf ile serialize ve deserialize işlemleri nasıl oluyor, hep beraber inceledik. Şimdi gelin Json.NewtonSoft ile olan performance farkını test edelim.

Program.cs(Test): Yukarıda tanımlı Bora adlı Person Sınıfı, “ListPerson<Person>”‘a ilk test’de 5 adet 2. test’de 10 adet eklenerek, 1000000 kere “Protobuf” ve “NewtonSoft” ile Seserialize, Deserialize edilmiştir. Başlangıç ve bitiş zamanları arasındaki fark, “saniye” cinsinden ekrana yukarıdaki gibi yazılmıştır. Yapılan testten de anlaşıldığı gibi, Protobuf data büyüklüğü arttıkça kendini daha da göstermekte ve neden tercih edilmesi gerektiğini bu kadar az data ile bile, bu kadar büyük performans farkı göstererek ispatlamaktadır.

Protobuf’a benzer kütüphaneler bulunmaktadır. Bunlardan bir tanesi de ZeroFormatter‘dır. Daha çok oyun programlama ve Unity için tasarlanmış bir kütüphanedir. Bir diğeri de MessagePack kütüphanesidir. Bu iki kütüphane sadece C# dilini desteklemektedir. Halbuki Protobuf, farklı bir çok dili desteklemektedir. Çalışma şekilleri ve kodlar, nerde ise Protobuf ile birebir aynıdır. Kısacası bu makalede geçen kodalardan, sınıfların başına konan “[ProtoContract]” yerine başka bir komut ve property’ye atanan “[ProtoMember(2)]” Unique index komutu yerine, ilgili kütüphaneye ait komut yazılarak kodlamaya devam edilebilir.

Geldik bir makalenin daha sonuna. Bu makalede, performans üzerine konuştuk. Umarım işinize yaramıştır. Artık büyük ve yoğun projelerde, NewtonSoft kullanırken iki kere düşünürsünüz:)

Yeni bir makalede görüşmek üzere, hepinize hoşçakalın.

Source Code: http://www.borakasmer.com/projects/protobufvsnewtonsoft

Kaynak : 

 

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

9 Cevaplar

  1. Yazilimci dedi ki:

    Hocam makale için teşekkürler, .net core da varsayılan olarak bir api methodunda örneğin List döndüğümde bunu json ‘a çeviren newtonsoft sanırım bunun arasına girip zero formatter ile nasıl değiştirebiliriz sorum yanlış olabilir kusura bakmayın

    • borsoft dedi ki:

      Öncelikle data dönen List modelinin propertylerini ZeroFormatter’a göre aşağıdaki gibi indexleyip, [ZeroFormattable] attribute’ü ile işaretlemelisin.
      Kısacası view modellerini kullanacağın serialize aracına göre değiştirmelisin. Sonra normal ZeroFormat kodunu içine gömücen.

      [ZeroFormattable]
      public class MyClass
      {
      [Index(0)]
      public virtual int[] Prop1 { get; set; }
      [Index(1)]
      public virtual IList Prop2 { get; set; }
      }

  2. can dedi ki:

    paket boyutlarından bahsettmemişsiniz json a göre trafik açısından ne kadar fark var

  3. ahmet dedi ki:

    merhaba bora hocam. merak ediyorumda bir online oyun -mmorg veya rpg- için socket mi yoksa protobuf mı kullanılmalıdır? ikisi arasında ne tür farklar var? protobuf klasik yöntem olan socket sisteminden daha stabil ve hızlı olabilir mi?

    deneyimlerinizi düşününce fikrinizi merak ediyorum. ve bu konuda bir makale veya videolu bir performans testi görmek çokta iyi olur.

    sağlıklı günler dilerim.

    • borsoft dedi ki:

      Selam Ahmet,

      Socket ve Protobuf birbirinen biraz farklı konular. Ama amacını söylersen daha sağlıklı bir cevap verebilirim. Socket kullanacak isen bence en performanslısı Go Socket sonra SocketIO ve son olarak Azure SignalR Service.

      İyi çalışmalar.

  4. Coder bora v2 dedi ki:

    Hocam yorumlara cevap verseniz çok iyi olur. Trafik ve online oyun soruları benimde merak ettiğim konular. Sizi 600r seven motorcu gibi seviyorum hocam öptüm.

    • borsoft dedi ki:

      Verdim sorulara cevap :) 600RR candır. Eski motorlarımdan biridir. Pert etmeseydim iyiydi :)

      Hoşçakal..

  1. 8 Şubat 2020

    […] için Json.Net & Newtonsoft yerine ProtoBuf kullanabilirsiniz. ProtoBuf ile ilgili olarak; Bora Kaşmer’in ProtoBuf Nedir ? yazısını tavsiye […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.