Bir uygulamayı Redis'e bağlamanın en kısa yolu bir bağlantı URL'si kullanmaktır: redis://default:şifre@sunucu:6379/0. Şema redis ise düz TCP, rediss ise TLS kullanılır; ardından kullanıcı adı, şifre, sunucu, port ve isteğe bağlı veritabanı numarası gelir. Ancak resmî belgeler önemli bir uyarı yapar: bu temel biçim dışında kalan her şey, yani zaman aşımı ayarları, TLS seçenekleri, RESP sürümü ve sorgu parametreleri istemci kütüphanesine göre değişir. Bağlantıyı kurduktan sonra ikinci karar, bağlantıların nasıl yönetileceğidir: kütüphaneler bunun için bağlantı havuzu (connection pool) ya da çoğullama (multiplexing) kullanır. Üçüncü konu da bağlantı koptuğunda veya komut hata verdiğinde ne yapacağınızdır.

Bu yazı, dile bağlı olmayan bu ortak katmanı ele alıyor: taşınabilir bir URL nasıl yazılır, hangi istemci URL'nin hangi parçasını nasıl yorumlar, havuz ile çoğullama arasındaki fark nedir ve hatalar hangi kategorilere ayrılıp nasıl ele alınır. Kütüphaneye özgü ayrıntılar için redis-py, node-redis, Predis, go-redis ve Jedis ile Lettuce yazılarına geçebilirsiniz. Serinin tamamı için Redis öğrenme rehberi sayfasına bakabilirsiniz; Redis'in ne olduğunu ve kurulumunu ise Redis nedir yazısında bulursunuz.

Redis bağlantı URL'sinin biçimi

Redis bağlantı URL'sinin biçimi: redis veya rediss, kullanıcı adı, şifre, sunucu

Belgelerde verilen temel biçim aşağıdadır. Köşeli parantez içindeki her parça isteğe bağlıdır. redis ve rediss şemaları IANA'da geçici (provisional) olarak kayıtlıdır; yani resmî bir standart değildir. Bu kayıt da yalnızca temel biçimi tanımlar ve sorgu parametrelerinin uygulamaya özgü olduğunu, istemciler arasında taşınamayacağını açıkça söyler.

text
redis[s]://[[<kullanıcı>][:<şifre>]@][<sunucu>][:<port>][/<veritabanı-no>]

redis://default:sifre@10.0.0.5:6379/0      # düz TCP
rediss://default:sifre@redis.ornek.com:6379/2  # TLS, 2 numaralı veritabanı
ParçaAnlamıVarsayılan
redis veya redissredis düz TCP, rediss TLS bağlantısızorunlu
kullanıcı adıACL kimlik doğrulaması için kullanıcıdefault
şifreKimlik doğrulama şifresikimlik doğrulama yok
sunucuAna makine adı veya IP; IPv6 köşeli parantezle yazılır, örneğin [::1]localhost
portSunucunun portu6379
veritabanı noSeçilecek mantıksal veritabanı0

Kullanıcı adı alanı doğrudan Redis'in ACL sistemine karşılık gelir. Kullanıcıları ve yetkileri nasıl tanımlayacağınızı Redis ACL yazısında anlatıyoruz. Burada bilmeniz gereken, kullanıcı adı yazılmadığında istemcinin default kullanıcısını varsaydığıdır.

Her istemcide aynı çalışan URL yazma kuralları

Aynı URL'yi birden fazla servis okuyorsa, örneğin Python ile yazılmış bir API ve Go ile yazılmış bir arka plan işçisi aynı ortam değişkenini kullanıyorsa, URL'nin her iki kütüphanede de aynı anlama gelmesi gerekir. Belgeler bunun için şu kuralları önerir:

  • Şemayı küçük harfle yazın. Lettuce, Predis ve senkron redis-py REDIS:// biçimini reddeder; ioredis ise TLS'yi yalnızca küçük harfli rediss:// gördüğünde açar.
  • Portu her zaman yazın. Jedis portsuz bir URL'yi kabul etmez.
  • Şifreyle birlikte kullanıcı adını da yazın. redis://default:şifre@sunucu:6379 her yerde aynı anlamdadır. redis://:şifre@sunucu biçimi de her istemcide "yalnızca şifre" olarak okunur. Asıl sorun iki nokta üst üste olmadan yazılan redis://değer@sunucu biçimindedir.
  • Kullanıcı adı ve şifredeki özel karakterleri yüzde kodlamasıyla yazın. @, :, /, ?, #, % ve + gibi URL'de anlamı olan karakterler kodlanmalıdır.
  • Veritabanını sorgu parametresiyle değil, yolla seçin. redis://sunucu:6379/2 her istemcide 2 numaralı veritabanını seçer; ?db= parametresi bazı istemcilerde yok sayılır, bazılarında başka bir adla geçer.
  • Birden fazla istemcinin okuduğu URL'ye sorgu parametresi koymayın.
  • Aynı ayarı hem URL'de hem kodda vermeyin. İstemciler hangisinin öncelikli olduğu konusunda anlaşmaz.

İki nokta üst üste olmadan yazılan biçimin istemcilere göre nasıl okunduğu aşağıdaki tabloda. Aynı URL bir kütüphanede kullanıcı adı, diğerinde şifre olarak yorumlanıyor; bu da kimlik doğrulama hatasının kaynağını bulmayı zorlaştırır.

İstemciredis://değer@sunucu biçimindeki değer
redis-py, node-redis, ioredis, go-redis, redis-rs, PredisŞifresiz kullanıcı adı
Lettuce, redis-rbŞifre
JedisHata

Tanımadığı bir sorgu parametresiyle karşılaşan istemcilerin davranışı da üç gruba ayrılır. Bu yüzden bir kütüphanede sorunsuz çalışan ?timeout=5 gibi bir ek, başka bir kütüphanede hiçbir etki yapmayabilir ya da bağlantıyı tamamen engelleyebilir.

Bilinmeyen parametreye tepkiİstemciler
Yok sayılırnode-redis, Jedis, Lettuce, redis-rs, redis-rb
İstemciye seçenek olarak geçirilirredis-py, ioredis, Predis
Hata verirgo-redis

Örnek: özel karakterli şifreyle taşınabilir URL

Diyelim ki uygulamanızın ACL kullanıcısı uygulama, şifresi p@ss:w+rd, sunucu 10.0.0.5 ve 2 numaralı veritabanını TLS ile kullanmak istiyorsunuz. Şifredeki @, : ve + karakterleri kodlanmadan yazılırsa istemci @ işaretini kullanıcı bilgisinin bittiği yer sanar. Belgelerdeki örneğe göre bu şifre p%40ss%3Aw%2Brd olur. Sonuç şöyle görünür:

text
rediss://uygulama:p%40ss%3Aw%2Brd@10.0.0.5:6379/2

Bu URL kuralların hepsine uyar: şema küçük harf, port yazılı, kullanıcı adı şifreyle birlikte, şifre kodlanmış, veritabanı yolda ve sorgu parametresi yok. Belgeler iki istisna belirtir: Predis kullanıcı adı ve şifredeki yüzde kodlamasını çözmez, redis-rb ise şifredekini çözer ama kullanıcı adındakini çözmez. Predis kullanıyorsanız özel karakterli şifreyi adres yerine kodlanmış bir password sorgu parametresiyle vermeniz önerilir; ayrıntısı Predis yazısında.

İstemcilere göre URL desteği

Aşağıdaki tablo belgelerdeki özet tablonun Türkçe hâlidir. URL'yi kabul eden giriş noktası, desteklenen şemalar, Unix soketi yazımı, veritabanının sorgu parametresiyle verilip verilemeyeceği ve RESP sürümünün URL'den seçilip seçilemeyeceği her kütüphanede farklıdır.

İstemciURL giriş noktasıŞemalarVeritabanı sorgudaRESP sürümü sorguda
redis-pyredis.from_url()redis, rediss, unix?db=?protocol=2 veya 3
node-rediscreateClient({ url })redis, rediss, unixyalnızca Unix soketindedesteklenmez
ioredisnew Redis(url)redis, rediss?db=desteklenmez
JedisRedisClient.create(url)redis, redissdesteklenmez?protocol=2 veya 3
LettuceRedisURI.create(url)redis, rediss, redis-socket, redis-sentinel ve diğerleri?database= veya ?db=desteklenmez
go-redisredis.ParseURL()redis, rediss, unix?db=?protocol=2 veya 3
Predisnew Predis\Client(url)redis, rediss, tcp, tls, unix?database=?protocol=3
StackExchange.RedisURL kabul etmez---

Belgelerdeki kısa örneklerle URL'nin her dilde nasıl verildiğini görelim. Hepsinde aynı temel biçim kullanılıyor; değişen yalnızca URL'yi alan fonksiyon:

python
import redis

r = redis.from_url("rediss://default:<password>@<host>:6379/0?protocol=3")
javascript
import { createClient } from 'redis';

const client = createClient({
  url: 'rediss://default:<password>@<host>:6379/0'
});
go
opt, err := redis.ParseURL("rediss://default:<password>@<host>:6379/0?protocol=3")
if err != nil {
    panic(err)
}

client := redis.NewClient(opt)
java
// Jedis
RedisClient jedis = RedisClient.create("rediss://default:<password>@<host>:6379/0");

// Lettuce
RedisClient client = RedisClient.create("rediss://default:<password>@<host>:6379/0");
php
$client = new Predis\Client('rediss://default:<password>@<host>:6379/0');

rediss şeması TLS'yi açar, fakat çoğu istemcide sertifika dosyalarını yalnızca kod içinden ayarlayabilirsiniz. Yani URL TLS'nin açık olduğunu söyler, CA sertifikası ve istemci sertifikası gibi ayrıntılar ise kütüphanenin TLS seçeneklerinde verilir.

Kütüphanelere özgü URL tuzakları

Kütüphanelere özgü URL tuzakları: redis-py, node-redis, ioredis, Jedis

Belgelerin her istemci için ayrı ayrı listelediği ayrıntılar arasında, gerçek projelerde en çok karşılaşılacak olanlar şunlar:

  • redis-py: Sorgu parametreleri bağlantıya anahtar sözcük argümanı olarak geçer. socket_timeout, socket_connect_timeout, health_check_interval, protocol gibi tanıdığı parametrelerin tipini çevirir, diğerlerini metin olarak geçirir. Bu nedenle ?decode_responses=False yazmak "False" metnini geçirir ve Python boş olmayan metni doğru kabul ettiği için ayar tersine işler. Böyle mantıksal seçenekleri kodda verin. Hem ?db= hem yol verilirse ?db= kazanır.
  • node-redis: redis:// ve rediss:// URL'lerindeki tüm sorgu parametrelerini yok sayar; RESP gibi ayarları seçenek nesnesinde verirsiniz. URL'deki kullanıcı adı, şifre ve veritabanı, seçeneklerde verilenleri geçersiz kılar.
  • ioredis: Tanımadığı şemaları reddetmez; redis:// ile başlamayan her metnin başına redis:// ekler. Bu yüzden unix:///tmp/redis.sock adı unix olan bir sunucu gibi okunur. Unix soketi için şemasız yol verilir.
  • Jedis: Port zorunludur, tek sorgu parametresi protocol'dür ve db dahil diğerleri yok sayılır. Veritabanı numarasından sonra eğik çizgi koymayın; Jedis redis://sunucu:6379/1/?protocol=3 biçimini çözümleyemez.
  • Lettuce: timeout parametresi birim eki alabilir (örneğin 10s), ek yoksa milisaniye sayılır. database veya db parametresi yoldaki numaradan önceliklidir.
  • go-redis: Sorgu parametreleri dial_timeout, read_timeout, pool_size gibi yılan biçimli adlarla redis.Options alanlarını ayarlar. Tanımadığı her parametre için ParseURL() hata döndürür. skip_verify=true yalnızca rediss URL'sinde geçerlidir.
  • Predis: Veritabanı parametresinin adı db değil database'dir. Kimlik bilgilerini ve veritabanını adresten yalnızca redis ve rediss şemalarında okur; tcp, tls ve unix için sorgu parametreleri kullanılır.
  • StackExchange.Redis (.NET): URL kabul etmez; virgülle ayrılmış kendi yapılandırma metnini kullanır. ssl=true verip portu yazmazsanız varsayılan port 6379 değil 6380 olur ve değerlerde virgülü kaçırmanın bir yolu yoktur.

Bağlantı havuzu ve çoğullama farkı

Belgelerdeki örnek kodlar genellikle bir bağlantı açar, bir komut gösterir ve bağlantıyı kapatır. Gerçek uygulamalar ise kısa iletişim anları ile boşta beklenen aralıklardan oluşur. Her istekte bağlantı açıp kapatmak ek yük getirir; bu yüzden üretimde mümkün olduğunca az sayıda ayrı bağlantı kullanmak performansı iyileştirir. Kütüphaneler bunu iki yolla sağlar.

Bağlantı havuzu başlatıldığında birkaç bağlantı açıp havuza koyar. Kodunuz bir bağlantı "açtığında" havuz mevcut bağlantılardan birini verir ve onu kullanımda olarak işaretler. Bağlantıyı "kapattığınızda" gerçekte kapanmaz, yeniden kullanılmak üzere havuza döner. Havuzdaki bağlantıların hepsi meşgulse istemci gerektikçe yeni bağlantı açar; böylece zamanla uygulamanın ihtiyacına uygun bağlantı sayısına ulaşılır. Belgelere göre redis-py, Jedis ve go-redis havuz kullanır.

Çoğullama (multiplexing) ise tek bir bağlantıyı açık tutar ve istemci ile sunucu arasındaki tüm trafiği onun üzerinden geçirir. Kodunuza verilen "bağlantılar" yalnızca hangi yanıtın kime gideceğini belirlemeye yarar. Çoğullayıcı birbirine yakın zamanda gelen komutları çoğu zaman bir pipeline hâlinde birleştirebilir, bu da verimliliği artırır. StackExchange.Redis çoğullama kullanır; Lettuce iki yaklaşımı da destekler.

ÖzellikBağlantı havuzuÇoğullama
Sunucuya açılan bağlantıBirkaç tane, ihtiyaca göre artarTek bağlantı
Uygulama kodunda değişiklikHavuzdan al, işi bitince bırakÖzel kod gerektirmez
Engelleyen komutlar (BLPOP vb.)Desteklenir, yalnızca o bağlantı beklerUygun değil, tüm çağıranları durdurur
Belgelerdeki örnek istemcilerredis-py, Jedis, go-redisStackExchange.Redis; Lettuce ikisini de destekler

Çoğullamanın temel dezavantajı tabloda görülüyor: BLPOP gibi engelleyen pop komutları tek paylaşılan bağlantıyı kilitleyeceği için tüm çağıranları bekletir. Uygulamanızda kuyruk dinleyen engelleyen komutlar varsa ya havuz kullanan bir istemci seçin ya da bu iş için ayrı bir bağlantı ayırın. Pub/Sub aboneliği de benzer şekilde bağlantıyı başka komutlara kapatır; bunun ayrıntısı Pub/Sub yazısında.

Redis istemci hatalarının dört kategorisi

Belgeler istemci tarafında karşılaşılan hataları dört ana gruba ayırır. Her grubun ne zaman ele alınması gerektiği farklıdır; asıl beceri, hatayı doğru gruba koyabilmektir.

KategoriTipik nedenlerNe zaman ele alınırÖrnekler
Bağlantı hatalarıAğ sorunu, sunucu kapalı, kimlik doğrulama, zaman aşımı, havuzun tükenmesiNeredeyse her zamanConnectionError, TimeoutError, AuthenticationError
Komut hatalarıKomut adında yazım hatası, yanlış argüman, yanlış tip, sürümde olmayan komutNadiren, genelde koddaki hatadırResponseError, WRONGTYPE, ERR unknown command
Veri hatalarıSerileştirme hatası, bozuk önbellek verisiBazen, veri kaynağına bağlıJSONDecodeError, SerializationError
Kaynak hatalarıBellek sınırı, havuz tükenmesi, çok fazla bağlantıBazen, bir kısmı geçicidirOOM, havuz zaman aşımı, LOADING

Bağlantı hataları çoğunlukla geçicidir; yeniden deneme ya da yedek veri kaynağına dönme mantıklıdır. Komut hataları ise çoğu zaman koddaki bir hatayı gösterir ve onları çalışma anında yakalamaya çalışmak yerine kodu düzeltmek gerekir. Kaynak hatalarından LOADING (sunucunun veri setini belleğe yüklüyor olması) kısa bir beklemeden sonra kendiliğinden geçer, bellek dolması ise yapılandırma sorununa işaret eder. Sunucu mesajlarının anlamını Redis hata mesajları ve OOM, MISCONF ve READONLY hataları yazılarında tek tek açıklıyoruz; bağlantı sınırına takılan istemciler için CLIENT LIST ve bağlantı yönetimi yazısına bakabilirsiniz.

Dört hata yönetimi deseni

Dört hata yönetimi deseni: Hızlı başarısız ol (fail fast), Zarif gerileme (graceful degradation), Bekleme süresini artırarak yeniden dene (retry with backoff), Kaydet ve devam et...

Belgeler bu kategorilere karşılık dört desen önerir. Örnekler belgelerde Python ile verilmiştir; aynı mantık her dile uygulanır.

  • Hızlı başarısız ol (fail fast): Hata kurtarılamazsa ya da koddaki bir hatayı gösteriyorsa yakalayıp yeniden fırlatın. Komut sözdizimi hataları ve kimlik doğrulama hataları bu gruptadır.
  • Zarif gerileme (graceful degradation): Veriyi elde etmenin başka bir yolu varsa ona dönün. Önbellek okumasında veritabanına, oturum okumasında varsayılan değerlere dönmek tipik örneklerdir.
  • Bekleme süresini artırarak yeniden dene (retry with backoff): Zaman aşımı, geçici ağ sorunu ya da sunucunun veri yüklüyor olması gibi geçici durumlarda kullanılır.
  • Kaydet ve devam et (log and continue): İşlem kritik değilse hatayı kaydedip uygulamayı sürdürün. Önbelleğe yazma ve metrik toplama bu gruptadır.

Zarif gerileme deseninde önbellek erişilemezse uygulama hata vermek yerine veritabanına gider:

python
try:
    cached_value = r.get(key)
    if cached_value:
        return cached_value
except redis.ConnectionError:
    logger.warning("Cache unavailable, using database")

# Fallback to database
return database.get(key)

Yeniden deneme deseninde her denemeden sonra bekleme süresi ikiye katlanır ve son denemede hata yukarı fırlatılır:

python
import time

max_retries = 3
retry_delay = 0.1

for attempt in range(max_retries):
    try:
        return r.get(key)
    except redis.TimeoutError:
        if attempt < max_retries - 1:
            time.sleep(retry_delay)
            retry_delay *= 2  # Exponential backoff
        else:
            raise

Belgelerdeki karar ağacı da şöyle özetlenebilir: bağlantı hatasında okuma işlemiyse gerileme, yazma işlemiyse kaydedip devam etme ya da yeniden deneme, kritik bir işlemse yeniden deneme uygulanır. Komut hatası kullanıcı girdisinden geliyorsa kaydedilip kullanıcıya hata döndürülür, sizin kodunuzdan geliyorsa hızlı başarısız olunur. Veri hatasında okumada kaydı silip kaynaktan yeniden okumak, yazmada ise işlemi başarısız saymak önerilir. Kaynak hatasında sunucu yükleme yapıyorsa beklenip yeniden denenir, havuz tükendiyse havuz büyütülür, bellek dolduysa yapılandırma incelenir.

Ne kaydedilmeli, ne izlenmeli

Hata kaydına hatanın tipini ve mesajını, bağlamı (hangi anahtar, hangi işlem), zaman damgasını ve bunun kaçıncı deneme olduğunu yazmak, sorunu sonradan anlamayı kolaylaştırır. İzleme tarafında ise dakikadaki hata sayısı, en sık görülen hata tipleri, yeniden denemelerin ne kadarının başarılı olduğu ve yedek yolun ne sıklıkla kullanıldığı takip edilmeye değer.

Bu metrikleri elle toplamak zorunda da değilsiniz. Belgelere göre redis-py, go-redis ve node-redis OpenTelemetry desteği sunar. İstemci metrikleri OTLP ile bir toplayıcıya (collector) gönderir, Prometheus gibi bir depolama katmanı onları çeker ve Grafana gibi bir araç görselleştirir. Metrikler resiliency, connection-basic, connection-advanced, command, client-side-caching, streaming ve pubsub gruplarına ayrılır; varsayılan olarak yalnızca resiliency ve connection-basic grupları açıktır.

Sık yapılan hatalar

  • Tüm istisnaları tek blokta yakalamak. except Exception gibi geniş bir yakalama koddaki gerçek hataları da gizler. Belgeler belirli istisna tiplerini yakalamayı önerir.
  • Hata türlerini ayırt etmemek. Sözdizimi hatasını yeniden denemek işe yaramaz. Zaman aşımında yeniden deneyin, yanıt hatasında hızlı başarısız olun.
  • Havuz hatalarını görmezden gelmek. Havuz tükenmesi bir yapılandırma ya da eşzamanlılık sorunudur; havuz kullanımını izleyip gerekirse boyutunu artırın.
  • Aynı ayarı iki yerde vermek. URL'de /2, kodda db=0 yazarsanız hangisinin geçerli olacağı kütüphaneye göre değişir.
  • Her istekte yeni istemci oluşturmak. Bu, havuzun amacını boşa çıkarır ve her çağrıda bağlantı kurma maliyeti ödenir. Uygulama açılışında bir istemci oluşturup paylaşın.

İstemci kütüphanelerinin desteklenme biçimi de seçimi etkiler. Belgelere göre Predis ve redis-rs Redis ekibinden "en iyi çaba" (best effort) düzeyinde destek alan üçüncü taraf kütüphanelerdir. Resmî istemcilerde ise önerilen yol en son major.minor sürümü kullanmak, sürüm notlarındaki test matrisini okumak ve büyük sürüm geçişlerini üretime benzer yük altında denemektir.

Sık Sorulan Sorular

URL'de veritabanını nasıl seçmeliyim?

Yolla seçin: redis://sunucu:6379/2. Belgelere göre bu biçim her istemcide 2 numaralı veritabanını seçer. ?db= parametresi bazı istemcilerde yok sayılır, Predis'te ise adı database'dir. Jedis'te numaradan sonra eğik çizgi koymamaya dikkat edin.

Şifremde @ ya da : var, URL bozuluyor. Ne yapmalıyım?

Özel karakterleri yüzde kodlamasıyla yazın; p@ss:w+rd şifresi p%40ss%3Aw%2Brd olur. Predis adresteki kodlamayı çözmediği için orada şifreyi kodlanmış password sorgu parametresiyle vermek gerekir.

Havuz mu çoğullama mı seçmeliyim?

Çoğu durumda bu kararı kütüphane verir: redis-py, Jedis ve go-redis havuz, StackExchange.Redis çoğullama kullanır. Lettuce'ta ikisi de mümkündür. Engelleyen komutları yoğun kullanıyorsanız havuz daha uygundur, çünkü çoğullanan tek bağlantıda böyle bir komut herkesi bekletir.

URL ile TLS sertifikası verebilir miyim?

rediss şeması TLS'yi açar ama çoğu istemci sertifikaları yalnızca kod içinden kabul eder. redis-py ssl_cert_reqs ve ssl_check_hostname parametrelerini, Predis ssl[cafile] gibi parametreleri URL'de kabul eder; bunlar taşınabilir değildir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Redis öğrenme rehberi · redis-py kullanımı · node-redis kullanımı · go-redis kullanımı · Redis ACL · Redis hata mesajları