Peralihan Tinder kepada Kubernetes

Catatan. terjemah: Kakitangan perkhidmatan Tinder yang terkenal di dunia baru-baru ini berkongsi beberapa butiran teknikal untuk memindahkan infrastruktur mereka ke Kubernetes. Proses itu mengambil masa hampir dua tahun dan menghasilkan pelancaran platform berskala sangat besar pada K8, yang terdiri daripada 200 perkhidmatan yang dihoskan pada 48 ribu kontena. Apakah kesukaran menarik yang dihadapi oleh jurutera Tinder dan apakah keputusan yang mereka perolehi? Baca terjemahan ini.

Peralihan Tinder kepada Kubernetes

Mengapa?

Hampir dua tahun lalu, Tinder memutuskan untuk memindahkan platformnya ke Kubernetes. Kubernetes akan membenarkan pasukan Tinder mengisi kontena dan beralih ke pengeluaran dengan usaha yang minimum melalui penggunaan yang tidak berubah (pengerahan tidak berubah). Dalam kes ini, pemasangan aplikasi, penggunaannya dan infrastruktur itu sendiri akan ditakrifkan secara unik mengikut kod.

Kami juga sedang mencari penyelesaian kepada masalah kebolehskalaan dan kestabilan. Apabila penskalaan menjadi kritikal, kami sering terpaksa menunggu beberapa minit untuk kejadian EC2 baharu berputar. Idea untuk melancarkan kontena dan mula melayani lalu lintas dalam beberapa saat dan bukannya minit menjadi sangat menarik kepada kami.

Proses itu ternyata sukar. Semasa penghijrahan kami pada awal 2019, kluster Kubernetes mencapai jisim kritikal dan kami mula menghadapi pelbagai masalah disebabkan volum trafik, saiz kluster dan DNS. Sepanjang perjalanan, kami menyelesaikan banyak masalah menarik yang berkaitan dengan pemindahan 200 perkhidmatan dan mengekalkan kluster Kubernetes yang terdiri daripada 1000 nod, 15000 pod dan 48000 kontena yang sedang berjalan.

Bagaimana?

Sejak Januari 2018, kita telah melalui pelbagai peringkat penghijrahan. Kami bermula dengan menyimpan semua perkhidmatan kami dan menggunakan perkhidmatan tersebut ke persekitaran awan ujian Kubernetes. Bermula pada bulan Oktober, kami mula memindahkan semua perkhidmatan sedia ada secara berkaedah kepada Kubernetes. Menjelang Mac tahun berikutnya, kami menyelesaikan penghijrahan dan kini platform Tinder berjalan secara eksklusif di Kubernetes.

Membina imej untuk Kubernetes

Kami mempunyai lebih 30 repositori kod sumber untuk perkhidmatan mikro yang dijalankan pada gugusan Kubernetes. Kod dalam repositori ini ditulis dalam bahasa yang berbeza (contohnya, Node.js, Java, Scala, Go) dengan berbilang persekitaran masa jalan untuk bahasa yang sama.

Sistem binaan direka bentuk untuk menyediakan "konteks binaan" yang boleh disesuaikan sepenuhnya untuk setiap perkhidmatan mikro. Ia biasanya terdiri daripada Dockerfile dan senarai arahan shell. Kandungan mereka boleh disesuaikan sepenuhnya, dan pada masa yang sama, semua konteks binaan ini ditulis mengikut format piawai. Penyeragaman konteks binaan membolehkan satu sistem binaan tunggal mengendalikan semua perkhidmatan mikro.

Peralihan Tinder kepada Kubernetes
Rajah 1-1. Proses binaan standard melalui bekas Builder

Untuk mencapai konsistensi maksimum antara masa larian (persekitaran masa jalan) proses binaan yang sama digunakan semasa pembangunan dan ujian. Kami menghadapi cabaran yang sangat menarik: kami perlu membangunkan satu cara untuk memastikan konsistensi persekitaran binaan merentas seluruh platform. Untuk mencapai ini, semua proses pemasangan dijalankan di dalam bekas khas. Pembina.

Pelaksanaan kontenanya memerlukan teknik Docker lanjutan. Builder mewarisi ID dan rahsia pengguna tempatan (seperti kunci SSH, bukti kelayakan AWS, dll.) yang diperlukan untuk mengakses repositori Tinder peribadi. Ia memasang direktori tempatan yang mengandungi sumber untuk menyimpan artifak binaan secara semula jadi. Pendekatan ini meningkatkan prestasi kerana ia menghapuskan keperluan untuk menyalin artifak binaan antara bekas Builder dan hos. Artifak binaan yang disimpan boleh digunakan semula tanpa konfigurasi tambahan.

Untuk sesetengah perkhidmatan, kami perlu mencipta bekas lain untuk memetakan persekitaran kompilasi kepada persekitaran masa jalan (contohnya, perpustakaan bcrypt Node.js menjana artifak binari khusus platform semasa pemasangan). Semasa proses penyusunan, keperluan mungkin berbeza antara perkhidmatan, dan Dockerfile terakhir disusun dengan cepat.

Seni bina dan penghijrahan kelompok Kubernetes

Pengurusan saiz kluster

Kami memutuskan untuk menggunakan kube-aws untuk penggunaan kluster automatik pada keadaan Amazon EC2. Pada mulanya, semuanya berfungsi dalam satu kumpulan nod yang sama. Kami segera menyedari keperluan untuk mengasingkan beban kerja mengikut saiz dan jenis contoh untuk menggunakan sumber yang lebih cekap. Logiknya ialah menjalankan beberapa pod berbilang benang yang dimuatkan ternyata lebih boleh diramal dari segi prestasi berbanding kewujudan bersamanya dengan sejumlah besar pod berbenang tunggal.

Pada akhirnya kami memutuskan:

  • m5.4x besar - untuk pemantauan (Prometheus);
  • c5.4x besar - untuk beban kerja Node.js (beban kerja berbenang tunggal);
  • c5.2x besar - untuk Java dan Go (beban kerja berbilang benang);
  • c5.4x besar β€” untuk panel kawalan (3 nod).

Penghijrahan

Salah satu langkah persediaan untuk berhijrah daripada infrastruktur lama ke Kubernetes ialah mengubah hala komunikasi terus sedia ada antara perkhidmatan kepada pengimbang beban baharu (Pengimbang Beban Elastik (ELB). Ia dicipta pada subnet tertentu awan peribadi maya (VPC). Subnet ini telah disambungkan kepada VPC Kubernetes. Ini membolehkan kami memindahkan modul secara beransur-ansur, tanpa mengambil kira susunan kebergantungan perkhidmatan tertentu.

Titik akhir ini dibuat menggunakan set wajaran rekod DNS yang mempunyai CNAME yang menghala ke setiap ELB baharu. Untuk menukar, kami menambah entri baharu yang menunjuk kepada ELB baharu perkhidmatan Kubernetes dengan berat 0. Kami kemudian menetapkan Masa Untuk Hidup (TTL) entri yang ditetapkan kepada 0. Selepas ini, pemberat lama dan baharu adalah perlahan-lahan dilaraskan, dan akhirnya 100% daripada beban telah dihantar ke pelayan baharu. Selepas penukaran selesai, nilai TTL kembali ke tahap yang lebih mencukupi.

Modul Java yang kami ada boleh mengatasi DNS TTL yang rendah, tetapi aplikasi Node tidak dapat. Salah seorang jurutera menulis semula sebahagian daripada kod kumpulan sambungan dan membungkusnya dengan pengurus yang mengemas kini kumpulan setiap 60 saat. Pendekatan yang dipilih berfungsi dengan baik dan tanpa sebarang penurunan prestasi yang ketara.

Pelajaran

Had Fabrik Rangkaian

Pada awal pagi 8 Januari 2019, platform Tinder secara tidak dijangka ranap. Sebagai tindak balas kepada peningkatan yang tidak berkaitan dalam kependaman platform pada awal pagi itu, bilangan pod dan nod dalam kelompok meningkat. Ini menyebabkan cache ARP kehabisan pada semua nod kami.

Terdapat tiga pilihan Linux yang berkaitan dengan cache ARP:

Peralihan Tinder kepada Kubernetes
(sumber)

gc_thresh3 - ini adalah had yang sukar. Kemunculan entri "limpahan meja jiran" dalam log bermakna walaupun selepas kutipan sampah (GC) segerak, tidak ada ruang yang mencukupi dalam cache ARP untuk menyimpan entri jiran. Dalam kes ini, kernel hanya membuang paket sepenuhnya.

Kami guna Flanel sebagai fabrik rangkaian dalam Kubernetes. Paket dihantar melalui VXLAN. VXLAN ialah terowong L2 yang dinaikkan di atas rangkaian L3. Teknologi ini menggunakan pengkapsulan MAC-in-UDP (MAC Address-in-User Datagram Protocol) dan membenarkan pengembangan segmen rangkaian Lapisan 2. Protokol pengangkutan pada rangkaian pusat data fizikal ialah IP ditambah UDP.

Peralihan Tinder kepada Kubernetes
Rajah 2–1. Gambar rajah flanel (sumber)

Peralihan Tinder kepada Kubernetes
Rajah 2–2. Pakej VXLAN (sumber)

Setiap nod pekerja Kubernetes memperuntukkan ruang alamat maya dengan topeng /24 daripada blok /9 yang lebih besar. Untuk setiap nod ini adalah bermakna satu entri dalam jadual penghalaan, satu entri dalam jadual ARP (pada antara muka flanel.1), dan satu entri dalam jadual pensuisan (FDB). Ia ditambah pada kali pertama nod pekerja dimulakan atau setiap kali nod baharu ditemui.

Selain itu, komunikasi nod-pod (atau pod-pod) akhirnya melalui antara muka eth0 (seperti yang ditunjukkan dalam gambar rajah Flanel di atas). Ini menghasilkan kemasukan tambahan dalam jadual ARP untuk setiap sumber dan hos destinasi yang sepadan.

Dalam persekitaran kita, jenis komunikasi ini sangat biasa. Untuk objek perkhidmatan dalam Kubernetes, ELB dibuat dan Kubernetes mendaftarkan setiap nod dengan ELB. ELB tidak mengetahui apa-apa tentang pod dan nod yang dipilih mungkin bukan destinasi akhir paket. Intinya ialah apabila nod menerima paket daripada ELB, ia menganggap ia mengambil kira peraturan iptables untuk perkhidmatan tertentu dan secara rawak memilih pod pada nod lain.

Pada masa kegagalan, terdapat 605 nod dalam kelompok. Atas sebab-sebab yang dinyatakan di atas, ini sudah memadai untuk mengatasi kepentingannya gc_thresh3, yang merupakan lalai. Apabila ini berlaku, bukan sahaja paket mula digugurkan, tetapi keseluruhan ruang alamat maya Flanel dengan topeng /24 hilang daripada jadual ARP. Komunikasi nod-pod dan pertanyaan DNS terganggu (DNS dihoskan dalam kelompok; baca kemudian dalam artikel ini untuk mendapatkan butiran).

Untuk menyelesaikan masalah ini, anda perlu meningkatkan nilai gc_thresh1, gc_thresh2 ΠΈ gc_thresh3 dan mulakan semula Flanel untuk mendaftar semula rangkaian yang hilang.

Penskalaan DNS yang tidak dijangka

Semasa proses migrasi, kami secara aktif menggunakan DNS untuk mengurus trafik dan memindahkan perkhidmatan secara beransur-ansur daripada infrastruktur lama kepada Kubernetes. Kami menetapkan nilai TTL yang agak rendah untuk RecordSets yang berkaitan dalam Route53. Apabila infrastruktur lama berjalan pada kejadian EC2, konfigurasi penyelesai kami menghala ke DNS Amazon. Kami mengambil mudah perkara ini dan kesan TTL yang rendah pada perkhidmatan kami dan perkhidmatan Amazon (seperti DynamoDB) sebahagian besarnya tidak disedari.

Semasa kami memindahkan perkhidmatan ke Kubernetes, kami mendapati DNS sedang memproses 250 ribu permintaan sesaat. Akibatnya, aplikasi mula mengalami tamat masa yang berterusan dan serius untuk pertanyaan DNS. Ini berlaku walaupun terdapat usaha yang luar biasa untuk mengoptimumkan dan menukar penyedia DNS kepada CoreDNS (yang pada beban puncak mencapai 1000 pod berjalan pada 120 teras).

Semasa menyelidik kemungkinan punca dan penyelesaian lain, kami mendapati artikel, menerangkan keadaan perlumbaan yang menjejaskan rangka kerja penapisan paket netfilter dalam Linux. Tamat masa yang kami perhatikan, ditambah dengan kaunter yang semakin meningkat masukkan_gagal dalam antara muka Flanel adalah konsisten dengan penemuan artikel.

Masalah berlaku pada peringkat Terjemahan Alamat Rangkaian Sumber dan Destinasi (SNAT dan DNAT) dan kemasukan seterusnya ke dalam jadual conntrack. Salah satu penyelesaian yang dibincangkan secara dalaman dan dicadangkan oleh komuniti ialah memindahkan DNS ke nod pekerja itu sendiri. Dalam kes ini:

  • SNAT tidak diperlukan kerana trafik kekal di dalam nod. Ia tidak perlu dihalakan melalui antara muka eth0.
  • DNAT tidak diperlukan kerana IP destinasi adalah setempat kepada nod, dan bukan pod yang dipilih secara rawak mengikut peraturan iptables.

Kami memutuskan untuk kekal dengan pendekatan ini. CoreDNS telah digunakan sebagai DaemonSet dalam Kubernetes dan kami melaksanakan pelayan DNS nod tempatan dalam resolusiv.conf setiap pod dengan menetapkan bendera --cluster-dns pasukan cubeletβ€Š. Penyelesaian ini ternyata berkesan untuk tamat masa DNS.

Walau bagaimanapun, kami masih melihat kehilangan paket dan peningkatan dalam kaunter masukkan_gagal dalam antara muka Flanel. Ini berterusan selepas penyelesaian dilaksanakan kerana kami dapat menghapuskan SNAT dan/atau DNAT untuk trafik DNS sahaja. Keadaan perlumbaan dipelihara untuk jenis lalu lintas lain. Nasib baik, kebanyakan paket kami adalah TCP, dan jika masalah berlaku ia hanya dihantar semula. Kami masih cuba mencari penyelesaian yang sesuai untuk semua jenis trafik.

Menggunakan Utusan untuk Pengimbangan Beban yang Lebih Baik

Semasa kami memindahkan perkhidmatan bahagian belakang ke Kubernetes, kami mula mengalami beban yang tidak seimbang antara pod. Kami mendapati bahawa HTTP Keepalive menyebabkan sambungan ELB tergantung pada pod sedia pertama bagi setiap penggunaan yang dilancarkan. Oleh itu, sebahagian besar trafik melalui peratusan kecil pod yang tersedia. Penyelesaian pertama yang kami uji ialah menetapkan MaxSurge kepada 100% pada penempatan baharu untuk senario kes terburuk. Kesannya ternyata tidak ketara dan tidak menjanjikan dari segi penggunaan yang lebih besar.

Penyelesaian lain yang kami gunakan ialah meningkatkan permintaan sumber secara buatan untuk perkhidmatan kritikal. Dalam kes ini, pod yang diletakkan berdekatan akan mempunyai lebih banyak ruang untuk bergerak berbanding dengan pod berat yang lain. Ia tidak akan berfungsi dalam jangka panjang sama ada kerana ia akan membazir sumber. Di samping itu, aplikasi Nod kami adalah satu-benang dan, oleh itu, hanya boleh menggunakan satu teras. Satu-satunya penyelesaian sebenar ialah menggunakan pengimbangan beban yang lebih baik.

Kami telah lama ingin menghargai sepenuhnya duta. Keadaan semasa membolehkan kami menggunakan cara yang sangat terhad dan mendapat keputusan segera. Envoy ialah proksi lapisan-XNUMX berprestasi tinggi, sumber terbuka, direka untuk aplikasi SOA yang besar. Ia boleh melaksanakan teknik pengimbangan beban lanjutan, termasuk percubaan semula automatik, pemutus litar dan pengehadan kadar global. (Catatan. terjemah: Anda boleh membaca lebih lanjut tentang ini dalam artikel ini tentang Istio, yang berdasarkan Utusan.)

Kami menghasilkan konfigurasi berikut: mempunyai kereta sampingan Utusan untuk setiap pod dan satu laluan, dan sambungkan kluster ke kontena secara setempat melalui port. Untuk meminimumkan potensi melata dan mengekalkan jejari pukulan yang kecil, kami menggunakan kumpulan pod proksi hadapan Envoy, satu bagi setiap Zon Ketersediaan (AZ) untuk setiap perkhidmatan. Mereka bergantung pada enjin penemuan perkhidmatan ringkas yang ditulis oleh salah seorang jurutera kami yang hanya mengembalikan senarai pod dalam setiap AZ untuk perkhidmatan tertentu.

Utusan hadapan perkhidmatan kemudian menggunakan mekanisme penemuan perkhidmatan ini dengan satu kluster dan laluan huluan. Kami menetapkan tamat masa yang mencukupi, meningkatkan semua tetapan pemutus litar dan menambah konfigurasi percubaan semula yang minimum untuk membantu dengan kegagalan tunggal dan memastikan penggunaan lancar. Kami meletakkan TCP ELB di hadapan setiap Utusan hadapan perkhidmatan ini. Walaupun keepalive daripada lapisan proksi utama kami tersekat pada beberapa pod Envoy, mereka masih dapat mengendalikan beban dengan lebih baik dan dikonfigurasikan untuk mengimbangi melalui least_request di bahagian belakang.

Untuk penggunaan, kami menggunakan cangkuk praStop pada kedua-dua pod aplikasi dan pod kereta sisi. Cangkuk mencetuskan ralat dalam menyemak status titik akhir pentadbir yang terletak pada bekas kereta sisi dan tidur seketika untuk membolehkan sambungan aktif ditamatkan.

Salah satu sebab kami dapat bergerak dengan pantas adalah disebabkan oleh metrik terperinci yang dapat kami sepadukan dengan mudah ke dalam pemasangan Prometheus biasa. Ini membolehkan kami melihat dengan tepat apa yang berlaku semasa kami melaraskan parameter konfigurasi dan mengagihkan semula trafik.

Hasilnya adalah serta-merta dan jelas. Kami bermula dengan perkhidmatan yang paling tidak seimbang, dan pada masa ini ia beroperasi di hadapan 12 perkhidmatan paling penting dalam kluster. Tahun ini kami merancang peralihan kepada rangkaian perkhidmatan penuh dengan penemuan perkhidmatan yang lebih maju, pemutus litar, pengesanan outlier, pengehadan kadar dan pengesanan.

Peralihan Tinder kepada Kubernetes
Rajah 3–1. Penumpuan CPU satu perkhidmatan semasa peralihan kepada Utusan

Peralihan Tinder kepada Kubernetes

Peralihan Tinder kepada Kubernetes

Keputusan akhir

Melalui pengalaman dan penyelidikan tambahan ini, kami telah membina pasukan infrastruktur yang kukuh dengan kemahiran yang kukuh dalam mereka bentuk, menggunakan dan mengendalikan kluster Kubernetes yang besar. Semua jurutera Tinder kini mempunyai pengetahuan dan pengalaman untuk membungkus bekas dan menggunakan aplikasi ke Kubernetes.

Apabila keperluan untuk kapasiti tambahan timbul pada infrastruktur lama, kami terpaksa menunggu beberapa minit untuk contoh EC2 baharu dilancarkan. Kini bekas mula berjalan dan mula memproses trafik dalam beberapa saat dan bukannya beberapa minit. Menjadualkan berbilang bekas pada satu contoh EC2 juga memberikan kepekatan mendatar yang lebih baik. Hasilnya, kami meramalkan pengurangan ketara dalam kos EC2019 pada 2 berbanding tahun lepas.

Penghijrahan mengambil masa hampir dua tahun, tetapi kami menyelesaikannya pada Mac 2019. Pada masa ini, platform Tinder berjalan secara eksklusif pada kluster Kubernetes yang terdiri daripada 200 perkhidmatan, 1000 nod, 15 pod dan 000 kontena berjalan. Infrastruktur bukan lagi domain tunggal pasukan operasi. Semua jurutera kami berkongsi tanggungjawab ini dan mengawal proses membina dan menggunakan aplikasi mereka menggunakan kod sahaja.

PS daripada penterjemah

Baca juga siri artikel di blog kami:

Sumber: www.habr.com

Tambah komen