Mencapai Zero Downtime Deployment

40

Saya mencoba untuk mencapai penerapan downtime nol sehingga saya dapat menggunakan lebih sedikit selama jam-jam off dan lebih banyak selama jam-jam "lebih lambat" - atau kapan saja, secara teori.

Setup saya saat ini, agak disederhanakan:

  • Web Server A (.NET App)
  • Server Web B (Aplikasi .NET)
  • Database Server (SQL Server)

Proses penyebaran saya saat ini:

  1. "Hentikan" situs di Server Web A dan B
  2. Tingkatkan skema basis data untuk versi aplikasi yang digunakan
  3. Perbarui Server Web A
  4. Perbarui Server Web B
  5. Bawa semuanya kembali online

Masalah saat ini

Ini menyebabkan sejumlah kecil downtime setiap bulan - sekitar 30 menit. Saya melakukan ini di luar jam kerja, jadi itu bukan masalah besar - tapi itu adalah sesuatu yang saya ingin hindari.

Juga - tidak ada cara untuk benar-benar kembali. Saya biasanya tidak membuat skrip DB rollback - hanya skrip upgrade.

Memanfaatkan Load Balancer

Saya ingin sekali dapat meningkatkan satu Server Web sekaligus. Keluarkan Web Server A dari load balancer, tingkatkan, pasang kembali online, lalu ulangi untuk Web Server B.

Masalahnya adalah database. Setiap versi dari perangkat lunak saya perlu dijalankan terhadap versi database yang berbeda - jadi saya agak "mandek".

Kemungkinan Solusi

Solusi saat ini yang saya pertimbangkan adalah mengadopsi aturan berikut:

  • Jangan pernah menghapus tabel database.
  • Jangan pernah menghapus kolom basis data.
  • Jangan pernah mengganti nama kolom basis data.
  • Jangan pernah memesan ulang kolom.
  • Setiap prosedur yang tersimpan harus diversi.
    • Artinya - 'spFindAllThings' akan menjadi 'spFindAllThings_2' saat diedit.
    • Kemudian menjadi 'spFindAllThings_3' saat diedit lagi.
    • Aturan yang sama berlaku untuk tampilan.

Sementara, ini tampaknya agak ekstrem - saya pikir itu menyelesaikan masalah. Setiap versi aplikasi akan memukul DB dengan cara yang tidak melanggar. Kode mengharapkan hasil tertentu dari tampilan / prosedur tersimpan - dan ini membuat 'kontrak' itu valid. Masalahnya adalah - itu hanya merembes ceroboh. Saya tahu saya bisa membersihkan prosedur lama yang tersimpan setelah aplikasi dikerahkan untuk sementara waktu, tetapi hanya terasa kotor. Juga - itu tergantung pada semua pengembang mengikuti aturan ini, yang sebagian besar akan terjadi, tapi saya membayangkan seseorang akan membuat kesalahan.

Akhirnya - Pertanyaan Saya

  • Apakah ini ceroboh atau berantakan?
  • Adakah yang melakukannya dengan cara ini?
  • Bagaimana orang lain memecahkan masalah ini?
MattW
sumber
2
Di mana rencana backout Anda? Bagaimana Anda menguji apakah semuanya berfungsi dan tidak ada regresi?
Deer Hunter
3
Anda tidak perlu "tidak pernah": Anda "hanya" perlu memastikan bahwa setiap dua versi yang berdekatan dapat berjalan secara bersamaan. Ini membatasi jalur peningkatan Anda, tetapi tidak sesulit yang pernah bisa mengubah skema DB secara signifikan.
Joachim Sauer
Terima kasih Joachim ... Saya suka berbicara secara absolut sehingga ide dasarnya jelas - tetapi Anda benar, kami dapat memiliki kebijakan untuk mundur kompatibel dengan rilis N, pada titik mana kami dapat menghapus objek DB yang tidak perlu.
MattW
2
Anda akan ingin memiliki rencana rollback di tempat. Suatu hari kamu akan membutuhkannya.
Thorbjørn Ravn Andersen
1
Dalam pengalaman saya, untuk sebagian besar situs web, solusi Anda yang mungkin lebih buruk daripada masalah yang dipecahkannya. Kompleksitas yang akan ditambahkan akan lebih mahal daripada yang dapat Anda antisipasi sekarang. Mungkin berkali-kali lebih banyak waktu / upaya untuk melakukan perubahan dan menambah fitur. Saya hanya akan mempertimbangkan untuk situs yang benar-benar tidak bisa setiap memiliki downtime, pernah .
MGOwen

Jawaban:

14

Ini adalah pendekatan yang sangat pragmatis untuk peningkatan perangkat lunak yang didukung database. Itu dijelaskan oleh Martin Fowler dan Pramod Sadalage pada tahun 2003 dan kemudian ditulis dalam Refactoring Databases: Evolutionary Database Design .

Saya dapat melihat apa yang Anda maksudkan ketika Anda mengatakan bahwa itu tampak ceroboh, tetapi ketika dilakukan dengan sengaja dan dengan pemikiran sebelumnya, dan meluangkan waktu untuk memperbaiki struktur yang tidak digunakan dari basis kode dan basis data ketika mereka terbukti tidak lagi digunakan, itu jauh lebih kuat daripada solusi sederhana berdasarkan skrip upgrade dan rollback.

Mike Partridge
sumber
5

"Nol downtime" hanyalah salah satu dari banyak alasan yang mungkin untuk pendekatan semacam ini. Menjaga agar model data tetap kompatibel dengan cara ini membantu Anda menangani banyak masalah berbeda:

  • jika Anda memiliki banyak paket perangkat lunak yang mengakses database Anda, Anda tidak perlu memeriksa semuanya jika perubahan skema memengaruhi mereka (dalam organisasi yang lebih besar dengan beberapa tim menulis semua program mengakses database yang sama, perubahan skema mungkin menjadi sangat sulit)

  • jika Anda harus, Anda dapat memeriksa versi lama dari salah satu program Anda dan kemungkinan besar akan berjalan terhadap basis data yang lebih baru (selama Anda tidak mengharapkan program lama untuk menangani kolom yang lebih baru dengan benar)

  • impor / ekspor data yang diarsipkan ke versi database saat ini jauh lebih mudah

Berikut adalah aturan tambahan untuk daftar Anda

  • setiap kolom baru harus NULLable atau memberikan nilai default yang bermakna

(ini memastikan bahkan program yang lebih lama yang tidak tahu kolom baru tidak akan merusak apa pun ketika mereka membuat catatan baru di database Anda).

Tentu saja, pendekatan ini memiliki satu kelemahan nyata: kualitas model data Anda mungkin menurun seiring waktu. Dan jika Anda memiliki kendali penuh atas semua aplikasi yang mengakses basis data Anda, dan Anda dapat mereformasi semua aplikasi itu dengan mudah ketika Anda, misalnya, akan mengganti nama kolom, maka Anda dapat mempertimbangkan untuk merombak berbagai hal dengan cara yang lebih bersih.

Doc Brown
sumber
4

Ini jenis bervariasi dari satu penempatan ke yang lain.

Tentu, Anda tidak akan pernah bisa menghapus tabel atau kolom. Anda tidak pernah dapat mengubah apa pun yang merusak kompatibilitas antarmuka. Anda selalu dapat menambahkan lapisan abstraksi. Tapi kemudian Anda harus versi abstraksi itu dan versi versi.

Pertanyaan yang perlu Anda tanyakan pada diri sendiri adalah, apakah setiap rilis mengubah skema sedemikian rupa sehingga tidak kompatibel?

Jika sangat sedikit rilis yang mengubah skema dengan cara itu, maka masalah database menjadi bisu. Lakukan saja penyebaran server aplikasi yang bergulir.

Dua hal yang saya lihat paling membantu dengan penyebaran downtime minimal adalah:

  1. Upayakan kompatibilitas mundur - setidaknya dalam satu rilis. Anda tidak akan selalu mencapainya, tetapi saya berani bertaruh Anda dapat mencapainya di 90% atau lebih dari rilis Anda, terutama jika setiap rilis kecil.
  2. Memiliki skrip basis data pra-rilis dan pasca-rilis. Ini memungkinkan Anda untuk menangani perubahan nama atau antarmuka dengan membuat objek baru sebelum kode aplikasi Anda digunakan, lalu menjatuhkan yang lama setelah kode aplikasi digunakan. Jika Anda menambahkan kolom baru yang tidak dapat dibatalkan, Anda bisa menambahkannya sebagai nullable di skrip pra-rilis Anda dengan pemicu yang mengisi nilai default. Kemudian dalam post-release Anda, Anda dapat menjatuhkan pelatuk.

Semoga sisa penyebaran Anda dapat disimpan untuk pemeliharaan windows.

Gagasan lain yang mungkin membantu menangani beberapa penyebaran yang membutuhkan waktu henti:

  • Bisakah Anda membangun kompatibilitas ke belakang ke dalam kode Anda? Misalnya, apakah ada cara kode Anda dapat mendukung beberapa jenis set hasil? Jika Anda perlu mengubah kolom dari int menjadi dobel, kode aplikasi Anda bisa membacanya sebagai string dan menguraikannya. Agak kacau, tetapi jika itu adalah kode sementara untuk mendapatkan diri Anda melalui proses rilis, itu mungkin bukan akhir dari dunia.
  • Prosedur tersimpan dapat membantu melindungi kode aplikasi Anda dari perubahan skema. Ini hanya bisa sejauh ini, tetapi sedikit membantu.
Brandon
sumber
2

Anda berpotensi melakukannya seperti ini untuk sedikit usaha ekstra.

  1. Cadangkan basis data dengan mengambil ekspor
  2. Impor cadangan tetapi ubah nama dengan versi rilis mis. MyDb_2_1
  3. Jalankan rilis basis data di myDB_2_1
  4. "Hentikan" kumpulan aplikasi di Web Server A atau keluarkan dari load balancer
  5. Perbarui Server Web A, jalankan tes implementasi posting dan kembalikan jika perlu
  6. Sesi berdarah Web Server B dan menempatkan Web Server A kembali dalam lingkaran
  7. Tingkatkan server Web B dan kemudian masukkan kembali penyeimbang beban

Tentu saja pembaruan web akan memerlukan entri konfigurasi baru untuk menunjuk ke skema Db baru. Masalahnya adalah jika Anda melakukan rilis sebulan sekali dan ini adalah tim kecil berapa banyak perubahan DB yang benar-benar Anda buat yang tidak kompatibel? Jika Anda dapat mengontrolnya dengan menguji, Anda dapat menggunakan penyebaran otomatis tanpa waktu henti atau mungkin yang terburuk hanya 5 menit waktu henti.

LeoLambrettra
sumber
1
Bagaimana jika (ketika) aplikasi pada Server A menulis ke DB setelah Anda menyimpan cadangan, tetapi sebelum Anda menghentikan Server A? Selalu ada "jendela kerentanan". Tulisan-tulisan ini akan hilang, yang mungkin tidak dapat diterima.
sleske