Bikaranîna mcrouter ji bo pîvandina memcached horîzontal

Bikaranîna mcrouter ji bo pîvandina memcached horîzontal

Pêşxistina projeyên bargiraniyê bi her zimanî nêzîkbûnek taybetî û karanîna amûrên taybetî hewce dike, lê dema ku dor tê ser sepanên di PHP-ê de, rewş dikare ew qas giran bibe ku hûn neçar bibin ku pêşve bibin, mînakî, server serlêdana xwe. Di vê têbînîyê de em ê li ser êşa naskirî ya hilgirtina danişîna belavkirî û veşartina daneyê di memcached de biaxivin û ka me çawa van pirsgirêkan di yek projeya "war" de çareser kir.

Lehengê bûyerê serîlêdanek PHP-ê ye ku li ser bingeha çarçoweya symfony 2.3-ê ye, ku qet di nav plansaziyên karsaziyê yên ji bo nûvekirinê de tune ye. Digel hilanîna danişîna pir standard, vê projeyê bi tevahî bikar anî polîtîkaya "veşartina her tiştî". di memcached de: bersivên daxwazên li ser databas û serverên API, alayên cihêreng, kilîdên ji bo hevdengkirina pêkanîna kodê û hêj bêtir. Di rewşek weha de, têkçûna memcached ji bo xebata serîlêdanê dibe kujer. Digel vê yekê, windabûna cache dibe sedema encamên cidî: DBMS dest pê dike ku di nav deran de biteqe, karûbarên API dest bi qedexekirina daxwazan dikin, hwd. Dibe ku aramkirina rewşê bi deh hûrdeman bidome, û di vê demê de karûbar dê pir hêdî be an jî bi tevahî neyê peyda kirin.

Pêwîstiya me bi pêşkêşkirina hebû şiyana ku bi hewildanek hindik serîlêdanê bi rengek horizontî mezin bike, yanî bi guhertinên hindiktirîn ên koda çavkaniyê û fonksiyona tevahî parastî. Cache-ê ne tenê li hember têkçûnan berxwedêr bikin, lê di heman demê de hewl bidin ku windabûna daneyê jê kêm bikin.

Çi xeletiya memcached bixwe ye?

Bi gelemperî, pêveka memcached ji bo PHP-ê piştgirî dide daneya belavkirî û hilanîna danişînê ya derveyî qutiyê. Mekanîzmaya haşkirina birêkûpêk a domdar dihêle hûn daneyan bi rengek yeksan li ser gelek pêşkêşkeran bi cih bikin, bi rengek yekta her mifteyek taybetî ji serverek taybetî ya komê re navnîşan bikin, û amûrên têkçûyî yên çêkirî hebûna zêde ya karûbarê cachkirinê misoger dikin (lê, mixabin, dane tune).

Bi hilanîna danişînê re tişt hinekî çêtir in: hûn dikarin mîheng bikin memcached.sess_number_of_replicas, di encamê de dê dane li ser çend pêşkêşkeran bi yekcarî werin hilanîn, û di bûyera têkçûna mînakek memcached de, dê dane ji yên din werin veguheztin. Lêbelê, heke server bêyî daneyê vegere serhêl (wek ku bi gelemperî piştî nûve destpêkirinê diqewime), hin kilît dê di berjewendiya wê de ji nû ve werin dabeş kirin. Di rastiyê de ev ê wateya windakirina daneyên danişînê, ji ber ku di rewşek bêkêmasî de rêyek tune ku meriv "biçe" kopiyek din.

Amûrên pirtûkxaneyê yên standard bi giranî têne armanc kirin asumane scaling: ew dihêlin ku hûn cache-ê bi mezinahiyên mezin zêde bikin û ji koda ku li ser serverên cihêreng têne mêvandar kirin gihîştina wê peyda bikin. Lêbelê, di rewşa me de, qebareya daneyên hilanîn ji çend gigabaytan derbas nabe, û performansa yek an du girêk têr e. Li gorî vê yekê, amûrên standard ên bikêr tenê dikarin peydakirina hebûna memcached be dema ku bi kêmî ve yek mînakek cache di rewşa xebatê de bimîne. Lêbelê, ne gengaz bû ku meriv ji vê derfetê jî sûd werbigire... Li vir hêja ye ku meriv kevnariya çarçoweya ku di projeyê de hatî bikar anîn bi bîr bîne, ji ber vê yekê ne gengaz bû ku serîlêdanê bi hewzek serveran re bixebite. Werin em windabûna daneya danişînê jî ji bîr nekin: çavê xerîdar ji derketina girseyî ya bikarhêneran diqelişe.

Bi îdeal ew hewce bû dubarekirina tomarên di kopiyên memcached û paşguhkirinê de di rewşeke xelet an xeletî de. Alîkariya me kir ku vê stratejiyê pêk bînin mcrouter.

mcrouter

Ev routerek memcached e ku ji hêla Facebook ve hatî pêşve xistin da ku pirsgirêkên xwe çareser bike. Ew protokola nivîsê ya memcached piştgirî dike, ku destûrê dide sazkirinên memcached pîvan bi rêjeyên dîn. Danasînek berfireh a mcrouter dikare tê de were dîtin vê daxuyaniyê. Di nav tiştên din de fonksiyona berfireh ew dikare tiştê ku em hewce ne bike:

  • replicate record;
  • Heke xeletiyek çêbibe, li ser serverên din ên di komê de paşvegerê bikin.

Bike ser kar!

veavakirina mcrouter

Ez ê rasterast herim ser mîhengê:

{
 "pools": {
   "pool00": {
     "servers": [
       "mc-0.mc:11211",
       "mc-1.mc:11211",
       "mc-2.mc:11211"
   },
   "pool01": {
     "servers": [
       "mc-1.mc:11211",
       "mc-2.mc:11211",
       "mc-0.mc:11211"
   },
   "pool02": {
     "servers": [
       "mc-2.mc:11211",
       "mc-0.mc:11211",
       "mc-1.mc:11211"
 },
 "route": {
   "type": "OperationSelectorRoute",
   "default_policy": "AllMajorityRoute|Pool|pool00",
   "operation_policies": {
     "get": {
       "type": "RandomRoute",
       "children": [
         "MissFailoverRoute|Pool|pool02",
         "MissFailoverRoute|Pool|pool00",
         "MissFailoverRoute|Pool|pool01"
       ]
     }
   }
 }
}

Çima sê hewz? Çima server têne dubare kirin? Ka em fêr bibin ka ew çawa dixebite.

  • Di vê veavakirinê de, mcrouter riya ku daxwaz dê li ser bingeha fermana daxwaznameyê were şandin hildibijêre. Mêrik vê yekê jê re dibêje OperationSelectorRoute.
  • Daxwazên GET diçin destwerdanê RandomRouteku bi korfelaqî hewzek an rêgezek di nav tiştên array de hildibijêre children. Her hêmanek vê rêzê di dorê de rêvekerek e MissFailoverRoute, ku dê di nav her serverek di hewzê re derbas bibe heya ku ew bersivek bi daneyan bistîne, ku dê ji xerîdar re were vegerandin.
  • Ger em bi taybetî bikar bînin MissFailoverRoute bi hewzek ji sê pêşkêşkeran re, wê hingê hemî daxwaz dê pêşî werin mînaka yekem a memcached, û yên mayî dê dema ku dane tune be dê daxwaznameyan li ser bingehek mayî bistînin. Nêzîkatiyek bi vî rengî wê bibe sedema barkirina zêde li ser servera yekem a di navnîşê de, ji ber vê yekê biryar hate girtin ku sê hewzên bi navnîşanên di rêzikên cihêreng de werin çêkirin û wan bi korfelaqî hilbijêrin.
  • Hemî daxwazên din (û ev tomarek e) bi karanîna têne kirin AllMajorityRoute. Ev hilber daxwazan ji hemî pêşkêşkerên li hewzê re dişîne û li benda bersivên herî kêm ji N/2 + 1 ji wan e. Ji bikaranîna AllSyncRoute ji bo operasyonên nivîsandinê diviyabû ku dev jê berdin, ji ber ku ev rêbaz bersivek erênî hewce dike всех pêşkêşkerên di komê de - wekî din ew ê vegere SERVER_ERROR. Her çend mcrouter dê daneyan li kaşên berdest lê zêde bike, fonksiyona bangkirina PHP-ê dê xeletiyek vegere û dê hişyariyê çêbike. AllMajorityRoute ne ew qas hişk e û dihêle ku nîvê yekîneyan bêyî pirsgirêkên ku li jor hatine destnîşan kirin ji kar werin derxistin.

Kêmasiya sereke Ev nexşe ev e ku heke bi rastî di cacheyê de dane tune be, wê hingê ji bo her daxwazek ji xerîdar N daxwazên memcached bi rastî dê bêne darve kirin - ji bo her kesî pêşkêşkerên di hewzê de. Em dikarin hejmara pêşkêşkerên di hewzan de kêm bikin, mînakî, duduyan: qurbankirina pêbaweriya hilanînê, em digirinоleza bilindtir û barkirina kêmtir ji daxwazên bişkokên wenda.

NB: Hûn dikarin ji bo fêrbûna mcrouter lînkên kêrhatî jî bibînin belgeyên li ser wiki и pirsgirêkên projeyê (tevî yên girtî), ku nûnertiya depoyek tevahî ya veavakirinên cihêreng dike.

Avakirin û xebitandina mcrouter

Serlêdana me (û xwe memcached) li Kubernetes dimeşîne - li gorî vê yekê, mcrouter jî li wir e. Bo civîna konteynir em bikar tînin werf, veavakirina ku dê bi vî rengî xuya bike:

NB: Lîsteyên ku di gotarê de hatine dayîn di depoyê de têne weşandin flat / mcrouter.

configVersion: 1
project: mcrouter
deploy:
 namespace: '[[ env ]]'
 helmRelease: '[[ project ]]-[[ env ]]'
---
image: mcrouter
from: ubuntu:16.04
mount:
- from: tmp_dir
 to: /var/lib/apt/lists
- from: build_dir
 to: /var/cache/apt
ansible:
 beforeInstall:
 - name: Install prerequisites
   apt:
     name: [ 'apt-transport-https', 'tzdata', 'locales' ]
     update_cache: yes
 - name: Add mcrouter APT key
   apt_key:
     url: https://facebook.github.io/mcrouter/debrepo/xenial/PUBLIC.KEY
 - name: Add mcrouter Repo
   apt_repository:
     repo: deb https://facebook.github.io/mcrouter/debrepo/xenial xenial contrib
     filename: mcrouter
     update_cache: yes
 - name: Set timezone
   timezone:
     name: "Europe/Moscow"
 - name: Ensure a locale exists
   locale_gen:
     name: en_US.UTF-8
     state: present
 install:
 - name: Install mcrouter
   apt:
     name: [ 'mcrouter' ]

(werf.yaml)

... û wê xêz bike Helm chart. Tişta balkêş ev e ku li ser bingeha hejmara kopiyan tenê jeneratorek mîhengê heye (heke kesek vebijarkek lakonîk û xweşiktir hebe, wê di şîroveyan de parve bikin):

{{- $count := (pluck .Values.global.env .Values.memcached.replicas | first | default .Values.memcached.replicas._default | int) -}}
{{- $pools := dict -}}
{{- $servers := list -}}
{{- /* Заполняем  массив двумя копиями серверов: "0 1 2 0 1 2" */ -}}
{{- range until 2 -}}
 {{- range $i, $_ := until $count -}}
   {{- $servers = append $servers (printf "mc-%d.mc:11211" $i) -}}
 {{- end -}}
{{- end -}}
{{- /* Смещаясь по массиву, получаем N срезов: "[0 1 2] [1 2 0] [2 0 1]" */ -}}
{{- range $i, $_ := until $count -}}
 {{- $pool := dict "servers" (slice $servers $i (add $i $count)) -}}
 {{- $_ := set $pools (printf "MissFailoverRoute|Pool|pool%02d" $i) $pool -}}
{{- end -}}
---
apiVersion: v1
kind: ConfigMap
metadata:
 name: mcrouter
data:
 config.json: |
   {
     "pools": {{- $pools | toJson | replace "MissFailoverRoute|Pool|" "" -}},
     "route": {
       "type": "OperationSelectorRoute",
       "default_policy": "AllMajorityRoute|Pool|pool00",
       "operation_policies": {
         "get": {
           "type": "RandomRoute",
           "children": {{- keys $pools | toJson }}
         }
       }
     }
   }

(10-mcrouter.yaml)

Em wê di hawîrdora ceribandinê de derdixin û kontrol dikin:

# php -a
Interactive mode enabled

php > # Проверяем запись и чтение
php > $m = new Memcached();
php > $m->addServer('mcrouter', 11211);
php > var_dump($m->set('test', 'value'));
bool(true)
php > var_dump($m->get('test'));
string(5) "value"
php > # Работает! Тестируем работу сессий:
php > ini_set('session.save_handler', 'memcached');
php > ini_set('session.save_path', 'mcrouter:11211');
php > var_dump(session_start());
PHP Warning:  Uncaught Error: Failed to create session ID: memcached (path: mcrouter:11211) in php shell code:1
Stack trace:
#0 php shell code(1): session_start()
#1 {main}
  thrown in php shell code on line 1
php > # Не заводится… Попробуем задать session_id:
php > session_id("zzz");
php > var_dump(session_start());
PHP Warning:  session_start(): Cannot send session cookie - headers already sent by (output started at php shell code:1) in php shell code on line 1
PHP Warning:  session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning:  session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning:  session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning:  session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning:  session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning:  session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning:  session_start(): Unable to clear session lock record in php shell code on line 1
PHP Warning:  session_start(): Failed to read session data: memcached (path: mcrouter:11211) in php shell code on line 1
bool(false)
php >

Lêgerîna li teksta xeletiyê tu encam negirt, lê ji bo pirsê "mcrouter php"Di serî de pirsgirêka herî kevnare ya projeyê bû - nebûna piştgirî protokola binary memcached.

NB: Protokola ASCII ya di memcached de ji ya binaryê hêdîtir e, û rêgezên standard ên haşkirina mifteya hevgirtî tenê bi protokola binaryê re dixebitin. Lê ev ji bo dozek taybetî pirsgirêk dernakeve.

Xefet di çenteyê de ye: ya ku hûn bikin ev e ku hûn derbasî protokola ASCII bibin û her tişt dê bixebite…. Lêbelê, di vê rewşê de, adeta ku li bersivan digere belgeyên li ser php.net henekeke hovane lîst. Hûn ê bersiva rast li wir nebînin... heya ku, bê guman, hûn heya dawiyê, ku di beşê de ye, bigerin "Nîşeyên beşdariya bikarhêner" dê dilsoz be û bersîva bi neheqî nerazîbûn.

Erê, navê vebijarka rast e memcached.sess_binary_protocol. Pêdivî ye ku ew bête asteng kirin, piştî ku dê danişîn dest bi xebatê bikin. Tiştê ku dimîne ev e ku hûn konteynera bi mcrouter bi PHP-ê ve têxin nav podek!

encamê

Bi vî rengî, bi tenê guhertinên binesaziyê me karî pirsgirêk çareser bikin: Pirsgirêka tolerasyona xeletiya memcached hate çareser kirin, û pêbaweriya hilanîna cache zêde bûye. Digel avantajên eşkere yên ji bo serîlêdanê, vê yekê dema ku li ser platformê dixebitin cîhê manevrayê da: gava ku hemî pêkhate rezervek hebe, jiyana rêveberê pir hêsan dibe. Erê, vê rêbazê kêmasiyên xwe jî hene, dibe ku ew mîna "kûçikek" xuya bike, lê heke ew drav xilas dike, pirsgirêkê dişewitîne û dibe sedema yên nû - çima na?

PS

Li ser bloga me jî bixwînin:

Source: www.habr.com

Add a comment