ሜምካቹን በአግድም ለመለካት mcrouterን በመጠቀም

ሜምካቹን በአግድም ለመለካት mcrouterን በመጠቀም

በማንኛውም ቋንቋ ከፍተኛ ጭነት ያላቸው ፕሮጀክቶችን ማዘጋጀት ልዩ አቀራረብ እና ልዩ መሳሪያዎችን መጠቀምን ይጠይቃል, ነገር ግን በ PHP ውስጥ ወደ አፕሊኬሽኖች ሲመጣ, ሁኔታው ​​በጣም ሊባባስ ስለሚችል ለምሳሌ ማዳበር አለብዎት. የራሱ መተግበሪያ አገልጋይ. በዚህ ማስታወሻ ውስጥ ስለ የተለመደው ህመም በተከፋፈለ የክፍለ-ጊዜ ማከማቻ እና በሜምካች ውስጥ የውሂብ መሸጎጫ እና እነዚህን ችግሮች በአንድ "ዋርድ" ፕሮጀክት ውስጥ እንዴት እንደፈታን እንነጋገራለን.

የዝግጅቱ ጀግና በሲምፎኒ 2.3 ማዕቀፍ ላይ የተመሠረተ የ PHP መተግበሪያ ነው ፣ ይህም ለማዘመን በቢዝነስ እቅዶች ውስጥ በጭራሽ አልተካተተም። ከመደበኛ የክፍለ-ጊዜ ማከማቻ በተጨማሪ ይህ ፕሮጀክት ሙሉ በሙሉ ጥቅም ላይ ውሏል "ሁሉንም ነገር መሸጎጥ" ፖሊሲ በሜምካሼድ ውስጥ፡ ለዳታቤዝ እና ለኤፒአይ አገልጋዮች ለሚቀርቡ ጥያቄዎች ምላሾች፣ የተለያዩ ባንዲራዎች፣ የኮድ አፈጻጸምን ለማመሳሰል መቆለፊያዎች እና ሌሎችም። በእንደዚህ ዓይነት ሁኔታ, የሜምኬድ ብልሽት ለትግበራው አሠራር ገዳይ ይሆናል. በተጨማሪም የመሸጎጫ መጥፋት ወደ አስከፊ መዘዞች ያመራል፡ ዲቢኤምኤስ በመገጣጠሚያዎች ላይ መፍረስ ይጀምራል፣ የኤፒአይ አገልግሎቶች ጥያቄዎችን መከልከል ይጀምራሉ፣ ወዘተ. ሁኔታውን ማረጋጋት አሥር ደቂቃዎችን ሊወስድ ይችላል, እና በዚህ ጊዜ አገልግሎቱ በጣም ቀርፋፋ ወይም ሙሉ በሙሉ አይገኝም.

ማቅረብ ነበረብን በትንሽ ጥረት አፕሊኬሽኑን በአግድም የመለካት ችሎታ፣ ማለትም እ.ኤ.አ. በምንጭ ኮድ ላይ በትንሹ ለውጦች እና ሙሉ ተግባራት ተጠብቀዋል። መሸጎጫው ውድቀቶችን የሚቋቋም ብቻ ሳይሆን የውሂብ መጥፋትንም ለመቀነስ ይሞክሩ።

በራሱ መሸጎጥ ምን ችግር አለው?

በአጠቃላይ፣ ለPHP የተመሰከረው ቅጥያ የተከፋፈለ ውሂብ እና የክፍለ-ጊዜ ማከማቻን ከሳጥኑ ውስጥ ይደግፋል። የማይለዋወጥ የቁልፍ ሃሽንግ ዘዴው ውሂብን በብዙ አገልጋዮች ላይ በእኩል እንዲያስቀምጡ ይፈቅድልዎታል ፣ ይህም እያንዳንዱን ልዩ ቁልፍ በልዩ ቡድን ውስጥ ላለ አገልጋይ አድራሻ ያቀርባል ፣ እና አብሮገነብ ያልተሳካላቸው መሳሪያዎች የመሸጎጫ አገልግሎቱን ከፍተኛ ተደራሽነት ያረጋግጣሉ (ግን በሚያሳዝን ሁኔታ) ምንም ውሂብ የለም).

በክፍለ-ጊዜ ማከማቻ ነገሮች ትንሽ የተሻሉ ናቸው፡ ማዋቀር ይችላሉ። memcached.sess_number_of_replicas, በዚህ ምክንያት ውሂቡ በአንድ ጊዜ በበርካታ አገልጋዮች ላይ ይከማቻል, እና አንድ የተመሰከረ ምሳሌ ካልተሳካ, ውሂቡ ከሌሎች ይተላለፋል. ነገር ግን፣ አገልጋዩ ያለመረጃ ተመልሶ ወደ ኦንላይን ከመጣ (ብዙውን ጊዜ ዳግም ከተጀመረ በኋላ እንደሚከሰት) አንዳንድ ቁልፎች በእሱ ሞገስ እንደገና ይሰራጫሉ። በእውነቱ ይህ ማለት ይሆናል የክፍለ ጊዜ ውሂብ ማጣት, በጠፋ ጊዜ ወደ ሌላ ቅጂ "መሄድ" የሚቻልበት መንገድ ስለሌለ.

መደበኛ የቤተ መፃህፍት መሳሪያዎች በዋናነት ያነጣጠሩ ናቸው። አግድም ስኬል: መሸጎጫውን ወደ ግዙፍ መጠኖች እንዲያሳድጉ እና በተለያዩ አገልጋዮች ላይ ከሚስተናገደው ኮድ እንዲደርሱበት ያስችሉዎታል። ሆኖም ግን, በእኛ ሁኔታ, የተከማቸ መረጃ መጠን ከበርካታ ጊጋባይት አይበልጥም, እና የአንድ ወይም ሁለት አንጓዎች አፈፃፀም በጣም በቂ ነው. በዚህ መሰረት፣ ብቸኛው ጠቃሚ መደበኛ መሳሪያዎች በስራ ሁኔታ ውስጥ ቢያንስ አንድ የመሸጎጫ ምሳሌ እየጠበቁ ሜምካሼድ መኖራቸውን ማረጋገጥ ሊሆን ይችላል። ይሁን እንጂ ይህን እድል እንኳን ለመጠቀም አልተቻለም... እዚህ ላይ በፕሮጀክቱ ውስጥ ጥቅም ላይ የዋለውን ማዕቀፍ ጥንታዊነት ማስታወስ ጠቃሚ ነው, ለዚህም ነው አፕሊኬሽኑ ከአገልጋይ ገንዳ ጋር አብሮ ለመስራት የማይቻልበት ምክንያት. እንዲሁም ስለ የክፍለ-ጊዜ ውሂብ መጥፋት መዘንጋት የለብንም: ከተጠቃሚዎች ግዙፍ መውጣት የደንበኛው አይን ተንቀጠቀጠ።

በሐሳብ ደረጃ ተፈላጊ ነበር። የተቀረጹ እና ቅጂዎችን በማለፍ መዝገቦችን ማባዛት። ስህተት ወይም ስህተት ከሆነ. ይህንን ስልት ተግባራዊ ለማድረግ ረድቶናል። mcrouter.

mcrouter

ይህ ችግሮቹን ለመፍታት በፌስቡክ የተሰራ 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 ውሂቡን ወደ ሚገኙ መሸጎጫዎች ቢያክልም ፣የጥሪው ፒኤችፒ ተግባር ስህተት ይመልሳል እና ማስታወቂያ ይፈጥራል። AllMajorityRoute ያን ያህል ጥብቅ አይደለም እና ከላይ ከተገለጹት ችግሮች ውጭ እስከ ግማሽ የሚሆኑት ክፍሎች ከአገልግሎት እንዲወጡ ያስችላቸዋል።

ዋና ጉዳቱ ይህ እቅድ በእውነቱ በመሸጎጫ ውስጥ ምንም ውሂብ ከሌለ ፣ ከዚያ ለእያንዳንዱ የደንበኛው ጥያቄ N ለመካድ ጥያቄዎች በትክክል ይፈጸማሉ - ወደ ለሁሉም ገንዳ ውስጥ አገልጋዮች. በገንዳዎች ውስጥ ያሉትን የአገልጋዮች ብዛት ወደ ሁለት መቀነስ እንችላለን-የማከማቻ አስተማማኝነትን መስዋዕት ማድረግ, እናገኛለንоከፍ ያለ ፍጥነት እና አነስተኛ ጭነት ከጥያቄዎች ወደ የጎደሉ ቁልፎች።

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)

... እና ይሳሉት። Helm ገበታ. የሚገርመው ነገር በተባዙት ብዛት ላይ የተመሰረተ የውቅር ጀነሬተር ብቻ ነው። (ማንም ሰው የበለጠ ቆንጆ እና የሚያምር አማራጭ ካለው በአስተያየቶቹ ውስጥ ያካፍሉት):

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

የስህተቱን ጽሑፍ መፈለግ ምንም ውጤት አላመጣም ፣ ግን ለጥያቄው "ማይክሮውተር php"በግንባር ቀደምትነት የፕሮጀክቱ ያልተፈታ ችግር ነበር - የድጋፍ እጦት memcached ሁለትዮሽ ፕሮቶኮል.

NBበሜምካቸድ ውስጥ ያለው የASCII ፕሮቶኮል ከሁለትዮሽ ቀርፋፋ ነው፣ እና መደበኛ የወጥ ቁልፍ ሃሽንግ መንገዶች ከሁለትዮሽ ፕሮቶኮል ጋር ብቻ ይሰራሉ። ነገር ግን ይህ ለአንድ የተወሰነ ጉዳይ ችግር አይፈጥርም.

ዘዴው በከረጢቱ ውስጥ ነው፡ ማድረግ ያለብዎት ወደ ASCII ፕሮቶኮል መቀየር ብቻ ነው እና ሁሉም ነገር ይሰራል .... ሆኖም ፣ በዚህ ጉዳይ ላይ ፣ በ ውስጥ መልሶችን የመፈለግ ልማድ ሰነዶች በ php.net ላይ ጭካኔ የተሞላበት ቀልድ ተጫውቷል። እዚያ ትክክለኛውን መልስ አያገኙም ... እርግጥ ነው, ወደ መጨረሻው እስካልሄዱ ድረስ, በክፍሉ ውስጥ "በተጠቃሚ ያበረከቱ ማስታወሻዎች" ታማኝ ይሆናል እና ፍትሃዊ ያልሆነ ምላሽ.

አዎ ትክክለኛው አማራጭ ስም ነው። memcached.sess_binary_protocol. መሰናከል አለበት, ከዚያ በኋላ ክፍለ-ጊዜዎቹ መስራት ይጀምራሉ. የሚቀረው እቃውን ከ mcrouter ጋር ወደ ፒኤችፒ ፖድ ውስጥ ማስገባት ብቻ ነው!

መደምደሚያ

ስለዚህ፣ በመሠረተ ልማት ለውጦች ብቻ ችግሩን መፍታት ችለናል፡ የተጨማለቀ ስህተት መቻቻል ጉዳይ ተፈቷል፣ እና የመሸጎጫ ማከማቻ አስተማማኝነት ጨምሯል። ለመተግበሪያው ግልጽ ከሆኑ ጥቅሞች በተጨማሪ ይህ በመድረክ ላይ በሚሰሩበት ጊዜ ለማንቀሳቀስ ቦታ ሰጥቷል-ሁሉም አካላት መጠባበቂያ ሲኖራቸው የአስተዳዳሪው ህይወት በጣም ቀላል ነው. አዎን, ይህ ዘዴም የራሱ ድክመቶች አሉት, እንደ "ክራች" ሊመስል ይችላል, ነገር ግን ገንዘብን ቢቆጥብ, ችግሩን ከቀበረ እና አዳዲሶችን ካላመጣ - ለምን አይሆንም?

PS

በብሎጋችን ላይ ያንብቡ፡-

ምንጭ: hab.com

አስተያየት ያክሉ