Cara menentukan sweet spot antara ukuran kumpulan dan koneksi basis data di PostgreSQL

14

Kami mengalami masalah dalam menangani lalu lintas selama jam sibuk ke server database kami. Kami sedang mencari cara untuk meningkatkan perangkat keras (lihat pertanyaan ini tentang sisi itu ) tetapi kami juga ingin bekerja pada konfigurasi penyatuan dan penyetelan server.

Aplikasi yang sedang kami kerjakan adalah game multiplayer berbasis giliran untuk smartphone, di mana backend terdiri dari Rails dengan unicorn dan PostgreSQL 9.1 sebagai databasenya. Saat ini kami memiliki 600.000 pengguna terdaftar dan karena status permainan disimpan dalam database, beberapa ribu penulisan dilakukan setiap beberapa detik. Kami telah menganalisis file log dari PostgreSQL menggunakan PgBadger dan selama jam-jam kritis kami mendapatkan banyak

FATAL: remaining connection slots are reserved for non-replication superuser connections

Solusi naif untuk mengatasi masalah ini adalah dengan meningkatkan max_connections (yang saat ini 100) di postgresql.conf . Saya telah membaca http://wiki.postgresql.org/wiki/Number_Of_Database_Connections yang menunjukkan bahwa ini mungkin bukan hal yang tepat untuk dilakukan. Dalam artikel tersebut disebut mencari sweet spot antara max_connections dan ukuran kumpulan .

Apa yang bisa dilakukan untuk menemukan sweet spot ini? Apakah ada alat yang bagus untuk mengukur kinerja I / O untuk nilai berbeda dari max_connections dan ukuran kumpulan ?

Pengaturan kami saat ini adalah 4 server permainan, masing-masing memiliki 16 pekerja unicorn dan ukuran kumpulan 5.

Berikut adalah pengaturan postgres non-standar yang kami gunakan:

version                      | PostgreSQL 9.1.5 on x86_64-unknown-linux-gnu,compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit
checkpoint_completion_target | 0.9
checkpoint_segments          | 60
checkpoint_timeout           | 6min
client_encoding              | UTF8
effective_cache_size         | 2GB
lc_collate                   | en_US.UTF-8
lc_ctype                     | en_US.UTF-8
log_destination              | csvlog
log_directory                | pg_log
log_filename                 | postgresql-%Y-%m-%d_%H%M%S.log
log_line_prefix              | %t
log_min_duration_statement   | 200ms
log_rotation_age             | 1d
log_rotation_size            | 10MB
logging_collector            | on
max_connections              | 100
max_stack_depth              | 2MB
server_encoding              | UTF8
shared_buffers               | 1GB
ssl                          | on
TimeZone                     | localtime
wal_buffers                  | 16MB
work_mem                     | 8MB
lorgartzor
sumber
Apakah Anda orang yang menanyakan hal ini di milis dalam beberapa minggu terakhir? Jika demikian, saya akan menambahkan tautan balik ke diskusi itu. Juga: Apa perangkat keras dan konfigurasi server DB Anda ? wiki.postgresql.org/wiki/Slow_Query_Questions . Sertakan pengaturan non-standar: wiki.postgresql.org/wiki/Server_Configuration . Sudahkah Anda membaca wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server ? Apakah Anda bisa melakukan transaksi yang lebih besar jika memungkinkan? Apakah Anda menggunakan lapisan caching dan jika demikian, apa? Apakah Anda menggunakan synchronous_commit = offatau commit_delay?
Craig Ringer
Jadi Anda memiliki total 20 koneksi ke server PostgreSQL? 5 per server game? Dengan 5 konek dari setiap server game yang dibagikan di 16 pekerja unicorn?
Craig Ringer
Oh, apakah Anda masuk kueri lambat? Jika demikian, apa hot spot Anda? Sederhana INSERTs? Seperti apa skema Anda - apakah dipartisi? Apa explain analyzebeberapa pertanyaan sampel? Seberapa sering pos pemeriksaan Anda dan berapa lama waktu yang dibutuhkan? (lihat opsi pencatatan pos pemeriksaan). Dan serius, apa versi PostgreSQL Anda ? (Pembaruan: Tampaknya Anda mencantumkan perangkat keras di sini: dba.stackexchange.com/questions/28061/… )
Craig Ringer
Bagaimanapun, untuk penyetelan ukuran kumpulan secara khusus, satu-satunya jawaban nyata adalah mengatur pengukuran beban dan throughput server DB yang kuat, kemudian mulai menyesuaikan ke atas dan ke bawah hingga Anda menemukan sweet spot.
Craig Ringer
@CraigRinger Tidak, saya bukan orang itu. Tapi terima kasih untuk backlinknya! Saya telah membaca Tuning Your PostgreSQL server dan mengikuti beberapa tips yang disebutkan. Saya sekarang sudah memasukkan pengaturan tidak-default. Kami sekarang sedang mencari untuk melakukan transaksi dan pengujian yang lebih besarsynchronous_commit = off
lorgartzor

Jawaban:

14

Jawaban singkat di sini adalah "percobaan dan kesalahan yang dipandu oleh metrik pemantauan dan kinerja".

Ada beberapa aturan umum yang dapat membantu Anda menemukan area samar yang harus Anda mulai, tetapi mereka sangat umum. Pedoman umum "jumlah CPU plus jumlah disk yang independen" sering dikutip, tetapi ini hanyalah titik awal yang sangat kasar.

Yang benar-benar perlu Anda lakukan adalah mendapatkan metrik kinerja yang kuat untuk aplikasi Anda. Mulai merekam statistik.

Tidak banyak cara untuk mengintegrasikan alat untuk ini. Ada beberapa hal seperti check_postgresskrip nagios , pencatatan konter kinerja sistem Cacti, pengumpul statistik PostgreSQL, dll ... tetapi tidak banyak yang menyatukan semuanya. Sayangnya, Anda harus melakukannya sendiri. Untuk sisi PostgreSQL, lihat pemantauan di manual PostgreSQL. Ada beberapa opsi pihak ketiga, seperti Postgres Enterprise Monitor EnterpriseDB .

Untuk metrik tingkat aplikasi yang disebutkan di sini, Anda ingin merekamnya dalam struktur data bersama atau dalam DB eksternal yang tidak tahan lama seperti Redis dan menggabungkannya baik saat Anda merekamnya atau sebelum Anda menulisnya ke PostgreSQL DB Anda. Mencoba masuk langsung ke Pg akan mendistorsi pengukuran Anda dengan overhead yang dibuat dengan mencatat pengukuran dan memperburuk masalah.

Opsi paling sederhana mungkin adalah singleton di setiap server aplikasi yang Anda gunakan untuk merekam statistik aplikasi. Anda mungkin ingin terus memperbarui min, maks, n, total, dan rata-rata; dengan begitu Anda tidak perlu menyimpan setiap titik stat, hanya agregat. Singleton ini dapat menulis statistik agregatnya ke Pg setiap x menit, tingkat yang cukup rendah sehingga dampak kinerja akan minimal.

Dimulai dari:

  • Apa latensi permintaan? Dengan kata lain, berapa lama waktu yang dibutuhkan aplikasi dari menerima permintaan dari klien hingga menanggapi klien. Catat ini secara agregat selama periode waktu tertentu, bukan sebagai catatan individual. Kelompokkan menurut jenis permintaan; katakan, demi halaman.

  • Apa penundaan akses basis data untuk setiap permintaan atau jenis permintaan yang dijalankan aplikasi? Berapa lama dari meminta informasi / menyimpan informasi sampai DB selesai dan dapat melanjutkan ke tugas berikutnya? Sekali lagi, gabungkan statistik ini dalam aplikasi dan hanya tuliskan informasi agregat ke DB.

  • Seperti apa throughput Anda? Dalam setiap x menit tertentu, berapa banyak kueri dari setiap kelas utama yang dijalankan aplikasi Anda dilayani oleh DB?

  • Untuk rentang waktu yang sama yaitu x menit, ada berapa banyak permintaan klien?

  • Menyampling setiap beberapa detik dan menjumlahkan melalui windows x menit yang sama dalam DB, berapa banyak koneksi DB yang ada? Berapa banyak dari mereka yang menganggur? Berapa banyak yang aktif? Di sisipan? Pembaruan? memilih? menghapus? Berapa banyak transaksi yang terjadi selama periode itu? Lihat dokumentasi pengumpul statistik

  • Sekali lagi mengambil sampel dan menggabungkan dalam interval waktu yang sama, seperti apa metrik kinerja sistem host? Berapa banyak membaca dan berapa banyak menulis disk IOs / detik? Megabita per detik disk membaca dan menulis? Pemanfaatan CPU? Rata-rata beban? Penggunaan RAM?

Anda sekarang dapat mulai belajar tentang kinerja aplikasi Anda dengan mengkorelasikan data, membuat grafik, dll. Anda akan mulai melihat pola, mulai menemukan kemacetan.

Anda mungkin mengetahui bahwa sistem Anda macet INSERTdan UPDATEs pada tingkat transaksi yang tinggi, meskipun I / O disk yang cukup rendah dalam megabyte per detik. Ini akan menjadi petunjuk bahwa Anda perlu meningkatkan kinerja flush disk Anda dengan pengontrol caching RAID write-back yang didukung baterai atau beberapa SSD yang dilindungi oleh daya berkualitas tinggi. Anda juga dapat menggunakan synchronous_commit = offjika OK untuk kehilangan beberapa transaksi pada server crash, dan / atau a commit_delay, untuk mengambil beberapa beban sinkronisasi.

Ketika Anda membuat grafik transaksi Anda per detik terhadap jumlah koneksi bersamaan dan mengoreksi untuk berbagai tingkat permintaan aplikasi melihat, Anda akan bisa mendapatkan ide yang lebih baik di mana sweet spot throughput Anda berada.

Jika Anda tidak memiliki penyimpanan pembilasan cepat (BBU RAID atau SSD tahan lama), Anda tidak akan menginginkan lebih dari sejumlah kecil koneksi yang aktif menulis, mungkin paling banyak 2x jumlah disk yang Anda miliki, mungkin lebih sedikit tergantung pada pengaturan RAID , kinerja disk, dll. Dalam hal ini bahkan tidak layak coba-coba; cukup tingkatkan subsistem penyimpanan Anda menjadi satu dengan flush disk cepat .

Lihat pg_test_fsyncalat yang akan membantu Anda menentukan apakah ini masalah bagi Anda. Sebagian besar paket PostgreSQL menginstal alat ini sebagai bagian dari contrib, jadi Anda tidak perlu mengkompilasinya. Jika Anda mendapatkan kurang dari beberapa ribu ops / detik, pg_test_fsyncAnda harus segera meningkatkan sistem penyimpanan Anda. Laptop saya yang dilengkapi SSD mendapat 5000-7000. Workstation saya bekerja dengan array RAID 10-disk 4 disk dengan disk 7200rpm SATA dan write-through (non-write-caching) mendapat sekitar 80 ops / detik f_datasync, turun hingga 20 ops / detik untuk fsync(); itu ratusan kali lebih lambat . Bandingkan: laptop dengan ssd vs workstation dengan RAID 10 ( write-through -caching). SSD laptop ini murah dan saya tidak percaya untuk menghapus cache tulisnya pada kehilangan daya; Saya menyimpan cadangan yang baik dan tidak akan menggunakannya untuk data yang saya pedulikan. SSD berkualitas baik berkinerja baik jika tidak lebih baik dan tahan lama.

Dalam hal aplikasi Anda, saya sangat menyarankan Anda untuk melihat ke dalam:

  • Subsistem penyimpanan yang baik dengan flush yang cepat. Saya tidak bisa cukup menekankan hal ini. SSD dengan daya-gagal-aman berkualitas baik dan / atau pengontrol RAID dengan cache write-back yang dilindungi daya.
  • Menggunakan UNLOGGEDtabel untuk data yang Anda bisa kehilangan. Gabungkan secara berkala ke dalam tabel yang dicatat. Misalnya, pertahankan game-in-progress dalam tabel yang tidak dicatat, dan tulis skornya ke tabel awet biasa.
  • Menggunakan commit_delay(kurang berguna dengan penyimpanan pembilasan cepat - petunjuk)
  • Mematikan synchronous_committransaksi yang Anda sanggup kehilangan (kurang berguna dengan penyimpanan yang cepat - petunjuk)
  • Tabel partisi, terutama tabel di mana data "menua" dan dibersihkan. Alih-alih menghapus dari tabel dipartisi, jatuhkan partisi.
  • Indeks sebagian
  • Mengurangi jumlah indeks yang Anda buat. Setiap indeks memiliki biaya penulisan.
  • Batching bekerja menjadi transaksi yang lebih besar
  • Menggunakan replika siaga panas hanya baca untuk mengambil beban baca dari DB utama
  • Menggunakan lapisan caching seperti memcached atau redis untuk data yang kurang sering berubah atau bisa basi. Anda dapat menggunakan LISTENdan NOTIFYuntuk melakukan pembatalan cache menggunakan pemicu pada tabel PostgreSQL.

Jika ragu: http://www.postgresql.org/support/professional_support/

Craig Ringer
sumber