Roblox, Kafka Platformunu Nasıl Günde 18 Trilyondan Fazla Mesajı İşleyecek Şekilde Genişletti?
Verimli Sistemler için Uçtan Uca Optimizasyon

Son iki yılda, şirket içi mesaj kuyruğu platformumuzu her yıl 2,5 kat artırarak günlük 18 trilyon mesajın üzerine çıkardık. Şu anda saniyede 300 milyondan fazla mesajı işlerken %99,995 kullanılabilirlik oranını koruyoruz. Apache Kafka üzerine kurulu bu mesaj kuyruğu platformu, şirket genelinde veri aktarımında kritik bir rol oynamaktadır. Analitik olayları, moderasyon boru hatları, eşleştirme sistemleri ve daha pek çok iş yükünü desteklemektedir. Bu rakamlar heyecan verici olsa da asıl önemli olan, bu noktaya nasıl geldiğimizdir.
Uçtan Uca Optimizasyonun Etkisi
Büyük ölçekli sistemlerle ilgili yaygın bir yanılgı, kapasitenin çoğunlukla bir donanım sorunu olduğu yönündedir. Deneyimlerimize göre, en etkili iyileştirmeler ölçeklenebilirliği uçtan uca bir mühendislik sorunu olarak ele alarak elde edilir.
Roblox’taki ekipler, mesaj kuyruğunun üzerine yapay zeka eğitim iş akışları, akış işleme soyutlamaları ve telemetri sistemleri dahil olmak üzere çeşitli platformlar oluşturdu. Bu platformların sahipleriyle iş birliği yapmak, toplu işleme ve sıkıştırmayı etkinleştirme gibi en iyi uygulamalara uyulmasını sağlamamıza yardımcı oluyor. Bu da, son kullanıcıları ayrıntılı yapılandırma işlemlerine dahil etmeden verimli sistemler elde etmemizi sağlıyor.

İş öncelikleri, ölçüm ve başarı kriterleri konusunda platformu kullanan ekiplerle uyum sağlamak çok önemlidir ve ekipler arası işbirliğini teşvik eder. Temel metrikler, sistemin katmanları arasında farklılık gösterir: Kafka sunucularını, daha az makineyle büyük veri hacimlerini verimli bir şekilde işleyecek şekilde optimize edebiliriz; ancak son kullanıcılar, uçtan uca gecikmeyi milisaniye düzeyine kadar optimize etmek veya toplu işlerinin veri yazma işleminin tamamlanması için gereken toplam süreyi optimize etmek isteyebilir.
Tüm Trafik Eşit Değildir
Öğrendiğimiz önemli derslerden biri, büyük ölçekli platformların tüm trafiği eşit şekilde ele almadıklarında daha güvenilir olduğudur. Bazı iş yükleri, uçtan uca gecikme süresi 10 milisaniyenin altında çalışan eşleştirme sistemlerimiz gibi, yoğun dönemlerde çok düşük gecikme süresi ve güçlü koruma gerektirir. Diğerleri ise son derece yüksek hacimli olmasına rağmen gecikmeye daha toleranslıdır; örneğin, uçtan uca gecikme süresi birkaç saniyeye ulaşsa bile sorunsuz çalışabilen analiz olay alımı boru hatlarımız gibi. Her ikisi de aynı şekilde ele alınırsa, özellikle yükün en yoğun olduğu dönemlerde, en yüksek hacimli trafik, iş açısından daha kritik olan trafiği gölgede bırakabilir.
Bu sorunu çözmek için, her birinin iyi bir şekilde desteklenmesini sağlamak amacıyla trafiği kullanım senaryosu gereksinimlerine göre gruplandırıyoruz. Kafka’da uçtan uca gecikme süresi ile verim arasındaki denge, yeni kullanım senaryoları oluştururken dikkate alınması gereken başlıca hususlardan biridir. Bu durum, üreticiden sunucuya ve oradan da tüketiciye uzanan veri yolu boyunca geçerlidir: Bunların her birinde, verim veya gecikme süresinden birini optimize etmek üzere ayarlanabilen yapılandırmalar bulunur. İstemci tarafındaki yapılandırmalar her bir kullanım senaryosuna göre ayarlanabilir, ancak sunucu tarafındaki yapılandırmalar daha az esnektir; zira her bir farklı kullanım senaryosu için ayrı bir küme bulundurmak mümkün değildir.
Her bir kümeyi, yığın boyunca hizmet verdiği kullanım senaryolarına göre optimize etme yaklaşımını donanım katmanına kadar uyguluyoruz.
Donanım Hâlâ Kritik Önem Taşıyor
Başlangıçta Kafka’yı RAID10 HDD makinelerinde çalıştırıyorduk. Trafik hacmi arttıkça, makinelerimizin disk I/O kapasitesi, sunucu başına Kafka verimini sınırlayan başlıca darboğaz haline geldi. Bunu çözmek için iki optimizasyon yaptık. Broker’ları mümkün olduğunca SSD kullanacak şekilde dönüştürdük; böylece darboğazı disk I/O kapasitesinden ağ verimine veya disk alanına kaydırdık (çünkü satın aldığımız SSD’lerin disk alanı daha azdı). Bu, disk I/O verimini 10 kat artırdı. Ayrıca kalan HDD’lerimizi RAID10’dan RAID0’a dönüştürmeye başladık. RAID0’da her yazma işlemi iki disk yerine tek bir diske yazma gerektirdiğinden, bu işlem disk I/O kapasitesini yaklaşık iki katına çıkardı.
Bunun getirdiği dezavantaj ise, her mesaj kopyasının broker başına iki disk yerine tek bir diske yazılması nedeniyle, RAID10’dan RAID0’a geçişin güvenilirlik riski taşıyabilmesidir. Güvenilirliği korumak için, onay sayısını ve veri çoğaltmasını artırmaya yönelik önemli kullanım senaryoları üzerinde çalıştık; buna birden fazla bölgeye çoğaltma da dahildi.
Her makinenin depolama ve verim kapasitelerinden tam olarak yararlanmak için ek çalışmalar yapmamız gerekti. Kafka’nın mesajları arabelleğe alabilmesi ve okumaları ya da güncel verileri bellekten sunabilmesi, yalnızca geçmiş verileri okurken olduğu gibi gerekli olduğunda diske başvurup değerli IOPS’leri tüketmesi için bellek tahsislerimizi ve sayfa önbelleği yönetimi yapılandırmalarımızı optimize ettik.
Ayrıca, donanım sınırlarını anlamak ve hangi yazılım düzeyindeki sınırları belirlememiz gerektiğini tespit etmek için performans karşılaştırmaları da yaptık. Uygulamada bu, kümelerin üzerinde çalıştığı donanıma göre değişen Kafka broker okuma ve yazma sınırlamalarını ayarlamak anlamına gelir. SSD makinelerimiz broker başına daha yüksek verim sağlayabilirken, HDD makinelerimiz geçmiş verilerin uzun süreli saklanmasını gerektiren kullanım senaryoları için daha uygundur.
Güvenilirlik Odaklı Tasarım
Kuyruk platformu, Roblox altyapısının kritik bir bileşenidir ve güvenilirliği korumak hayati önem taşır. Lansman öncesi testlerin yanı sıra devam eden arıza senaryosu testleri (bazen “oyun günü tatbikatları” olarak da adlandırılır), altyapımızın tek bir ana bilgisayar arızası, raf arızası, ağ sorunları ve diğer birçok arıza durumuna karşı dayanıklı olduğunu doğrulamada önemli bir rol oynamıştır. Güvenilirlik ekibimizin dahili kaos test platformu, çeşitli arıza senaryolarını simüle etme sürecini mümkün kılmış ve kolaylaştırmıştır. Bu testler, sistemdeki iyileştirmeleri veya gerilemeleri tespit etmeye yardımcı olur ve uyarıları düzenli olarak doğrulayarak, operatörlerin çeşitli sorunları (nadir görülenler dahil) ele alma adımlarına aşina olmalarını sağlayarak operasyonel mükemmelliği geliştirir.
Ayrıca, bağımlı kullanım senaryoları için kuyruk işlevselliğini hızla geri yükleyebilen yedekleme süreçleri tasarladık ve hayata geçirdik. Tek bir kümenin tamamen arızalanması durumunda bile, istemcileri yeterli kapasiteye sahip sağlıklı bir kümeye geçirebiliyoruz. Yeterli miktarda kullanılmamış kapasiteye sahip olduğumuzdan emin olmak için bir yedek Kafka kümesi bulunduruyoruz. Bu, aktif kümeler arasında trafik aktarımı yapılırken “gürültülü komşu” sorunları riskini ortadan kaldırmaya yardımcı olur.
Aşağıdaki şema, bir yedekleme işleminin yürütülmesine ilişkin genel adımları göstermektedir. İlk olarak, bir operatör yedekleme işleminin kapsamını belirler. Ardından, otomatik bir toplu işlemle yedek küme üzerinde konular ve erişim kontrol listeleri (ACL’ler) oluşturulur. Son olarak, operatör kontrol düzlemi hizmet yapılandırmalarımızı günceller; istemciler, yeniden bağlanmanın gerekip gerekmediğini belirlemek için bu yapılandırmaları sorgular. Aşağıdaki şema, genel gerçek zamanlı kullanım senaryoları içindir. Mirror Maker 2 kullanılarak konu yansıtma, veri geriye doldurma araçları ve daha fazlası dahil olmak üzere diğer kullanım durumları ve senaryolar için ek stratejilerimiz ve araçlarımız bulunmaktadır.

Roblox, güvenilirliğin de kritik bir parçası olan güvenlik konusunda katı gerekliliklere sahiptir. Aktarım sırasında şifreleme (mTLS ile), depolama sırasında şifreleme (şifreli disk ile), veri saklama süresi gereklilikleri ve Kafka ilkeleri ile ACL’ler aracılığıyla kimlik doğrulama/yetkilendirme gibi standart güvenlik özelliklerini uyguladık. Ayrıca, güvenliği daha da artırmak için kullanıcılarımızın kimlik bilgilerini otomatik olarak değiştiriyoruz.
Bunun yanı sıra, hızlı işletim sistemi yamalama ve raf boşaltma işlemlerini kolaylaştırmak için kontrol düzlemimizde özel bir işleme sistemi oluşturduk. İşletim sistemi yamalama sırasında, yamalanmış makinelerin Kafka kümesine yeniden katıldıktan sonra hızla sağlıklı duruma dönebilmesi için verileri diskte tutuyoruz. Bu sayede, filomuz büyümeye devam etse bile 30 gün içinde tüm filomuza yama uygulayabiliyoruz. Cruise Control gibi araçlarla, verilerimizi raf bazında çoğaltıyoruz; böylece veri kullanılabilirliğini etkilemeden bakım ve ağ yamalaması için rafların tamamı çevrimdışı hale getirilebiliyor.
Önümüzdeki Yol
Kuyruk platformumuzun bir sonraki aşaması, esnekliği ve izolasyonu geliştirmeye devam ederken platformu geliştiriciler için daha da basit hale getirmektir. Üretici ve tüketici proxy'leri ile tam olarak yönetilen konektörler dahil olmak üzere yeni soyutlamalara yatırım yapıyoruz. Bu sistemler, uygulama ekiplerini altyapı karmaşıklığından daha da bağımsız hale getirecek ve platformlarımızın büyük ölçekte benimsenmesini ve yönetilmesini kolaylaştıracaktır. Örneğin, bir tüketici proxy'si "rekabetçi tüketici" modelini mümkün kılacak; bu sayede platform daha geniş bir kullanım senaryosu yelpazesini destekleyebilecek ve işlemcilerin ölçeklendirilmesini Kafka bölümlerinin ölçeklendirilmesinden ayırabilecektir. Bu, sıralama gerektirmeyen ve uçtan uca teslimat hedeflerine ulaşma zorunluluğu olmaksızın işlemci sayısını geçici olarak artırmanın faydalı olabileceği, kitlesel bildirim patlamalarının işlenmesi gibi kullanım senaryoları için değerlidir.
Kafka’yı ölçeklendirmek, sadece kümelerin sayısını ve boyutunu artırmakla ilgili değildir. Bu, Roblox’un her gün bir milyar insanı iyimserlik ve nezaketle birbirine bağlama yolculuğuna devam etmesini sağlayan mühendislik disiplinini, soyutlamaları ve operasyonel modeli oluşturmakla ilgilidir.
Teşekkürler: Roblox kuyruk platformuna yaptıkları önemli katkılarından dolayı Danny Yuan ve George Li'ye teşekkür ederiz.


