هل يحتاج عنقود Kubernetes على موقعين إلى ثلاثة ناخبين من etcd؟
ثلاث عُقد للتحكم في موقعي VPN ما زالت تفقد النصاب عندما ينقطع الموقع الأكبر. عُدّ ناخبي etcd الحقيقيين واختر الخسارة التي تنجو منها.
ثلاث آلات افتراضية للتحكم تبدو كثلاث فرص للنجاة من ليلة سيئة. لكنها ليست كذلك، والمسافة بين هذين الاعتقادين هي ما يحوّل تصميمًا أنيقًا من ثلاث عُقد إلى عنقود يتوقف عن قبول الكتابة عندما يفقد مبنى واحد الكهرباء. رابط VPN بين الموقعين يجعل الآلات قابلة للوصول إحداها من الأخرى ويخفي المشكلة بدل أن يحلّها. تُحسب الأصوات لكل عضو في etcd، ويمكن أن يبقى عضوان من هؤلاء خلف مفتاح واحد ومزوّد طاقة غير منقطع واحد وخط ربط واحد.
ثلاث عُقد للتحكم، ونطاق فشل واحد
تشغّل kubectl get nodes فترى ثلاثة مدخلات للتحكم وتصنّف العنقود على أنه عالي الإتاحة. هذا العدد يصف السعة القابلة للجدولة، لا القدرة على النجاة. في kubeadm الذي يُبقى دون etcd خارجي، تستضيف كل عقدة تحكم عضوًا أيضًا، فثلاث عُقد تمنحك فعلًا ثلاثة ناخبين. أما هل تفشل هؤلاء الناخبون باستقلال، فهو سؤال منفصل لا تستطيع قائمة العُقد الإجابة عنه.
آلتان افتراضيتان على منصة محاكاة واحدة، ورفّان على تغذية كهربائية واحدة، وخطّا ربط من مزوّد خدمة واحد: كل زوج نطاق واحد يرتدي اسمَي مضيف. اكتب التوزيع وسجّل ما يتشاركه كل ناخب — منصة المحاكاة، ووحدة توزيع الطاقة، ومفتاح أعلى الرف، ومصفوفة التخزين، وجهاز NAT، ومركّز VPN. ثم أزل كل عنصر مشترك على الورق وأعد عدّ الأصوات المتبقية. العنقود الذي يفقد ناخبين بسبب مضيف واحد فاشل كان طوال الوقت عنقود ناخب واحد؛ لم يسأله أحد السؤال بعد.
ما يمكن أن ينجو منه انقسام الموقعين وما لا يمكن
حين تُوزّع ثلاثة أصوات بواقع صوتين وصوت واحد على موقعين، يحتفظ الجانب الأكبر بالنصاب عندما يختفي الموقع الآخر، ولا يفعل جانب الصوت الواحد ذلك أبدًا. هذا التفاوت حساب، لا ضبط. أي عنقود etcd قائم على الأغلبية وموزّع على موقعين مستقلين تمامًا يفشل في اختبار «اخسر أي موقع وواصل الالتزام»، لأن على الجانبين معًا أن يمتلكا أكثر من نصف الأصوات في الوقت نفسه.
الجدول أدناه أسرع طريقة لمعرفة أي أعطال اشتريتها فعلًا. اقرأ كل صف هكذا: إذا اختفى هذا الصف بأكمله الليلة، هل يستطيع الناجون رغم ذلك الالتزام بكتابة؟
| What disappears | Voters left | Writes still commit |
|---|---|---|
| Site B, holding voter 3 | 2 of 3 | Yes |
| Site A, holding voters 1 and 2 | 1 of 3 | No |
| One hypervisor carrying any two voters | 1 of 3 | No |
| The inter-site VPN only | 2 of 3 on one side | Only on the majority side |
لماذا لا يضيف النفق صوتًا أبدًا
VPN نقل، لا عضو. يمكنه جعل ناخب بعيد قابلًا للوصول، ويمكنه تحويل انقسام إلى شيء يشبه مهلة بطيئة، وهذا كل ما يقدّمه للنصاب. ما يضيفه حقًا هو الكلفة، لأن كل التزام يجب أن يعبر الرابط، وetcd يدفع تلك الرحلة ذهابًا وإيابًا في الكتابات التي تمسّ سجل raft. والمسار المتذبذب يحوّل النسخ إلى إعادات ومحاولات انتخاب.
الانقسامات هي حيث يتوقع الناس السحر، فكن دقيقًا بشأنها. إذا انقطع الرابط بينما يجلس القائد القديم في جانب الصوت الواحد، فلا يستطيع ذلك الجانب الالتزام وينزل القائد حالما تنتهي مهلة الانتخاب، بينما ينتخب جانب الصوتين بديلًا. أما دليل etcd لأنماط الفشل فيشرح السلوك بوضوح: خدمة مستمرة في جانب الأغلبية، ولا عنقود ثانٍ قابل للكتابة في الجانب المعزول.
اختر أي انقطاع تشتريه
تصميم «اثنان زائد واحد» مشروع عندما يكون الموقع A هو الأساسي، وتقبل أن خسارته تعني خسارة كتابات مستوى التحكم حتى يتصرف أحد. وما يجعله عيبًا هو ترك ذلك القرار ضمنيًا. دوّنه في دليل التشغيل: أي موقع ينجو منه مستوى التحكم لديك، وما يفعله المشغّل عندما ينقطع الموقع الآخر الساعة 03:00.
إذا كان الشرط بدلًا من ذلك هو «قد يفشل أي موقع»، فيجب أن يحتفظ التوزيع بأغلبية في كل موقع، وثلاثة ناخبين على موقعين لا يستطيعون ذلك. إما أن تضيف نطاقًا ثالثًا مستقلًا حقًا — منطقة صغيرة لدى مزوّد آخر تصلح إذا كان المسار إليها مستقرًا — أو تنقسم إلى عنقودين مع etcd منفصل وتقبل الكلفة التشغيلية لذلك الانقسام. لا مخرج عبر الشاهد يتجنب هذا: فetcd ليس لديه عضو محكّم خفيف، لذا فالناخب الثالث عضو كامل بمتطلباته الخاصة من القرص والذاكرة والشبكة. ورسم مربع مكتوب عليه «شاهد» في المخطط لا يخلق شاهدًا.
النصاب ليس هو الخدمة
نصاب etcd يبقي خادم API قادرًا على قبول الكتابة، وهذا كل ما يبقيه. فحوص صحة موازن التحميل، والدخول، ووصول CNI عبر النفق، ومناطق ربط الأحجام، ونسخ التطبيق، كلها تحتاج جوابها الخاص. ويمكن لعنقود أن يحتفظ بأغلبية نظيفة ويظل لا يقدم شيئًا مفيدًا للمستخدمين.
ثم تحقّق من العضوية التي تظن أنك تملكها، لأن المخططات تنحرف:
kubectl -n kube-system get pods -l component=etcd -o wide
kubectl get endpoints kube-apiserver -n default
etcdctl member list -w table
قارن قائمة الأعضاء بمخطط التوزيع. إذا كانت عضويتان تُحلّان إلى المضيف نفسه أو الرفّ نفسه، فالمخطط هو الخطأ وليس العنقود، وتغيير الحجم حول طوبولوجيا خاطئة لا يشتري إلا نسخة أغلى من الانقطاع نفسه.
قبل اعتماد أي تصميم من ثلاثة ناخبين، أجب عن أربعة أسئلة: كم ناخبًا يفقد الكهرباء معًا، وأي خسارة موقع ما زالت تترك أغلبية، وأين يجلس القائد عندما ينقطع النفق، وماذا يستطيع الموقع الناجي أن يفعل بعد ذلك. و«لا أعرف» في أي منها تعني أن العنقود ليس عالي الإتاحة بعد. إنه ثلاثة أجهزة كانت محظوظة.