Истифодаи mcrouter барои миқёси memcached ба таври уфуқӣ

Истифодаи mcrouter барои миқёси memcached ба таври уфуқӣ

Таҳияи лоиҳаҳои сербориш ба ҳар забон муносибати махсус ва истифодаи абзорҳои махсусро талаб мекунад, аммо вақте сухан дар бораи замимаҳо дар PHP меравад, вазъ метавонад то ҳадде бадтар шавад, ки шумо бояд масалан, сервери барномавии худ. Дар ин ёддошт мо дар бораи дарди ошно бо нигоҳдории сеанси тақсимшуда ва кэшкунии маълумот дар memcached ва чӣ гуна мо ин мушкилотро дар як лоиҳаи "шӯъба" ҳал кардем.

Қаҳрамони ин чорабинӣ як барномаи PHP дар асоси чаҳорчӯбаи symfony 2.3 мебошад, ки дар нақшаҳои бизнеси навсозӣ умуман дохил карда нашудааст. Илова ба нигаҳдории сессияи стандартӣ, ин лоиҳа пурра истифода бурд сиёсати "кэшкунии ҳама чиз" дар memcached: посухҳо ба дархостҳо ба пойгоҳи додаҳо ва серверҳои API, парчамҳои гуногун, қулфҳо барои ҳамоҳангсозии иҷрои код ва ғайра. Дар чунин вазъият, вайроншавии memcached барои кори барнома марговар мегардад. Илова бар ин, талафоти кэш ба оқибатҳои ҷиддӣ оварда мерасонад: DBMS дар қабатҳо ба шикастан оғоз мекунад, хидматҳои API ба манъи дархостҳо шурӯъ мекунанд ва ғайра. Муътадилгардонии вазъ метавонад даҳҳо дақиқа тӯл кашад ва дар ин муддат хидмат хеле суст ё тамоман дастнорас хоҳад буд.

таъмин кардан лозим буд қобилияти ба таври уфуқӣ васеъ кардани барнома бо кӯшиши кам, яъне. бо тағироти ҳадди ақал ба коди сарчашма ва функсияҳои пурра нигоҳ дошта мешаванд. Кэшро на танҳо ба нокомиҳо тобовар созед, балки кӯшиш кунед, ки талафоти маълумотро аз он кам кунед.

Худи memcached чӣ айб дорад?

Умуман, васеъшавии memcached барои PHP маълумоти тақсимшуда ва нигоҳдории сессияро аз қуттӣ дастгирӣ мекунад. Механизми хэшкунии пайвастаи калид ба шумо имкон медиҳад, ки маълумотро дар бисёр серверҳо яксон ҷойгир кунед, ба таври нотакрор ба ҳар як калиди мушаххас ба сервери мушаххас аз гурӯҳ муроҷиат кунед ва абзорҳои дарунсохт дастрасии баланди хидмати кэшро таъмин мекунанд (аммо, мутаассифона, маълумот нест).

Бо нигаҳдории сессия корҳо каме беҳтаранд: шумо метавонед танзим кунед memcached.sess_number_of_replicas, ки дар натиҷа маълумот якбора дар якчанд серверҳо нигоҳ дошта мешавад ва дар сурати нокомии як инстансияи memcached, маълумот аз дигарон интиқол дода мешавад. Аммо, агар сервер бе маълумот баргардад (чунон ки одатан пас аз бозоғозӣ рӯй медиҳад), баъзе аз калидҳо ба манфиати он дубора тақсим карда мешаванд. Дар асл ин маънои онро дорад гум кардани маълумоти сессия, зеро дар сурати гум шудан ба нусхаи дигар ҳеҷ роҳе барои "рафтан" вуҷуд надорад.

Воситаҳои стандартии китобхона асосан ба он нигаронида шудаанд уфуқӣ миқёс: онҳо ба шумо имкон медиҳанд, ки кэшро ба андозаи азим зиёд кунед ва дастрасӣ ба он аз коди дар серверҳои гуногун ҷойгиршударо таъмин кунед. Аммо, дар шароити мо, ҳаҷми маълумоти захирашуда аз якчанд гигабайт зиёд нест ва кори як ё ду гиреҳ комилан кофӣ аст. Мувофиқи он, ягона абзорҳои стандартии муфид барои таъмини мавҷудияти memcached ҳангоми нигоҳ доштани ҳадди аққал як нусхаи кэш дар ҳолати корӣ буда метавонанд. Аммо ҳатто аз ин фурсат истифода бурдан муяссар нашуд... Дар ин ҷо ба ёдоварӣ кардан бамаврид аст, ки чаҳорчӯбаи дар лоиҳа истифодашуда қадимӣ буд, бинобар ин имконнопазир буд, ки замима бо як ҳавзи серверҳо кор кунад. Биёед инчунин дар бораи гум шудани маълумотҳои сессия фаромӯш накунем: чашми муштарӣ аз баромади азими корбарон чилва кард.

Идеалӣ он талаб карда шуд такрори сабтҳо дар репликаҳои memcached ва bypass дар сурати хато ва ё хато. Ба мо дар татбиқи ин стратегия кӯмак кард 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 бо ҳавзи се сервер, пас ҳама дархостҳо аввал ба мисоли memcached аввал меоянд ва боқимонда ҳангоми мавҷуд набудани маълумот дархостҳоро ба таври боқимонда қабул мекунанд. Чунин муносибат ба он оварда мерасонад сарбории аз ҳад зиёд дар сервери аввал дар рӯйхат, бинобар ин тасмим гирифта шуд, ки се ҳавз бо суроғаҳо дар пайдарпайии гуногун тавлид карда, онҳоро ба таври тасодуфӣ интихоб кунанд.
  • Ҳамаи дархостҳои дигар (ва ин сабт аст) бо истифода аз коркард карда мешаванд AllMajorityRoute. Ин коркардкунанда ба ҳама серверҳои ҳавз дархостҳо мефиристад ва аз ҳадди ақал N/2 + 1-и онҳо посухҳоро интизор аст. Аз истифода AllSyncRoute барои амалиёти навиштан бояд даст кашида шавад, зеро ин усул посухи мусбатро талаб мекунад всех серверҳо дар гурӯҳ - дар акси ҳол он бармегардад SERVER_ERROR. Гарчанде ки mcrouter маълумотро ба кэшҳои дастрас илова мекунад, функсияи зангзании PHP хато бармегардонад ва огоҳӣ эҷод хоҳад кард. AllMajorityRoute чандон сахтгир нест ва имкон медихад, ки то нисфи агрегатхо бе проблемахои дар боло зикршуда аз кор бароварда шаванд.

Камбудии асосӣ Ин схема аз он иборат аст, ки агар воқеан дар кэш ягон маълумот мавҷуд набошад, пас барои ҳар як дархост аз муштарӣ N дархостҳо ба memcached воқеан иҷро мешаванд - ба ба ҳама серверҳо дар ҳавз. Мо метавонем шумораи серверҳоро дар ҳавзҳо, масалан, ба ду кам кунем: эътимоднокии нигаҳдории худро аз даст дода, мо ба даст меоремосуръати баландтар ва сарбории камтар аз дархостҳо ба калидҳои гумшуда.

NB: Шумо инчунин метавонед истинодҳои муфидро барои омӯзиши mcrouter пайдо кунед ҳуҷҷатҳо дар вики и масъалаҳои лоиҳа (аз ҷумла пӯшида), як анбори конфигуратсияҳои гуногунро ифода мекунад.

Сохтмон ва идора кардани mcrouter

Замимаи мо (ва худи memcached) дар Кубернетес кор мекунад - мувофиқан, mcrouter низ дар он ҷо ҷойгир аст. Барои монтажи контейнер истифода мебарем верф, конфигуратсия барои он чунин хоҳад буд:

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 >

Ҷустуҷӯи матни хато натиҷае надод, балки барои пурсиш "mcrouter php"Дар мадди аввал мушкилоти ҳалношудаи лоиҳа буд - набудани дастгирӣ протоколи дуии memcached.

NB: Протоколи ASCII дар memcached нисбат ба протоколи бинарӣ сусттар аст ва воситаҳои стандартии хэшкунии пайвастаи калидҳо танҳо бо протоколи бинарӣ кор мекунанд. Аммо ин барои як ҳолати мушаххас мушкилот эҷод намекунад.

Ҳилла дар халта аст: танҳо ба шумо лозим аст, ки ба протоколи ASCII гузаред ва ҳама чиз кор хоҳад кард.... Бо вуҷуди ин, дар ин ҳолат, одати ҷустуҷӯи ҷавоб дар ҳуҷҷатҳо дар php.net шӯхии бераҳмона бозид. Шумо дар он ҷо ҷавоби дурустро нахоҳед ёфт ... агар, албатта, шумо то ба охир ҳаракат кунед, дар куҷо дар қисмат "Қайдҳои саҳми корбар" вафодор мешавад ва ҷавоби беадолатона паст карда шудааст.

Бале, номи вариант дуруст аст memcached.sess_binary_protocol. Он бояд хомӯш карда шавад, ки пас аз он сессияҳо кор мекунанд. Танҳо ин аст, ки контейнер бо mcrouter ба pod бо PHP гузошта шавад!

хулоса

Ҳамин тариқ, танҳо бо тағироти инфрасохторӣ мо тавонистем мушкилотро ҳал кунем: масъала бо таҳаммулпазирии хатогиҳои memcached ҳал карда шуд ва эътимоднокии нигаҳдории кэш афзоиш ёфт. Илова бар бартариҳои баръало барои барнома, ин барои кор дар платформа имкон дод: вақте ки ҳама ҷузъҳо захира доранд, ҳаёти администратор хеле содда карда мешавад. Бале, ин усул нуқсонҳои худро ҳам дорад, метавонад ба «асгаб» монанд бошад, аммо агар пулро сарфа кунад, мушкилотро гӯр кунад ва боиси нав нашавад - чаро?

PS

Инчунин дар блоги мо хонед:

Манбаъ: will.com

Илова Эзоҳ