Akaryakıt Pompa Haberleşmesinde Performans: 650–790 ms’den 20–40 ms’ye

Akaryakıt Pompa Haberleşmesinde Performans: 650–790 ms’den 20–40 ms’ye

Oct 9, 2026 · @Mustafa Çağrı Altındal

Sorun: ekran geç tepki veriyordu

Haberleşme katmanında çerçeve başına süre 650–790 ms’den 20–40 ms düzeyine indi; yavaşlığın asıl sebebi mimari değil, loglama ve yanlış bir bekleme sayacıydı.

Bir akaryakıt istasyonunda pompa, kart okuyucu ve tank probu aslında basit bir iş yapar: soru sorar, cevap bekler. Bizim yazılım da yıllardır bunu yapıyor. Ama sahada bir şey rahatsız ediciydi: kart okutulduktan sonra ekran geç tepki veriyor, tabanca kalkınca pompa kartı geç güncelleniyordu. Cihaz monitöründe baktığımızda çerçeveler arasında gözle görülür boşluklar vardı.

Bu yazıda FuelAutomation’ın haberleşme katmanında yaptığımız değişiklikleri, neyi yanlış tahmin ettiğimizi ve yavaşlığın gerçek sebebini anlatıyoruz.

Not: Ölçümlerin tamamı pompa simülatörü ve gerçek bir kart okuyucu ile, geliştirme makinesinde alındı. Gerçek pompada saha doğrulaması sürüyor; sonuçları ayrıca paylaşacağız.

Başlangıç: mimariden performans beklemek

İlk hamlemiz haberleşme katmanını baştan tasarlamak oldu; hızı da buradan bekliyorduk.

Eski yapıda her cihaz için tek bir döngü vardı: komutu gönder, 5 milisaniye uyuyarak cevabı bekle, cevap geldiyse işle, sonra bir sonraki cihaza geç. İş akışı (hangi durumda ne yapılacağı) ile protokol detayı (hangi bayt ne anlama geliyor) aynı sınıfların içinde iç içeydi. Bir pompa markasının protokolüne dokunmak, aynı dosyadaki iş mantığını riske atıyordu.

Yeni mimariyi dört katman üzerine kurduk:

  • Protokol katmanı: Yalnızca “bu komut hangi bayt dizisine karşılık gelir, gelen bayt dizisi ne demek” sorusunu cevaplar.
  • Durum makinesi: Boşta, tabanca kalktı, yetkilendirildi, dolum, satış bitti gibi durumları ve geçişleri yönetir. Bütün markalar için ortaktır.
  • Asenkron donanım katmanı: Seri portu olay güdümlü okur, kopmalara karşı otomatik yeniden bağlanır.
  • Kurtarma günlüğü: Elektrik kesilirse sistem kaldığı yeri hatırlar.

Geçişi bir anda yapmadık. Eski sürücüleri yerinde bırakıp yenilerini yanlarına yazdık; hangisinin çalışacağı tek satırlık bir seçimle belirleniyor. Sahada sorun çıkarsa eskisine dönmek de bir satır.

Ölçüm: yavaşlığın asıl sebebi mimari değildi

Protokol loglarından hesapladığımızda bir çerçeve gerçekte 650–790 ms sürüyordu; oysa cihazlar birkaç on milisaniyede cevap veriyordu. Zaman bizim tarafımızda harcanıyordu ve dört sebep bulduk:

  1. Her log satırında zorunlu bellek temizliği. Haberleşme loglarını yazan kod, her satırdan sonra .NET’in çöp toplayıcısını elle çağırıyordu. Bu, bütün uygulamayı kısa süreliğine durdurur. Üstelik pompa, okuyucu ve tank aynı log kilidini paylaştığı için biri yazarken diğerleri bekliyordu.
  2. Hata fırtınası. Tank probu döngüsü saniyede birkaç kez aynı hatayı fırlatıyor, kart okuyucu cevap gelmeyen her sorguda bir istisna üretiyordu. Tek bir günde on binlerce hata kaydı birikmişti ve her biri aynı yavaş yazma yolundan geçiyordu.
  3. Yanlış sayılan bekleme süresi. Kod, cevabı beklerken “5 ms uyu, sayacı 5 artır” mantığıyla süre ölçüyordu. Windows’ta kısa uykular yaklaşık 15 ms sürer. Geliştirme makinemizde ölçtük: kodun 100 ms sandığı bekleme gerçekte 315 ms sürüyordu. Cevap vermeyen her cihaz bu kadar bekletiyordu.
  4. Port her çerçevede kapatılıp açılıyordu. Her gönderimde seri portu kapatıp yeniden açmak hem zaman kaybettiriyor hem de cihazın cevabını kaçırabiliyordu.

Bunların tek tek payını ayırmadık; hepsini birlikte düzelttik.

Uygulanan çözümler: dört darboğazı ortadan kaldırmak

Dört darboğazı kaldırdıktan sonra çerçeve başına süre, ortancada 18–31 ms ve %90’da 34–41 ms ile cihazın gerçek cevap süresine yaklaştı.

  • Log yazma arka plana alındı. Log satırı artık kuyruğa bırakılıyor, diske yazmayı tek bir arka plan görevi yapıyor. 2000 satırı kuyruğa almak toplam 4 milisaniye sürdü. Zorunlu bellek temizliği kaldırıldı. Satırın saati kuyruğa alındığı anda alınıyor; dosyaya geç yazılsa bile log saati doğru. Loglara milisaniye hassasiyeti de ekledik, böylece bir sonraki ölçümü doğrudan okuyabiliyoruz.
  • Bekleme gerçek saatle ölçülüyor. Çerçeve tamamlandığı anda (protokolün bitiş bayrağı gelince) bekleme bitiyor, süre dolması beklenmiyor.
  • Port bir kez açılıyor ve açık kalıyor.
  • Kart okuyucuda cevap gelmeyen sorgu artık hata üretmiyor. Tank probundaki tekrar eden hata ayrıca ele alınacak.

Aynı makinede, son ölçümlerde:

CihazÖlçümOrtanca (ms)%90 (ms)
Pompakomut → ACK1834
PompaPOLL → cevap2439
Kart okuyucudurum sorgusu → ACK3141

Asenkron neden tek başına hızlandırmadı?

Asenkron okuma tek başına hız getirmedi, çünkü pompa ve okuyucu hattı yarım çift yönlüdür: aynı anda tek soru gidip cevabı beklenebilir.

Asenkron okumanın kazandırdığı şey, cevap gelir gelmez beklemeyi bırakmaktır. Bunu eski kodun içindeki bekleme döngüsünü düzelterek de elde edebilirdik. Modern mimarinin asıl getirisi hız değil, düzen: iş akışının protokolden ayrılması, yeni bir cihaz markası eklemenin kolaylaşması ve port koptuğunda otomatik yeniden bağlanma.

Protokol ve akış tarafında yaptığımız iyileştirmeler

Ölçüm işini yaparken protokol dokümanlarını sürücü koduyla yan yana baştan okuduk ve haberleşmeyi daha sağlam hâle getiren bir dizi düzeltme yaptık.

Haberleşme ve protokol

  • Kart okuyucu komutlarında kontrol toplamı yöntemi dokümandaki 16 bit CRC’ye göre düzeltildi.
  • Okuyucu ekranına yazı gönderen komut ve satır yerleşimi düzeltildi; metinler artık doğru satırlarda ve ortalanmış görünüyor.
  • Sıfırlama komutu artık kart verisi okuyucuda hazır olana kadar bekletiliyor.
  • Pompa tarafında gelen veri, blok uzunluğuna göre değil içindeki işlemlere (transaction) göre çözümleniyor. CRC doğrulaması, bayt kaçışı desteği ve blok sıra numarası yönetimi gözden geçirildi; tutar ön ayarı doğru işlem koduyla gönderiliyor.
  • İki ada yüzü olan pompada fiyat bloğu artık her yüze yalnızca o yüzün kendi tabancalarının fiyatlarını taşıyor.

Filo akışı: kart sırası ve yetkilendirme

Filo müşterilerinde kart akışı şu sıraya oturdu:

  1. Tabanca kalkınca okuyucu ekranı “ARAÇ KARTI OKUTUNUZ” der.
  2. Araç kartı okununca, filo tanımında aktifse kilometre sorulur (ya da araç takip sisteminden alınır).
  3. Filo tanımında sürücü aktifse “SÜRÜCÜ KARTI OKUTUNUZ” çıkar.
  4. Pompacı ayarı açıksa “POMPACI KARTI OKUTUNUZ” çıkar.
  5. Gerekli tüm adımlar tamamlanınca pompa yetkilendirilir.

İki tasarım kararı önemliydi. Birincisi, sürücü sorulup sorulmayacağına genel ayar değil filo tanımı karar verir; sürücü takibi olmayan filolar etkilenmez. İkincisi, yetkilendirme yalnızca akıştaki tüm gerekli bilgiler tamamlandığında verilir.

Kart tabanca kalkmadan önce okutulursa okunan bilgiler artık hemen silinmiyor; yarım kalan işlem 90 saniye sonra, tabanca hâlâ kalkmamışsa temizleniyor. Tek bir okuyucu iki ada yüzüne bağlıysa, kart tabancası kalkık olan yüze yazılıyor.

Ekran tarafındaki görünür düzeltmeler

  • Fiyat değiştirildiğinde pompa kartındaki birim fiyat, pompa boştayken de 5 saniye içinde güncelleniyor.
  • “SATIŞ BİTTİ / FİŞ ALINIZ” yazısı ekranda 100 saniye yerine yaklaşık 8 saniye kalıyor.
  • Dolum sırasındaki ekran yazısı doğru metni (“DOLUM / YAPILIYOR”) gösteriyor.

Çıkardığımız dersler

Bu çalışmadan dört ders aldık:

  1. Önce ölç, sonra mimariyi suçla. Asenkron geçişin hız getireceğini varsaymıştık. Gerçek darboğaz loglama, hata fırtınası ve yanlış bir bekleme sayacıydı.
  2. Loglama sıcak yolun parçasıdır. Haberleşme döngüsünün içinden diske yazan her satır, o döngünün süresine eklenir.
  3. Yeni yapıyı eskisini silmeden kurun. Eski sürücüleri yerinde bıraktık; sahadaki bir sorun bir satırlık seçimle geri alınabiliyor.
  4. Protokol dokümanını sürücüyle yan yana okumak sessiz hataları ortaya çıkarır.

Bir yanıt yazın