Redis: SCAN ist nicht SCAN
In einer Laravel-Anwendung ist es entscheidend, immer im Blick zu haben, welchen Redis-Client du verwendest. Unterschiedliche Redis-Clients (wie predis oder phpredis) können sich in Performance, Funktionsumfang und Konfiguration unterscheiden. Besonders bei der Implementierung des SCAN-Befehls gibt es Unterschiede, die nicht sofort offensichtlich sind.
Vor ein paar Tagen sind wir auf die Anforderung gestoßen, in einem riesigen Pool von Keys nach Ähnlichkeiten zu suchen. Bis dahin kein Problem.
1$keys = Redis::keys($pattern);2 3foreach ($keys as $key) {4 Log::info($key);5}
Normalerweise würde dieser Code die Anforderung erfüllen. Das Problem ist jedoch, dass die Anwendung, für die wir diese Funktionalität implementiert haben, mehrere Millionen Anfragen pro Tag verarbeitet, wodurch eine riesige Menge an Caching-Keys in Redis entsteht.
Die Lösung ist SCAN. Im Gegensatz zu KEYS, das alle Keys auf einmal abruft, SCAN iteriert über die Daten und benötigt einen Cursor, um die Ergebnisse zu verwalten. Aber soweit ist das noch nicht das Problem.
Unser nächster Versuch war ein klassischer Ansatz zur Iteration in Redis:
1$pattern = '/test/*' 2$cursor = '0'; 3$count = 50000; 4do { 5 $result = $redis->scan($cursor, ['match' => $pattern, 'count' => $count]); 6 if ($result === false) { 7 break; 8 } 9 10 $cursor = $result[0];11 $allResults = array_merge($allResults, $result[1]);12 13} while ($cursor !== '0');
Ein erfahrenes Auge erkennt schnell, dass diese Implementierung vor allem für PREDIS ausgelegt ist, einen in PHP geschriebenen Redis-Client.
Ehrlich gesagt hat uns das überrascht. Während unsere Entwickler Predis verwendet hatten (vielleicht aus Bequemlichkeit beim Setup 😉), war in unserer Staging-Umgebung der PHPRedis-Client eingerichtet, der in C geschrieben ist.
Das Problem mit diesem Code ist: Er funktioniert nicht mit PHPRedis, oder liefert zumindest kein Ergebnis. Um das zu ändern, musst du den Code ein wenig anpassen.
1$pattern = '/test/*' 2$cursor = config('database.redis.client') == 'predis' ? '0' : null; 3$count = 50000; 4do { 5 $result = $redis->scan($cursor, ['match' => $pattern, 'count' => $count]); 6 if ($result === false) { 7 break; 8 } 9 10 $cursor = $result[0];11 $allResults = array_merge($allResults, $result[1]);12 13} while ($cursor !== '0');
Das Ergebnis dieses Unterschieds war absolut absurd. Aufgrund der leichten Abweichungen bei der Cursor-Verarbeitung zwischen den Clients hatten wir am Ende überhaupt keine Ergebnisse.
Behalte also immer im Blick, welchen Redis-Client du in Laravel verwendest! 🚀
Lust, gemeinsam zu kochen?
Ob Idee, Refactor oder Neubau — erzähl uns kurz von deinem Projekt. Wir melden uns innerhalb von 24 Stunden.
Weiterlesen
08. Jul 2026
Triff Sushi beim WeAreDevelopers in Berlin
Wir sind beim WeAreDevelopers World Congress in Berlin und treffen uns gerne mit dir zum Austauschen. Sprich uns einfach an oder sichere dir vorab einen entspannten Kaffee-Slot.
15. Jun 2026
Responsive Images: Der komplette Guide zu srcset & sizes
Responsive Images ohne Handwedeln: wie srcset und sizes wirklich funktionieren, picture für Art Direction — und wie du die Varianten generierst, statt sie von Hand zu pflegen.
06. Jun 2026
Core Web Vitals sind ein Bilder-Problem – und wie Fairu es löst
LCP ist der Core Web Vital, an dem die meisten Seiten scheitern — und schuld sind fast immer die Bilder. Wie Fairu sie bestehen lässt, ganz ohne eigene Pipeline.