Memcached горизонталдуу масштабда mcrouter колдонуу

Memcached горизонталдуу масштабда mcrouter колдонуу

Кайсы тилде болбосун жогорку жүктөмдүү долбоорлорду иштеп чыгуу өзгөчө мамилени жана атайын куралдарды колдонууну талап кылат, бирок PHPдеги тиркемелерге келгенде, кырдаал ушунчалык курчуп кетиши мүмкүн, мисалы, иштеп чыгууга туура келет. өз колдонмо сервери. Бул жазууда биз сеанстардын бөлүштүрүлгөн сакталышынын жана маалыматтарды кэштин memcachedдеги тааныш азабы жана биз бул көйгөйлөрдү бир "палаталык" долбоордо кантип чечкенибиз жөнүндө сүйлөшөбүз.

Иш-чаранын каарманы - symfony 2.3 фреймворктун негизиндеги PHP тиркемеси, ал жаңылоо бизнес-пландарында такыр жок. Стандарттык сеанстарды сактоодон тышкары, бул долбоор толук пайдаланган "баарын кэштөө" саясаты memcached: маалымат базасына жана API серверлерине суроо-жооптор, ар кандай желектер, коддун аткарылышын синхрондоштуруу үчүн кулпулар жана башкалар. Мындай кырдаалда, memcached бузулушу колдонмонун иштеши үчүн өлүмгө алып келет. Мындан тышкары, кэш жоготуу олуттуу кесепеттерге алып келет: DBMS тигиштерде жарылып баштайт, API кызматтары суроо-талаптарга тыюу сала баштайт ж.б. Кырдаалды турукташтыруу ондогон мүнөттөрдү талап кылышы мүмкүн жана бул убакыттын ичинде кызмат өтө жай же таптакыр жеткиликсиз болот.

камсыз кылышыбыз керек болчу колдонмону горизонталдуу түрдө аз күч менен масштабдоо мүмкүнчүлүгү, б.а. баштапкы кодуна минималдуу өзгөртүүлөр жана толук функционалдык сакталган. Кэшти каталарга туруштук бербестен, андан маалымат жоготууларын азайтууга аракет кылыңыз.

Memcached өзүнө эмне болду?

Жалпысынан алганда, PHP үчүн memcached кеңейтүү кутудан тышкары бөлүштүрүлгөн маалыматтарды жана сеанстарды сактоону колдойт. Ачкычтарды ырааттуу хэштөө механизми көптөгөн серверлерге маалыматтарды бирдей жайгаштырууга мүмкүндүк берет, ар бир конкреттүү ачкычты топтон белгилүү бир серверге уникалдуу түрдө даректейт жана орнотулган иштебей калуу куралдары кэш кызматынын жогорку жеткиликтүүлүгүн камсыз кылат (бирок, тилекке каршы, маалымат жок).

Сеанс сактагычында баары бир аз жакшыраак: сиз конфигурациялай аласыз memcached.sess_number_of_replicas, мунун натыйжасында маалыматтар бир эле учурда бир нече серверлерде сакталат, ал эми бир memcached инстанция иштебей калса, маалыматтар башкалардан өткөрүлүп берилет. Бирок, эгер сервер маалыматсыз кайра онлайнга кирсе (адатта, өчүрүп күйгүзгөндөн кийин болот), кээ бир баскычтар анын пайдасына бөлүштүрүлөт. Чынында бул билдирет сеанс маалыматтарын жоготуу, сагынган учурда башка репликага "барууга" эч кандай жол жок болгондуктан.

Стандарттык китепкана куралдары негизинен багытталган горизонталдуу масштабдоо: алар кэшти гиганттык өлчөмдөргө чейин көбөйтүүгө жана ар кандай серверлерде жайгашкан коддон ага жетүү мүмкүнчүлүгүн берет. Бирок, биздин шартта, сакталган маалыматтардын көлөмү бир нече гигабайттан ашпайт, ал эми бир же эки түйүндүн иштеши жетиштүү. Демек, бир гана пайдалуу стандарттык инструменттер, жок дегенде, бир кэш инстанциясын иштөө абалында сактоо менен, memcachedдин болушун камсыз кылуу болушу мүмкүн. Бирок, бул мүмкүнчүлүктөн да пайдалануу мүмкүн болгон жок... Бул жерде долбоордо колдонулган фреймворктун байыркылыгын эске сала кетели, ошол себептен тиркемени серверлердин бассейни менен иштөөгө алуу мүмкүн эмес эле. Сеанс маалыматтарынын жоголушу жөнүндө да унутпайлы: колдонуучулардын массалык түрдө чыгуусунан кардардын көздөрү чыйралды.

Идеалында талап кылынган memcached жана айланып өтүүчү репликалардагы жазууларды репликациялоо ката же ката болгон учурда. Бул стратегияны ишке ашырууга жардам берди mcrouter.

mcrouter

Бул Facebook тарабынан көйгөйлөрүн чечүү үчүн иштелип чыккан мемкэштелген роутер. Бул мүмкүндүк берет memcached текст протоколун колдойт масштабдуу memcached орнотуулар жинди пропорцияларга. mcrouterдын толук сүрөттөлүшүн табууга болот бул жарыя. Башка нерселердин арасында кең функционалдык ал бизге керектүү нерсени жасай алат:

  • көчүрмө жазуу;
  • ката пайда болсо, топтун башка серверлерине кайра кайтарыңыз.

Ишке киришүү!

mcrouter конфигурациясы

Мен түз эле конфигурацияга барам:

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

Эмне үчүн үч бассейн? Эмне үчүн серверлер кайталанат? Келгиле, анын кантип иштээрин карап көрөлү.

  • Бул конфигурацияда mcrouter сурам буйругунун негизинде сурам жөнөтүлө турган жолду тандайт. Жигит ага муну айтат OperationSelectorRoute.
  • GET сурамдары иштетүүчүгө барат RandomRouteмассив объектилеринин арасынан бассейнди же маршрутту туш келди тандайт children. Бул массивдин ар бир элементи өз кезегинде иштеткич болуп саналат MissFailoverRoute, ал кардарга кайтарылып берилүүчү маалыматтар менен жооп алганга чейин бассейндеги ар бир сервер аркылуу өтөт.
  • Эгерде биз эксклюзивдүү түрдө колдонсок MissFailoverRoute үч серверден турган бассейн менен, анда бардык суроо-талаптар биринчи мемкэштелген инстанцияга келет, ал эми калгандары эч кандай маалымат жок болгондо суроо-талаптарды кабыл алышат. Мындай мамиле алып келет тизмедеги биринчи серверде ашыкча жүк, ошондуктан ар кандай ырааттуулукта даректери бар үч бассейнди түзүү жана аларды туш келди тандоо чечими кабыл алынды.
  • Бардык башка суроо-талаптар (жана бул рекорд) колдонуу менен иштетилет AllMajorityRoute. Бул иштеткич бассейндеги бардык серверлерге суроо-талаптарды жөнөтөт жана алардын жок дегенде N/2 + 1 жоопторун күтөт. Колдонуудан AllSyncRoute жазуу операцияларын таштоо керек болчу, анткени бул ыкма оң жооп талап кылат всех топтун серверлери - антпесе ал кайтып келет SERVER_ERROR. mcrouter маалыматтарды жеткиликтүү кэштерге кошот да, чакыруучу PHP функциясы ката кайтарат жана билдирүү жаратат. AllMajorityRoute анчалык катуу эмес жана агрегаттардын жарымына чейинкисин жогоруда айтылган проблемаларсыз иштен чыгарууга мумкундук берет.

Негизги кемчилиги Бул схема, эгерде чындыгында кэште эч кандай маалымат жок болсо, анда кардардын ар бир суроо-талабы үчүн N memcachedге болгон өтүнүч иш жүзүндө аткарылат - бардык бассейндеги серверлер. Биз бассейндердеги серверлердин санын экиге чейин кыскарта алабыз: сактагычтын ишенимдүүлүгүн жоготуп, биз алабызожогорку ылдамдыкта жана жетишпеген баскычтарга суроо-талаптардан азыраак жүк.

NB: Ошондой эле mcrouter үйрөнүү үчүн пайдалуу шилтемелерди таба аласыз викидеги документтер и долбоор маселелери (анын ичинде жабык), ар кандай конфигурациядагы бүтүндөй кампаны билдирет.

mcrouter куруу жана иштетүү

Биздин тиркеме (жана memcached өзү) Kubernetesте иштейт - ошого жараша mcrouter да ошол жерде жайгашкан. үчүн контейнер чогултуу Биз колдонобуз werf, анын конфигурациясы төмөнкүдөй болот:

NB: Макалада берилген тизмелер репозиторийде жарыяланган flant/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)

... жана аны чийиңиз Руль диаграммасы. Кызыктуусу, репликалардын санына негизделген конфигурация генератору гана бар (эгер кимде бир кыйла кыска жана жарашыктуу вариант болсо, аны комментарийлерде бөлүшүңүз):

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

Биз аны сыноо чөйрөсүнө чыгарып, текшеребиз:

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

Ката текстин издөө эч кандай жыйынтык берген жок, бирок суроо үчүн "microuter php"Биринчи планда долбоордун эң эски чечилбеген көйгөйү болгон - колдоосунун жетишсиздиги memcached бинардык протокол.

NB: Memcachedдеги ASCII протоколу бинардык протоколго караганда жайыраак жана ырааттуу ачкычтарды хэширлөөнүн стандарттык каражаттары экилик протокол менен гана иштейт. Бирок бул конкреттүү иш үчүн көйгөй жаратпайт.

Айла баштыкта: сиз ASCII протоколуна өтсөңүз болот жана баары иштейт.... Бирок, бул учурда жооп издөө адаты php.net боюнча документтер ырайымсыз тамаша ойноду. Сиз ал жерден туура жооп таба албайсыз ... эгерде, албетте, сиз бөлүмдүн кайсы жерине чейин жылдырсаңыз "Колдонуучунун кошкон жазуулары" ишенимдүү жана болот адилетсиз төмөндөтүлгөн жооп.

Ооба, туура вариант аты memcached.sess_binary_protocol. Аны өчүрүү керек, андан кийин сессиялар иштей баштайт. Болгону mcrouter менен контейнерди PHP менен подкачка салуу гана калды!

жыйынтыктоо

Ошентип, жөн гана инфраструктуралык өзгөртүүлөр менен биз көйгөйдү чече алдык: мемкэштелген катага чыдамдуулук маселеси чечилди жана кэш сактоонун ишенимдүүлүгү жогорулады. Тиркеме үчүн ачык артыкчылыктардан тышкары, бул платформада иштөөдө маневр үчүн орун берди: бардык компоненттер резервге ээ болгондо, администратордун жашоосу абдан жөнөкөйлөштүрүлөт. Ооба, бул ыкманын да кемчиликтери бар, ал "балдак" сыяктуу көрүнүшү мүмкүн, бирок ал акчаны үнөмдөп, көйгөйдү көмүп, жаңысын пайда кылбаса - эмне үчүн?

PS

Биздин блогдон дагы окуңуз:

Source: www.habr.com

DDoS коргоосу, VPS VDS серверлери бар сайттар үчүн ишенимдүү хостинг сатып алыңыз 🔥 DDoS коргоосу, VPS VDS серверлери бар ишенимдүү веб-сайт хостингин сатып алыңыз | ProHoster