Redis’te anahtarları listelemenin iki yolu vardır: KEYS desen eşleşen bütün anahtarları tek seferde döndürür ama bunu yaparken sunucuyu bloklar; SCAN imleç ise anahtar uzayını her çağrıda küçük bir parça döndürerek adım adım gezer ve üretim sunucusunda güvenle kullanılabilir. Kısacası KEYS hata ayıklama ve özel bakım işleri içindir, uygulama kodunda anahtar aramak için SCAN kullanılır. SCAN’in bedeli daha zayıf garantilerdir: aynı anahtar birden fazla kez dönebilir ve tarama sırasında eklenip silinen anahtarlar için sonuç belirsizdir.
Bu yazıda iki komutun nasıl çalıştığını, SCAN’in garantilerini, MATCH, COUNT ve TYPE seçeneklerini, aynı mantıkla çalışan SSCAN, HSCAN, ZSCAN komutlarını ve redis-cli --scan kullanımını resmî belgelere göre anlatıyoruz. Anahtar adlandırma için anahtar isimlendirme ve keyspace, serinin geneli için Redis öğrenme rehberi yazısına bakın.
KEYS nasıl çalışır ve neden riskli?
![KEYS nasıl çalışır ve neden riskli? h?llo, h*llo, h[ae]llo, h[^e]llo](/assets/blog/redis-scan-ve-keys-farki-b1.webp)
KEYS tek bir glob deseni alır ve eşleşen bütün anahtar adlarını bir dizi olarak döndürür. Belgedeki örnek:
> MSET firstname Jack lastname Stuntman age 35
OK
> KEYS *name*
1) "lastname"
2) "firstname"
> KEYS a??
1) "age"
> KEYS *
1) "age"
2) "lastname"
3) "firstname"Komutun karmaşıklığı O(N)’dir, yani veritabanındaki anahtar sayısıyla doğru orantılıdır. Belge sabit maliyetin düşük olduğunu, giriş seviyesi bir dizüstü bilgisayarda çalışan Redis’in 1 milyon anahtarlık bir veritabanını 40 milisaniyede taradığını söyler. Sorun şudur: belgeye göre KEYS, bütün anahtarlar dönene kadar Redis sunucusunu bloklar; bu sürede diğer istemcilerin komutları bekler. Anahtar sayısı arttıkça bu süre uzar ve bütün uygulama bu süre boyunca bekler.
KEYS ve SCAN ... MATCH aynı glob desen sözdizimini kullanır:
h?llo: tek bir karakter;hello,hallovehxlloile eşleşir.h*llo: sıfır veya daha fazla karakter;hlloveheeeelloile eşleşir.h[ae]llo: köşeli parantezdeki karakterlerden biri;hellovehalloile eşleşir,hilloile eşleşmez.h[^e]llo: parantezdeki karakter dışında biri;hallo,hblloile eşleşir,helloile eşleşmez.h[a-b]llo: aralıktaki bir karakter;hallovehblloile eşleşir.
Bu özel karakterlerden birini olduğu gibi aramak isterseniz önüne ters eğik çizgi (\) koyarsınız.
SCAN temel kullanımı: imleçle adım adım tarama
SCAN imleç (cursor) tabanlı bir yineleyicidir. Her çağrıda sunucu güncellenmiş bir imleç döndürür ve bir sonraki çağrıda bu imleci vermeniz gerekir. Tarama imleç 0 ile başlar ve sunucu imleç olarak yeniden 0 döndürdüğünde biter. 0 ile başlayıp 0 dönene kadar yapılan bu çağrılar dizisine tam yineleme (full iteration) denir. Belgedeki örnekte iki çağrıda bütün anahtarlar gezilir:
> scan 0
1) "17"
2) 1) "key:12"
2) "key:8"
3) "key:4"
4) "key:14"
5) "key:16"
6) "key:17"
7) "key:15"
8) "key:10"
9) "key:3"
10) "key:7"
11) "key:1"
> scan 17
1) "0"
2) 1) "key:5"
2) "key:18"
3) "key:0"
4) "key:2"
5) "key:19"
6) "key:13"
7) "key:6"
8) "key:9"
9) "key:11"Yanıt iki elemanlı bir dizidir: ilk eleman bir sonraki çağrıda kullanılacak imleçtir (işaretsiz 64 bitlik bir sayıyı temsil eden string), ikinci eleman ise bu çağrıda dönen anahtarların dizisidir. İkinci çağrıda imleç 0 döndüğü için tarama tamamlanmıştır. Örneklerde görüldüğü gibi imleç artarak gitmez; değerini yorumlamaya çalışmadan bir sonraki çağrıya aynen aktarırsınız.
Uygulama kodunda tarama döngüsü şöyle kurulur: imleci 0 yapın; SCAN çağırın; dönen anahtarları işleyin; dönen imleci saklayın; imleç 0 değilse tekrar çağırın. Döngüyü bitiren tek koşul imlecin 0 dönmesidir. İstemci kütüphanelerinin çoğu bu döngüyü sizin yerinize kuran yardımcılar sunar; dil yazılarımızda redis-py ve go-redis örneklerine bakabilirsiniz.
SCAN garantileri ve sınırları
SCAN sunucu tarafında hiçbir durum tutmaz; bütün durum imleçtedir. Bu tasarım, garantileri de belirler. Belgeye göre tam bir yineleme şunları garanti eder:
- Yinelemenin başından sonuna kadar koleksiyonda bulunan her eleman en az bir kez döndürülür.
- Yinelemenin başından sonuna kadar koleksiyonda hiç bulunmamış bir eleman asla döndürülmez. Tarama başlamadan silinmiş ve geri eklenmemiş bir anahtar sonuçta görünmez.
Buna karşılık iki dezavantaj vardır:
- Aynı eleman birden fazla kez dönebilir. Tekrarları ayıklamak uygulamanın işidir; ya sonuçları bir kümede biriktirin ya da yapacağınız işlemi tekrar uygulandığında zarar vermeyecek şekilde tasarlayın.
- Tarama sırasında eklenen veya silinen, yani yineleme boyunca sürekli var olmayan elemanların dönüp dönmeyeceği belirsizdir.
Ayrıca her çağrının kaç eleman döndüreceği garanti edilmez. Bir çağrı hiç eleman döndürmeyebilir; imleç 0 olmadığı sürece tarama bitmemiştir. Yaygın bir hata, boş bir sonuç gelince döngüyü durdurmaktır. Sonlanma garantisi de koşulludur: SCAN ancak taranan koleksiyonun boyutu belli bir üst sınırda kalıyorsa sonlanmayı garanti eder. Sürekli büyüyen bir koleksiyonda, büyüme hızı tarama hızını aşarsa tam yineleme hiç bitmeyebilir.
COUNT seçeneği: her çağrıdaki iş miktarı

COUNT, her çağrıda dönecek eleman sayısı için bir sınır değil, sunucunun her çağrıda ne kadar iş yapması gerektiğine dair bir ipucudur. Varsayılan değer 10’dur. Anahtar uzayını ya da hash tablosuyla temsil edilecek kadar büyük bir set, hash veya sorted seti tararken, MATCH kullanılmıyorsa sunucu genellikle COUNT kadar ya da biraz daha fazla eleman döndürür.
Her çağrıda aynı COUNT değerini kullanmanız gerekmez; bir sonraki çağrıya önceki çağrının döndürdüğü imleci verdiğiniz sürece değeri istediğiniz gibi değiştirebilirsiniz. Büyük COUNT değerleri daha az gidiş dönüş ama çağrı başına daha uzun iş anlamına gelir; küçük değerler ise sunucuyu her seferinde daha kısa süre meşgul eder.
Küçük koleksiyonlarda farklı bir durum görürsünüz. Redis, belli bir eleman sayısına veya eleman boyutuna ulaşana kadar küçük set, hash ve sorted setleri tek bir bellek bloğunda sıkıştırılmış biçimde saklar. Bu durumda anlamlı bir imleç yoktur ve SSCAN, HSCAN, ZSCAN bütün elemanları COUNT değerinden bağımsız olarak ilk çağrıda döndürür. Koleksiyon büyüyüp gerçek bir hash tablosuna dönüştüğünde normal davranışa geçilir. Belge, bu durumun yalnızca küçük koleksiyonlarda görüldüğü için karmaşıklığa veya gecikmeye etkisi olmadığını, SCAN komutunun kendisinin ise anahtar uzayı her zaman hash tablosu olduğu için bu davranışı hiç göstermediğini belirtir. Kodlamaları incelemek için bellek kullanımı ve OBJECT ENCODING yazısına bakın.
MATCH seçeneği: desenle filtrelemek
MATCH desen eklediğinizde yalnızca desene uyan elemanlar döner; bu seçenek SCAN ailesinin bütün komutlarında çalışır. Bir set üzerinde örnek:
> sadd myset 1 2 3 foo foobar feelsgood
(integer) 6
> sscan myset 0 match f*
1) "0"
2) 1) "foo"
2) "feelsgood"
3) "foobar"Burada çok önemli bir ayrıntı var: filtre, elemanlar koleksiyondan alındıktan sonra, istemciye gönderilmeden hemen önce uygulanır. Yani MATCH sunucunun yaptığı işi azaltmaz, yalnızca dönen sonucu süzer. Desen az sayıda anahtara uyuyorsa çağrıların çoğu boş dönebilir. Belgedeki örnekte dört çağrının üçü boş döner, son çağrıda COUNT 1000 ile tek seferde çok daha fazla iş yaptırılarak tarama tamamlanır:
> scan 0 MATCH *11*
1) "288"
2) 1) "key:911"
> scan 288 MATCH *11*
1) "224"
2) (empty list or set)
> scan 224 MATCH *11*
1) "80"
2) (empty list or set)
> scan 80 MATCH *11*
1) "176"
2) (empty list or set)
> scan 176 MATCH *11* COUNT 1000
1) "0"
2) 1) "key:611"
2) "key:711"
3) "key:118"
4) "key:117"
5) "key:311"
6) "key:112"
7) "key:111"
8) "key:110"
9) "key:113"
10) "key:211"
11) "key:411"
12) "key:115"
13) "key:116"
14) "key:114"
15) "key:119"
16) "key:811"
17) "key:511"
18) "key:11"Bu örnek, “boş sonuç gelince dur” hatasının neden tehlikeli olduğunu da gösterir: ikinci çağrıda durmuş olsaydınız 18 eşleşen anahtarı kaçırırdınız.
TYPE seçeneği: belirli tipteki anahtarları bulmak
TYPE seçeneği yalnızca belirtilen tipteki anahtarları döndürür ve yalnızca bütün veritabanını tarayan SCAN komutunda bulunur; HSCAN veya ZSCAN gibi komutlarda yoktur. Tip adı, TYPE komutunun döndürdüğü adla aynıdır. Belge bir tuhaflığa dikkat çeker: coğrafi indeksler, HyperLogLog, bitmap ve bitfield gibi bazı yapılar içeride string veya sorted set gibi başka tiplerle kurulduğu için SCAN onları aynı tipteki diğer anahtarlardan ayıramaz:
> GEOADD geokey 0 0 value
(integer) 1
> ZADD zkey 1000 value
(integer) 1
> TYPE geokey
zset
> TYPE zkey
zset
> SCAN 0 TYPE zset
1) "0"
2) 1) "geokey"
2) "zkey"TYPE filtresi de MATCH gibi elemanlar alındıktan sonra uygulanır. Bu yüzden tam bir yinelemenin toplam iş miktarını azaltmaz ve nadir bir tipi ararken birçok çağrının boş dönmesi normaldir.
SSCAN, HSCAN ve ZSCAN: tek bir koleksiyonun içinde gezinmek
Dört komut neredeyse aynı çalışır; fark, ilk argümanın taranacak anahtarın adı olmasıdır. SCAN anahtar adı almaz çünkü taranan nesne veritabanının kendisidir. Dönen dizinin içeriği komuta göre değişir: SSCAN set üyelerini, HSCAN her eleman için alan ve değer çiftini, ZSCAN her eleman için üye ve skor çiftini döndürür.
redis> HMSET hash name Jack age 33
OK
redis> HSCAN hash 0
1) "0"
2) 1) "name"
2) "Jack"
3) "age"
4) "33"HSCAN komutunun NOVALUES seçeneği yalnızca alan adlarını döndürür; komut sayfası bu seçeneğin Redis 7.4 ile geldiğini belirtir. Büyük bir hash’in yalnızca alan adlarına ihtiyacınız varsa değerleri boşuna taşımamış olursunuz. Bu komutlar, büyük koleksiyonlarda bütün elemanları tek seferde döndüren SMEMBERS veya HGETALL gibi komutların engelleyici alternatifidir. Belge, SMEMBERS gibi komutların büyük koleksiyonlarda sunucuyu uzun süre, hatta birkaç saniye bloklayabileceğini belirtir; ama bunun karşılığında koleksiyonun belli bir andaki tam görüntüsünü verdiklerini de not eder.
redis-cli ile anahtar listelemek
Komut satırında anahtarları listelemek için KEYS * yerine redis-cli --scan kullanın. Bu mod arka planda SCAN kullandığı için sunucuyu bloklamaz; aynı nedenle veri değişiyorsa bir anahtar birden fazla kez görünebilir ama taramanın başından beri var olan hiçbir anahtar atlanmaz. --pattern seçeneği desen verir, çıktıyı wc -l komutuna aktararak belirli bir türdeki anahtarları sayabilirsiniz:
$ redis-cli --scan --pattern '*-11*'
$ redis-cli --scan --pattern 'user:*' | wc -l
3829433Belge, SCAN çağrıları arasına -i 0.01 ile bekleme eklemenin taramayı yavaşlattığını ama sunucu üzerindeki yükü belirgin biçimde azalttığını belirtir. --count ile her çağrının COUNT değerini de değiştirebilirsiniz. Aracın diğer seçenekleri için redis-cli kullanımı yazısına bakın.
Cluster, paralel tarama ve geçersiz imleç
Redis Cluster kullanırken desenin tek bir slota işaret ettiği durumlar için bir iyileştirme vardır: desen yalnızca tek bir slottaki anahtarlarla eşleşebiliyorsa Redis bütün veritabanı yerine yalnızca o slotu tarar. Belgedeki örnekte {a}h*llo deseni, {a} hash tag’inin işaret ettiği 15495 numaralı slotla sınırlanır. Aynı iyileştirme KEYS için de geçerlidir. Hash tag ve slot kavramları için cluster ve hash slot yazısına bakın.
Sunucu tarafında durum tutulmadığı için aynı koleksiyonu istediğiniz kadar istemci aynı anda tarayabilir. Bir taramayı yarıda bırakmak için sunucuya haber vermeniz gerekmez; yarım kalan taramalar hiçbir kaynak tüketmez. Geçerli imleçler yalnızca iki tanedir: başlangıç için 0 ve bir önceki çağrının döndürdüğü imleç. Bozuk, negatif veya aralık dışı bir imleç sunucuyu çökertmez, ama sonuçlar için verilen garantiler artık geçerli olmaz.
Sık yapılan hatalar

- Uygulama kodunda KEYS kullanmak: Anahtar sayısı arttıkça bütün sunucuyu bloklayan bir komut haline gelir.
- Boş sonuçta döngüyü durdurmak: Tarama yalnızca imleç 0 döndüğünde biter.
- COUNT’u sınır sanmak: COUNT bir ipucudur; daha fazla veya daha az eleman dönebilir.
- Tekrarları hesaba katmamak: Aynı anahtar birden fazla kez dönebilir; işlemleriniz tekrar uygulanmaya dayanıklı olmalıdır.
- MATCH’in işi azalttığını düşünmek: Filtre sonradan uygulanır; nadir desenlerde çağrıların çoğu boş döner.
- İmleci elle üretmek: İmleç yalnızca önceki çağrıdan alınır; sayısal değeri tahmin edilemez.
Sık Sorulan Sorular
KEYS komutunu hiç kullanmamalı mıyım?
Belge onu hata ayıklama ve anahtar düzenini değiştirmek gibi özel işler için ayırır. Az anahtarlı bir geliştirme veritabanında bloklama süresi kısa olur; üretim sunucusunda ve uygulama kodunda ise SCAN kullanın.
SCAN bir anahtarı atlayabilir mi?
Taramanın başından sonuna kadar var olan bir anahtarı atlamaz. Tarama sırasında eklenen veya silinen anahtarlar ise dönebilir ya da dönmeyebilir.
COUNT değerini ne kadar büyük vermeliyim?
Kesin bir kural yoktur; varsayılan 10’dur. Daha büyük değerler gidiş dönüş sayısını azaltır ama her çağrıda sunucuyu daha uzun meşgul eder. Değeri tarama sırasında değiştirmek serbesttir.
SCAN ile belirli bir tipteki anahtarları bulabilir miyim?
Evet, SCAN 0 TYPE hash gibi. Ancak coğrafi indeksler zset, bitmap’ler string olarak görünür ve filtre toplam iş miktarını azaltmaz.
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 · Anahtar isimlendirme ve keyspace · redis-cli kullanımı · Bellek kullanımı · Cluster ve hash slot