Defnyddio mcrouter i raddfa memcached yn llorweddol

Defnyddio mcrouter i raddfa memcached yn llorweddol

Mae datblygu prosiectau llwyth uchel mewn unrhyw iaith yn gofyn am ddull arbennig a defnyddio offer arbennig, ond o ran cymwysiadau yn PHP, gall y sefyllfa waethygu cymaint nes bod yn rhaid i chi ddatblygu, er enghraifft, gweinydd cais ei hun. Yn y nodyn hwn byddwn yn siarad am y boen gyfarwydd gyda storio sesiwn ddosbarthedig a storio data mewn memcached a sut y gwnaethom ddatrys y problemau hyn mewn un prosiect “ward”.

Arwr yr achlysur yw cais PHP sy'n seiliedig ar fframwaith symfony 2.3, nad yw wedi'i gynnwys o gwbl yn y cynlluniau busnes i'w diweddaru. Yn ogystal â storfa sesiwn eithaf safonol, gwnaeth y prosiect hwn ddefnydd llawn o polisi "caching everything". yn memcached: ymatebion i geisiadau i'r gronfa ddata a gweinyddwyr API, baneri amrywiol, cloeon ar gyfer cydamseru gweithredu cod a llawer mwy. Mewn sefyllfa o'r fath, mae dadansoddiad o memcached yn dod yn angheuol i weithrediad y cais. Yn ogystal, mae colli storfa yn arwain at ganlyniadau difrifol: mae'r DBMS yn dechrau byrstio yn y gwythiennau, mae gwasanaethau API yn dechrau gwahardd ceisiadau, ac ati. Mae’n bosibl y bydd yn cymryd degau o funudau i sefydlogi’r sefyllfa, ac yn ystod y cyfnod hwn bydd y gwasanaeth yn ofnadwy o araf neu ddim ar gael o gwbl.

Roedd angen i ni ddarparu y gallu i raddio'r cais yn llorweddol heb fawr o ymdrech, h.y. gydag ychydig iawn o newidiadau i'r cod ffynhonnell ac ymarferoldeb llawn wedi'i gadw. Gwnewch y storfa nid yn unig yn gallu gwrthsefyll methiannau, ond hefyd yn ceisio lleihau colli data ohono.

Beth sy'n bod ar memcached ei hun?

Yn gyffredinol, mae'r estyniad memcached ar gyfer PHP yn cefnogi data dosbarthedig a storio sesiynau allan o'r blwch. Mae'r mecanwaith ar gyfer stwnsio bysellau cyson yn caniatáu ichi osod data'n gyfartal ar lawer o weinyddion, gan fynd i'r afael yn unigryw â phob allwedd benodol i weinydd penodol o'r grŵp, ac mae offer methu mewnol yn sicrhau argaeledd uchel y gwasanaeth caching (ond, yn anffodus, dim data).

Mae pethau ychydig yn well gyda storfa sesiwn: gallwch chi ffurfweddu memcached.sess_number_of_replicas, ac o ganlyniad bydd y data'n cael ei storio ar sawl gweinydd ar unwaith, ac os bydd un enghraifft memcached yn methu, bydd y data'n cael ei drosglwyddo o eraill. Fodd bynnag, os daw'r gweinydd yn ôl ar-lein heb ddata (fel sy'n digwydd fel arfer ar ôl ailgychwyn), bydd rhai o'r allweddi yn cael eu hailddosbarthu o'i blaid. Mewn gwirionedd bydd hyn yn golygu colli data sesiwn, gan nad oes unrhyw ffordd i “fynd” at atgynhyrchiad arall rhag ofn y bydd colled.

Anelir offer llyfrgell safonol yn bennaf at llorweddol graddio: maent yn caniatáu ichi gynyddu'r storfa i feintiau enfawr a darparu mynediad iddo o god a gynhelir ar weinyddion gwahanol. Fodd bynnag, yn ein sefyllfa ni, nid yw cyfaint y data sydd wedi'i storio yn fwy na sawl gigabeit, ac mae perfformiad un neu ddau nod yn ddigon. Yn unol â hynny, yr unig offer safonol defnyddiol posibl fyddai sicrhau bod memcached ar gael wrth gynnal o leiaf un enghraifft cache mewn cyflwr gweithio. Fodd bynnag, nid oedd yn bosibl manteisio ar y cyfle hwn hyd yn oed... Yma mae'n werth cofio hynafiaeth y fframwaith a ddefnyddiwyd yn y prosiect, a dyna pam ei bod yn amhosibl cael y cais i weithio gyda chronfa o weinyddion. Peidiwn ag anghofio hefyd am golli data sesiwn: roedd llygad y cwsmer yn gwegian o allgofnodi enfawr defnyddwyr.

Yn ddelfrydol roedd ei angen atgynhyrchu cofnodion mewn memcached ac osgoi copïau rhag ofn camgymeriad neu gamgymeriad. Helpodd ni i roi’r strategaeth hon ar waith mcrouter.

mcrouter

Mae hwn yn llwybrydd memcached a ddatblygwyd gan Facebook i ddatrys ei broblemau. Mae'n cefnogi'r protocol testun memcached, sy'n caniatáu gosodiadau memcached ar raddfa i gyfrannau gwallgof. Ceir disgrifiad manwl o mcrouter yn y cyhoeddiad hwn. Ymhlith pethau eraill ymarferoldeb eang gall wneud yr hyn sydd ei angen arnom:

  • atgynhyrchu cofnod;
  • gwneud wrth gefn i weinyddion eraill yn y grŵp os bydd gwall yn digwydd.

Ewch i'r gwaith!

cyfluniad mcrouter

Fe af yn syth i'r ffurfwedd:

{
 "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"
       ]
     }
   }
 }
}

Pam tri phwll? Pam mae gweinyddion yn cael eu hailadrodd? Gadewch i ni ddarganfod sut mae'n gweithio.

  • Yn y cyfluniad hwn, mae mcrouter yn dewis y llwybr yr anfonir y cais iddo yn seiliedig ar y gorchymyn cais. Mae'r dyn yn dweud hyn wrtho OperationSelectorRoute.
  • Ceisiadau GET mynd at y triniwr RandomRoutesy'n dewis pwll neu lwybr ar hap ymhlith gwrthrychau arae children. Mae pob elfen o'r arae hon yn ei thro yn driniwr MissFailoverRoute, a fydd yn mynd trwy bob gweinydd yn y pwll nes ei fod yn derbyn ymateb gyda data, a fydd yn cael ei ddychwelyd i'r cleient.
  • Os byddwn yn defnyddio yn unig MissFailoverRoute gyda chronfa o dri gweinydd, yna byddai pob cais yn dod yn gyntaf i'r enghraifft memcached cyntaf, a byddai'r gweddill yn derbyn ceisiadau ar sail weddilliol pan nad oes data. Byddai ymagwedd o'r fath yn arwain at llwyth gormodol ar y gweinydd cyntaf yn y rhestr, felly penderfynwyd cynhyrchu tri phwll gyda chyfeiriadau mewn gwahanol ddilyniannau a'u dewis ar hap.
  • Mae pob cais arall (a dyma gofnod) yn cael eu prosesu gan ddefnyddio AllMajorityRoute. Mae'r triniwr hwn yn anfon ceisiadau i bob gweinydd yn y gronfa ac yn aros am ymatebion gan o leiaf N/2 + 1 ohonynt. O ddefnydd AllSyncRoute ar gyfer gweithrediadau ysgrifennu roedd yn rhaid rhoi'r gorau iddi, gan fod angen ymateb cadarnhaol gan y dull hwn holl gweinyddwyr yn y grŵp - fel arall bydd yn dychwelyd SERVER_ERROR. Er y bydd mcrouter yn ychwanegu'r data i'r caches sydd ar gael, y swyddogaeth PHP sy'n galw bydd yn dychwelyd gwall a bydd yn cynhyrchu rhybudd. AllMajorityRoute nid yw mor llym ac mae'n caniatáu i hyd at hanner yr unedau gael eu tynnu allan o wasanaeth heb y problemau a ddisgrifir uchod.

Prif anfantais Y cynllun hwn yw, os nad oes unrhyw ddata yn y storfa mewn gwirionedd, yna ar gyfer pob cais gan y cleient N bydd ceisiadau i memcached yn cael eu gweithredu - i i bawb gweinyddion yn y pwll. Gallwn leihau nifer y gweinyddwyr mewn pyllau, er enghraifft, i ddau: aberthu dibynadwyedd storio, a gawnоcyflymder uwch a llai o lwyth o geisiadau i allweddi coll.

NB: Efallai y byddwch hefyd yn dod o hyd i ddolenni defnyddiol ar gyfer mcrouter dysgu dogfennaeth ar wici и materion prosiect (gan gynnwys rhai caeedig), yn cynrychioli stordy cyfan o wahanol gyfluniadau.

Adeiladu a rhedeg mcrouter

Mae ein cais (a memcached ei hun) yn rhedeg yn Kubernetes - yn unol â hynny, mae mcrouter hefyd wedi'i leoli yno. Canys cynulliad cynhwysydd rydym yn defnyddio werff, bydd y ffurfwedd ar ei gyfer yn edrych fel hyn:

NB: Mae'r rhestrau a roddir yn yr erthygl yn cael eu cyhoeddi yn yr ystorfa fflant/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)

... a braslun ohono Siart llyw. Y peth diddorol yw mai dim ond generadur config sydd yn seiliedig ar nifer y replicas (os oes gan unrhyw un opsiwn mwy laconig a chain, rhannwch ef yn y sylwadau):

{{- $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)

Rydyn ni'n ei gyflwyno i'r amgylchedd prawf ac yn gwirio:

# 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 >

Ni roddodd chwilio am destun y gwall unrhyw ganlyniadau, ond ar gyfer yr ymholiad “mcrouter php“Ar y blaen oedd problem hynaf y prosiect heb ei datrys - diffyg cefnogaeth protocol deuaidd memcached.

NB: Mae'r protocol ASCII yn memcached yn arafach na'r un deuaidd, ac mae dulliau safonol o stwnsio allweddol cyson yn gweithio gyda'r protocol deuaidd yn unig. Ond nid yw hyn yn creu problemau ar gyfer achos penodol.

Mae'r tric yn y bag: y cyfan sy'n rhaid i chi ei wneud yw newid i'r protocol ASCII a bydd popeth yn gweithio.... Fodd bynnag, yn yr achos hwn, mae'r arferiad o chwilio am atebion yn dogfennaeth ar php.net chwarae jôc greulon. Ni fyddwch yn dod o hyd i'r ateb cywir yno ... oni bai, wrth gwrs, eich bod yn sgrolio i'r diwedd, ble yn yr adran "Nodiadau a gyfrannwyd gan y defnyddiwr" bydd ffyddlon a ateb heb bleidlais annheg.

Ydy, yr enw opsiwn cywir yw memcached.sess_binary_protocol. Rhaid iddo fod yn anabl, ac ar ôl hynny bydd y sesiynau'n dechrau gweithio. Y cyfan sydd ar ôl yw rhoi'r cynhwysydd gyda mcrouter mewn pod gyda PHP!

Casgliad

Felly, gyda newidiadau seilwaith yn unig, roeddem yn gallu datrys y broblem: mae'r mater gyda goddefgarwch namau memcached wedi'i ddatrys, ac mae dibynadwyedd storio storfa wedi cynyddu. Yn ogystal â manteision amlwg y cais, rhoddodd hyn le i symud wrth weithio ar y platfform: pan fydd gan yr holl gydrannau gronfa wrth gefn, mae bywyd y gweinyddwr wedi'i symleiddio'n fawr. Oes, mae gan y dull hwn ei anfanteision hefyd, efallai y bydd yn edrych fel “crutch”, ond os yw'n arbed arian, yn claddu'r broblem ac nid yw'n achosi rhai newydd - pam lai?

PS

Darllenwch hefyd ar ein blog:

Ffynhonnell: hab.com

Ychwanegu sylw