افقی طور پر memcached پیمانے کے لیے mcrouter کا استعمال

افقی طور پر memcached پیمانے کے لیے mcrouter کا استعمال

کسی بھی زبان میں زیادہ بوجھ والے پراجیکٹس کو تیار کرنے کے لیے ایک خاص نقطہ نظر اور خصوصی ٹولز کے استعمال کی ضرورت ہوتی ہے، لیکن جب بات پی ایچ پی میں ایپلی کیشنز کی ہو تو صورتحال اس قدر گھمبیر ہو سکتی ہے کہ آپ کو ترقی کرنا پڑتی ہے، مثال کے طور پر، اپنا ایپلیکیشن سرور. اس نوٹ میں ہم میم کیچڈ میں تقسیم شدہ سیشن اسٹوریج اور ڈیٹا کیشنگ کے ساتھ واقف درد کے بارے میں بات کریں گے اور ہم نے ایک "وارڈ" پروجیکٹ میں ان مسائل کو کیسے حل کیا۔

اس موقع کا ہیرو سمفونی 2.3 فریم ورک پر مبنی ایک پی ایچ پی ایپلی کیشن ہے، جو اپ ڈیٹ کرنے کے کاروباری منصوبوں میں بالکل شامل نہیں ہے۔ کافی معیاری سیشن سٹوریج کے علاوہ، اس پراجیکٹ کا مکمل استعمال ہوا۔ "سب کچھ کیشنگ" کی پالیسی memcached میں: ڈیٹا بیس اور API سرورز کی درخواستوں کے جوابات، مختلف جھنڈے، کوڈ پر عمل درآمد کو مطابقت پذیر بنانے کے لیے تالے اور بہت کچھ۔ ایسی صورت حال میں، میم کیچڈ کا ٹوٹنا ایپلی کیشن کے آپریشن کے لیے مہلک بن جاتا ہے۔ اس کے علاوہ، کیشے کا نقصان سنگین نتائج کا باعث بنتا ہے: ڈی بی ایم ایس سیون پر پھٹنا شروع ہو جاتا ہے، API سروسز درخواستوں پر پابندی لگانا شروع کر دیتی ہیں، وغیرہ۔ صورتحال کو مستحکم کرنے میں دسیوں منٹ لگ سکتے ہیں، اور اس دوران سروس انتہائی سست یا مکمل طور پر دستیاب نہیں ہوگی۔

ہمیں فراہم کرنے کی ضرورت تھی۔ تھوڑی محنت کے ساتھ ایپلیکیشن کو افقی طور پر پیمانہ کرنے کی صلاحیت، یعنی سورس کوڈ میں کم سے کم تبدیلیوں کے ساتھ اور مکمل فعالیت کو محفوظ کیا گیا ہے۔ کیشے کو نہ صرف ناکامیوں کے خلاف مزاحم بنائیں بلکہ اس سے ڈیٹا کے نقصان کو کم سے کم کرنے کی کوشش کریں۔

خود memcached کے ساتھ کیا غلط ہے؟

عام طور پر، PHP کے لیے memcached ایکسٹینشن ڈسٹری بیوٹ شدہ ڈیٹا اور سیشن اسٹوریج کو باکس سے باہر سپورٹ کرتی ہے۔ مستقل کلیدی ہیشنگ کا طریقہ کار آپ کو بہت سارے سرورز پر ڈیٹا کو یکساں طور پر تقسیم کرنے کی اجازت دیتا ہے، ہر مخصوص کلید کو گروپ سے مخصوص سرور پر منفرد طریقے سے ایڈریس کرتا ہے، اور بلٹ ان فیل اوور ٹولز کیشنگ سروس کی اعلی دستیابی کو یقینی بناتے ہیں (لیکن بدقسمتی سے، کوئی مواد نہیں).

سیشن اسٹوریج کے ساتھ چیزیں تھوڑی بہتر ہیں: آپ ترتیب دے سکتے ہیں۔ memcached.sess_number_of_replicas، جس کے نتیجے میں ڈیٹا کو ایک ساتھ کئی سرورز پر محفوظ کیا جائے گا، اور ایک میمکیچ مثال کے ناکام ہونے کی صورت میں، ڈیٹا کو دوسروں سے منتقل کیا جائے گا۔ تاہم، اگر سرور ڈیٹا کے بغیر آن لائن واپس آجاتا ہے (جیسا کہ عام طور پر دوبارہ شروع ہونے کے بعد ہوتا ہے)، کچھ چابیاں اس کے حق میں دوبارہ تقسیم کردی جائیں گی۔ درحقیقت اس کا مطلب ہوگا۔ سیشن ڈیٹا کا نقصان, چونکہ مس ہونے کی صورت میں کسی اور نقل پر "جانے" کا کوئی طریقہ نہیں ہے۔

معیاری لائبریری ٹولز کا مقصد بنیادی طور پر ہے۔ افقی اسکیلنگ: وہ آپ کو کیشے کو بڑے سائز تک بڑھانے اور مختلف سرورز پر ہوسٹ کردہ کوڈ سے اس تک رسائی فراہم کرنے کی اجازت دیتے ہیں۔ تاہم، ہماری صورت حال میں، ذخیرہ شدہ ڈیٹا کا حجم کئی گیگا بائٹس سے زیادہ نہیں ہے، اور ایک یا دو نوڈس کی کارکردگی کافی ہے۔ اس کے مطابق، کام کرنے کی حالت میں کم از کم ایک کیشے کی مثال کو برقرار رکھتے ہوئے memcached کی دستیابی کو یقینی بنانے کے لیے واحد مفید معیاری ٹولز ہوسکتے ہیں۔ تاہم، اس موقع سے بھی فائدہ اٹھانا ممکن نہیں تھا... یہاں پر پراجیکٹ میں استعمال کیے گئے فریم ورک کی قدیمی کو یاد کرنے کے قابل ہے، یہی وجہ ہے کہ سرورز کے ایک تالاب کے ساتھ ایپلی کیشن کو کام کرنے کے لیے حاصل کرنا ناممکن تھا۔ آئیے سیشن ڈیٹا کے ضائع ہونے کو بھی نہ بھولیں: صارفین کے بڑے لاگ آؤٹ سے گاہک کی آنکھ پھڑک اٹھی۔

مثالی طور پر اس کی ضرورت تھی۔ میم کیشڈ اور بائی پاس ریپلیکس میں ریکارڈز کی نقل غلطی یا غلطی کی صورت میں۔ اس حکمت عملی کو نافذ کرنے میں ہماری مدد کی۔ میکروٹر.

میکروٹر

یہ ایک 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. اگرچہ میکروٹر ڈیٹا کو دستیاب کیشز میں شامل کرے گا، کالنگ پی ایچ پی فنکشن ایک غلطی واپس کرے گا اور نوٹس تیار کرے گا۔ AllMajorityRoute اتنا سخت نہیں ہے اور اوپر بیان کردہ مسائل کے بغیر نصف یونٹس کو سروس سے ہٹانے کی اجازت دیتا ہے۔

اہم نقصان یہ اسکیم یہ ہے کہ اگر واقعی کیشے میں کوئی ڈیٹا نہیں ہے، تو کلائنٹ کی طرف سے ہر درخواست کے لیے N کی درخواستوں پر عمل درآمد کیا جائے گا۔ تمام پول میں سرورز. ہم تالابوں میں سرورز کی تعداد کو کم کر سکتے ہیں، مثال کے طور پر، دو کر سکتے ہیں: سٹوریج کی وشوسنییتا کی قربانی، ہم حاصل کرتے ہیںоدرخواستوں سے لاپتہ چابیاں تک تیز رفتار اور کم بوجھ۔

NB: آپ کو میکروٹر سیکھنے کے لیے مفید لنکس بھی مل سکتے ہیں۔ ویکی پر دستاویزات и منصوبے کے مسائل (بشمول بند شدہ)، مختلف کنفیگریشنوں کے پورے اسٹور ہاؤس کی نمائندگی کرتا ہے۔

میکروٹر بنانا اور چلانا

ہماری ایپلیکیشن (اور خود میم کیچڈ) Kubernetes میں چلتی ہے - اس کے مطابق، mcrouter بھی وہیں واقع ہے۔ کے لیے کنٹینر اسمبلی ہم استعمال کرتے ہیں werf، تشکیل جس کے لئے اس طرح نظر آئے گا:

NB: مضمون میں دی گئی فہرستیں مخزن میں شائع کی گئی ہیں۔ فلانٹ/مکراؤٹر.

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: memcached میں ASCII پروٹوکول بائنری پروٹوکول سے سست ہے، اور مستقل کلید ہیشنگ کے معیاری ذرائع صرف بائنری پروٹوکول کے ساتھ کام کرتے ہیں۔ لیکن یہ کسی مخصوص کیس کے لیے مسائل پیدا نہیں کرتا۔

چال تھیلے میں ہے: آپ کو بس ASCII پروٹوکول پر جانا ہے اور سب کچھ کام کرے گا.... تاہم، اس معاملے میں، میں جوابات تلاش کرنے کی عادت php.net پر دستاویزات ایک ظالمانہ مذاق کھیلا. آپ کو وہاں صحیح جواب نہیں ملے گا... جب تک کہ، یقیناً، آپ آخر تک سکرول کرتے ہیں، جہاں سیکشن میں ہے۔ "صارف کے تعاون کردہ نوٹ" وفادار ہو گا اور غیر منصفانہ طور پر مسترد جواب.

ہاں، صحیح آپشن کا نام ہے۔ memcached.sess_binary_protocol. اسے غیر فعال کرنا ضروری ہے، جس کے بعد سیشن کام کرنا شروع کر دیں گے۔ جو کچھ باقی ہے وہ یہ ہے کہ میکروٹر والے کنٹینر کو پی ایچ پی کے ساتھ پوڈ میں ڈالنا ہے!

حاصل يہ ہوا

اس طرح، صرف بنیادی ڈھانچے کی تبدیلیوں کے ساتھ، ہم اس مسئلے کو حل کرنے میں کامیاب ہو گئے: میمکیچڈ فالٹ ٹولرنس کا مسئلہ حل ہو گیا ہے، اور کیش اسٹوریج کی وشوسنییتا کو بڑھا دیا گیا ہے۔ ایپلیکیشن کے واضح فوائد کے علاوہ، اس نے پلیٹ فارم پر کام کرتے وقت تدبیر کی گنجائش فراہم کی: جب تمام اجزاء کے پاس ریزرو ہوتے ہیں، منتظم کی زندگی بہت آسان ہوجاتی ہے۔ جی ہاں، اس طریقے کی اپنی خامیاں بھی ہیں، یہ ایک "بیساکھی" کی طرح نظر آسکتی ہے، لیکن اگر یہ پیسے بچاتا ہے، مسئلہ کو دفن کرتا ہے اور نئے پیدا نہیں کرتا ہے - کیوں نہیں؟

PS

ہمارے بلاگ پر بھی پڑھیں:

ماخذ: www.habr.com

نیا تبصرہ شامل کریں