READONLY You can't write against a read only replica ir Redis atbilde, kad rakstīšanas komanda nonāk replikā. Pēc noklusējuma replikas pieņem tikai lasīšanu, tāpēc serveris rakstīšanu noraida. Gandrīz katrā incidentā datubāze ir kārtībā. Problēma ir tā, ka lietotne ir pieslēgta nepareizajam mezglam, parasti tūlīt pēc failover.
Redis kļūdu aprakstā tas pateikts vienkārši: rakstīšanu pieņem tikai primārais. Valkey, kas atdalījās no Redis, uzvedas tāpat un izmanto to pašu ziņojumu. Tātad jautājums nav "kas vainas Redis", bet "kāpēc mans klients uzskata šo repliku par primāro?"
Vispirms pārbaudiet, kas mezgls patiesībā ir
$ redis-cli -h cache-01 SET k v
(error) READONLY You can't write against a read only replica.
$ redis-cli -h cache-01 ROLE
1) "slave"
2) "10.0.2.15" # primārais, kam šis mezgls seko
3) (integer) 6379
4) "connected"
5) (integer) 3167038
$ redis-cli -h cache-01 INFO replication | head -5
# Replication
role:slave
master_host:10.0.2.15
master_port:6379
master_link_status:up
ROLE replikā kā pirmo elementu atgriež slave (vārds protokolā saglabāts atpakaļsaderībai), tad primārā adresi, savienojuma stāvokli un replikācijas nobīdi. INFO replication dod to pašu ainu teksta veidā. Ja mezgls ir replika, paskatieties, kuram primārajam tas seko. Tas pasaka, kur rakstīšanai vajadzēja nonākt.
Biežākie cēloņi
- Notika failover, un klients to nepamanīja. Vecais primārais atgriežas kā jaunā primārā replika. Jebkurš klients, kas vēl tur savienojumus ar veco adresi, tagad saņem READONLY uz katru rakstīšanu. Tas ir ievērojami biežākais gadījums.
- Klientam norādīta mezgla adrese, nevis servisa adrese. Iekodēta IP adrese vai mezgla vārds strādā, līdz lomas mainās. ElastiCache gadījumā AWS dokumentē, ka failover laikā tas pārnes paaugstinātās replikas DNS vārdu uz primāro galapunktu, tāpēc lietotnēm, kas raksta primārajā galapunktā, nekas nav jāmaina. Lietotnēm, kas raksta atsevišķa mezgla galapunktā, ir jāmaina.
- DNS vai savienojumu kešošana. Pat ar pareizo galapunktu klients vai izpildes vide, kas kešo DNS rezultātus, vai savienojumu pūls, kas nekad nepārslēdzas, turpina runāt ar veco mezglu arī pēc galapunkta pārvietošanas.
- Slodzes balansētājs vai Kubernetes Service, kas ietver replikas. Ja viens Service vai VIP norāda uz visiem Redis podiem, daļa rakstīšanas nonāk replikās. Tad kļūda parādās nejauši, ne tikai pēc failover.
- Kāds pazemināja mezglu. Manuāls
REPLICAOF, automatizācijas skripts vai Sentinel, kas pārkonfigurē mezglu, ko uzskata par novecojušu, var pārvērst primāro par repliku. - Lasīšanas maršrutēšana klientā. Klienti, kas sadala lasīšanu un rakstīšanu, var aizsūtīt rakstīšanu pa lasīšanas ceļu, piemēram, Lua skriptu vai
SORT ... STORE, ko klients uzskata par lasīšanu.
Skripti un "lasīšanas" komandas, kas patiesībā ir rakstīšana
Kļūdu aprakstā norādīts, ka Lua funkcija vai skripts, kas sākas ar rindu #!lua, replikā saņem READONLY jau pirms palaišanas, ja tam nav karoga no-writes. Parasts skripts saņem kļūdu, kad izsauc rakstīšanas komandu. Replikācijas dokumentācija arī norāda, ka EVAL, EVALSHA un SORT nav tikai lasīšanas komandas. Ja vēlaties tās izpildīt replikās, lietojiet EVAL_RO, EVALSHA_RO un SORT_RO, bet SUNIONSTORE vai ZINTERSTORE pagaidu atslēgās aizstājiet ar SUNION vai ZINTER.
Labojiet klientu, nevis repliku
- Ar Sentinel ļaujiet klientam pašam atrast primāro. Sentinel klientu specifikācija apraksta procedūru: pajautāt Sentinel ar
SENTINEL get-master-addr-by-name, pieslēgties un arROLEpārliecināties, ka mezgls tiešām ir master. Pie katras atkārtotas pieslēgšanās klientam jājautā Sentinel no jauna. Kad Sentinel pārkonfigurē instanci, tas nosūtaCLIENT KILL type normal, kas liek klientiem pārslēgties un adresi noskaidrot no jauna. Klients, kas atkal pieslēdzas kešotai adresei, šo mehānismu izjauc. - ElastiCache rakstiet tikai primārajā galapunktā (vai klastera režīmā konfigurācijas galapunktā) un pārliecinieties, ka izpildes vide nekešo DNS ilgāk par failover logu.
- Uztveriet READONLY kā signālu pārslēgties. Daudzus klientus var konfigurēt tā, lai, to saņemot, tie pārtrauc savienojumu un no jauna atrod primāro. Atkārtojot to pašu rakstīšanu tajā pašā savienojumā, tā neizdosies nekad.
- Atdaliet rakstīšanas un lasīšanas galapunktus. Kubernetes vidē dodiet rakstīšanai Service, kas atlasa tikai pašreizējo primāro. To nodrošina Sentinel atbalstoši klienti vai operators, kas marķē primāro. Service pār visiem podiem to nedara.
# pajautājiet Sentinel, kurš tagad ir primārais
$ redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
1) "10.0.2.21"
2) "6379"
# pēc tam pārbaudiet šo mezglu, pirms tam uzticaties
$ redis-cli -h 10.0.2.21 ROLE
1) "master"
...
Līdzīgas kļūdas
MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to 'no': replika ir zaudējusi savu primāro un ir konfigurēta atteikt datu komandas, nevis sniegt novecojušus datus.NOREPLICAS Not enough good replicas to write: jūs esat primārajā, bet ir iestatītsmin-replicas-to-write, un pieslēgts nav pietiekami daudz replikas ar pieņemamu nobīdi. Pēc noklusējumamin-replicas-to-writeir 0, tāpēc tas parādās tikai tad, ja kāds to ieslēdzis.LOADING Redis is loading the dataset in memory: mezgls tiek restartēts vai pabeidz pilnu sinhronizāciju. Par to rakstījām rakstā Redis LOADING dataset in memory.
Kas mainās ar lielām datu kopām
Ar desmitiem gigabaitu atmiņā tieši minūtes pēc failover ir tās, kad READONLY pārvēršas ilgākā dīkstāvē:
- Vecajam primārajam var vajadzēt pilnu pārsinhronizāciju. Kopš Redis 4.0 paaugstināta replika joprojām var nodrošināt daļēju pārsinhronizāciju vecā primārā replikām, bet tikai ja replikācijas buferis (backlog) vēl aptver starpību. Redis noklusējuma
repl-backlog-sizeir 1 MB (pašreizējā Valkey pirmkodā 10 MB), ko noslogots primārais piepilda sekundēs. Izvēlieties izmēru pēc rakstīšanas ātruma un pārtraukuma, ko vēlaties izturēt. - Pilna sinhronizācija maksā atmiņu un laiku. Primārais veido momentuzņēmumu ar fork, un noklusējuma
client-output-buffer-limit replica 256mb 64mb 60var atvienot repliku, kas ilgas pārsūtīšanas laikā atpaliek, un sinhronizācija sākas no jauna. Lielām datu kopām pārbaudiet šo limitu pirms plānota failover. - Replikas ielādes laikā bloķējas. Replikācijas dokumentācijā norādīts, ka pēc sākotnējās sinhronizācijas replikai jāielādē jaunā datu kopa galvenajā pavedienā un šajā logā tā bloķē savienojumus, kas ļoti lielām datu kopām var ilgt daudzas sekundes. Klienti, kas tajā brīdī pārslēdzas uz repliku, saņem LOADING, nevis READONLY.
- Pārslēgšanās vētras. Tūkstošiem klientu, kas vienlaikus meklē primāro, palielina slodzi uz Sentinel un jauno primāro. Pārslēgšanās loģikā lietojiet aizturi ar nejaušību (backoff ar jitter).
- Pārbaudiet failover apzināti. ElastiCache tieši šim nolūkam ir
test-failoverAPI. Ar Sentinel to pašu daraSENTINEL FAILOVER. Vērojiet, cik ilgi lietotnes turpina rakstīt vecajā mezglā. Tas ir jūsu īstais failover laiks, nevis sekundes, kas vajadzīgas datubāzei.
Tie paši noteikumi attiecas uz Valkey, ja esat pārgājuši vai plānojat pāriet, skatiet mūsu rakstu Redis uz Valkey migrācija: replikas pēc noklusējuma ir tikai lasāmas, un klientiem jāseko primārajam.
Galvenās atziņas
- READONLY nozīmē, ka rakstīšana nonāca replikā; datubāze parasti ir vesela.
- Pārbaudiet mezglu ar
ROLEvaiINFO replicationun skatieties, kuram primārajam tas seko. - Biežākais cēlonis ir klients, kas pēc failover joprojām pieslēgts vecajam primārajam, bieži caur mezgla adresi vai kešotu DNS.
- Labojiet atklāšanu: Sentinel atbalstoši klienti, ElastiCache primārais galapunkts, tikai rakstīšanas Service Kubernetes vidē.
- Nekad neiestatiet
replica-read-only nokā apvedceļu; lielām datu kopām arī pielāgojiet backlog un izvades buferus, lai failover nebeigtos ar pilnu pārsinhronizāciju.