Pekerjaan cron pengumpulan sampah Ubuntu untuk sesi PHP membutuhkan waktu 25 menit untuk dijalankan, mengapa?

13

Ubuntu memiliki pengaturan tugas cron yang mencari dan menghapus sesi PHP lama:

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] \
   && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 \
   -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir \
   fuser -s {} 2> /dev/null \; -delete

Masalah saya adalah bahwa proses ini memakan waktu sangat lama untuk dijalankan, dengan banyak IO disk. Inilah grafik penggunaan CPU saya:

Grafik penggunaan CPU

Pembersihan berjalan diwakili oleh paku kecil. Pada awal periode, pekerjaan pembersihan PHP dijadwalkan pada waktu default 09 dan 39 menit. Pada pukul 15:00 saya menghapus waktu 39 menit dari cron, jadi pekerjaan pembersihan dua kali ukuran berjalan setengah sering (Anda dapat melihat puncak mendapatkan dua kali lebih lebar dan setengah sering).

Berikut adalah grafik yang sesuai untuk waktu IO:

Waktu IO

Dan operasi disk:

Operasi disk

Pada puncak di mana terdapat sekitar 14.000 sesi aktif, pembersihan dapat terlihat berjalan selama 25 menit penuh, tampaknya menggunakan 100% dari satu inti CPU dan apa yang tampaknya 100% dari disk IO untuk seluruh periode. Mengapa sumber daya begitu intensif? Sebuah lsdirektori sesi /var/lib/php5hanya butuh sepersekian detik. Jadi mengapa perlu 25 menit penuh untuk memotong sesi lama? Apakah ada yang bisa saya lakukan untuk mempercepat ini?

Sistem file untuk perangkat ini saat ini adalah ext4, berjalan pada Ubuntu Precise 12.04 64-bit.

EDIT: Saya menduga bahwa beban ini disebabkan oleh proses "fuser" yang tidak biasa (karena saya berharap yang sederhana rmmenjadi pemandangan yang lebih cepat daripada kinerja yang saya lihat). Saya akan menghapus penggunaan fuser dan melihat apa yang terjadi.

lalu sayang
sumber
Berapa banyak traffic yang didapat situs web Anda untuk menghasilkan banyak sesi?
Michael Hampton

Jawaban:

9

Menghapus fuserharus membantu. Pekerjaan ini menjalankan fuserperintah (periksa apakah file saat ini dibuka) untuk setiap file sesi yang ditemukan , yang dapat dengan mudah memakan waktu beberapa menit pada sistem yang sibuk dengan 14k sesi. Ini adalah bug Debian (Ubuntu didasarkan pada Debian).

Alih-alih memcached Anda juga dapat mencoba menggunakan tmpfs (sistem file dalam memori) untuk file sesi. Seperti memcached ini akan membatalkan sesi pada reboot (ini dapat dikerjakan dengan membuat cadangan direktori ini di suatu tempat dalam skrip shutdown dan mengembalikan dalam skrip startup), tetapi akan jauh lebih mudah untuk setup. Tapi itu tidak akan membantu fusermasalah.

Tometzky
sumber
Kedengarannya seperti bug di fuser adalah bahwa versi sebelumnya bercabang tapi kemudian tidak pernah menuai setelah selesai, meninggalkan ribuan fuserproses dalam keadaan mengkonsumsi memori zombie, yang menyebabkan server crash. Saya pikir itu sudah diperbaiki dalam versi psmisc yang saya gunakan.
thenickdude
Itu bug lain. Anda memiliki masalah sederhana untuk memulai ribuan fuserproses, yang semuanya harus mencari keseluruhan /proc/file terbuka.
Tometzky
9

Selamat telah memiliki situs web populer dan mengelola agar tetap berjalan di mesin virtual selama ini.

Jika Anda benar-benar menarik dalam dua juta tampilan halaman per hari, maka Anda akan menumpuk BANYAK sesi PHP di filesystem, dan mereka akan memakan waktu lama untuk menghapus tidak peduli apakah Anda menggunakan fuseratau rmatau penyedot debu.

Pada titik ini saya sarankan Anda mencari cara alternatif untuk menyimpan sesi Anda:

  • Salah satu opsi adalah menyimpan sesi dimemcached . Ini sangat cepat, tetapi jika server crash atau restart, semua sesi Anda hilang dan semua orang keluar.
  • Anda juga dapat menyimpan sesi dalam database. Ini akan sedikit lebih lambat daripada memcached, tetapi database akan gigih, dan Anda bisa menghapus sesi lama dengan query SQL sederhana. Untuk mengimplementasikan ini, Anda harus menulis pengendali sesi khusus .
Michael Hampton
sumber
Memcached tentu saja merupakan opsi, meskipun itu harus berupa kumpulan terpisah dari instance memcached utama kami, jika tidak, sesi akan diusir secara acak dari tekanan cache kami. Saya tidak yakin bahwa menghapus 14.000 file akan memakan waktu 25 menit. Kedengarannya terlalu lambat bagi saya. Saya akan menunggu beberapa jam dan melihat seperti apa kinerja yang sederhana rmitu.
thenickdude
Tanpa mengetahui lebih banyak tentang arsitektur keseluruhan Anda, saya ragu untuk merekomendasikan satu di atas yang lain.
Michael Hampton
Anda dapat menggabungkan server Memcached untuk redundansi dengan mengatur memcache.session_redundancy = 2. Lihat serverfault.com/questions/164350/… . Redis adalah pilihan yang baik jika Anda khawatir tentang kegigihan dan jauh lebih cepat daripada toko database SQL.
jfountain
4

Jadi, opsi penyimpanan Memcached dan sesi basis data yang disarankan oleh pengguna di sini adalah pilihan yang baik untuk meningkatkan kinerja, masing-masing dengan kelebihan dan kekurangannya sendiri.

Tetapi dengan pengujian kinerja, saya menemukan bahwa biaya kinerja yang sangat besar dari pemeliharaan sesi ini hampir seluruhnya tergantung pada panggilan ke fuserdalam pekerjaan cron. Berikut grafik kinerja setelah kembali ke tugas cron Natty / Oneiric yang menggunakan rmalih-alih fuseruntuk memangkas sesi lama, peralihan terjadi pada 2:30.

penggunaan CPU

Waktu IO yang telah berlalu

Operasi disk

Anda dapat melihat bahwa penurunan kinerja berkala yang disebabkan oleh pembersihan sesi PHP Ubuntu hampir seluruhnya dihapus. Lonjakan yang diperlihatkan dalam grafik Operasi Disk sekarang jauh lebih kecil dalam besarnya, dan sekitar setipis yang dapat diukur oleh grafik ini, menunjukkan gangguan kecil, pendek di mana kinerja server sebelumnya terdegradasi secara signifikan selama 25 menit. Penggunaan CPU ekstra sepenuhnya dihilangkan, sekarang ini adalah pekerjaan yang terikat IO.

(pekerjaan IO yang tidak terkait berjalan pada 05:00 dan pekerjaan CPU berjalan pada 7.40 yang keduanya menyebabkan lonjakan mereka sendiri pada grafik ini)

Pekerjaan cron yang dimodifikasi yang saya jalankan sekarang adalah:

09 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && \
   [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 \
   -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -print0 \
   | xargs -n 200 -r -0 rm
lalu sayang
sumber
-print0 | xargs ...tidak perlu - Anda bisa pergi begitu saja -delete. Tapi itu akan bekerja dua arah dengan kecepatan yang sebanding.
Tometzky
1

Saya menemukan posting ini ketika melakukan penelitian pada sesi. Sementara jawaban yang diterima sangat bagus (dan panggilan fuser telah dihapus dari skrip gc untuk beberapa waktu) saya pikir perlu dicatat beberapa pertimbangan lain jika orang lain menemukan masalah yang sama.

Dalam skenario yang dijelaskan, OP menggunakan ext4. Direktori di ext4 menyimpan data file dalam format database htree - yang berarti ada dampak yang dapat diabaikan dalam menyimpan banyak file dalam direktori tunggal dibandingkan dengan mendistribusikannya di direktori mutliple. Ini tidak berlaku untuk semua sistem file. Penangan default dalam PHP memungkinkan Anda untuk menggunakan beberapa sub-direktori untuk file sesi (tetapi perhatikan bahwa Anda harus memeriksa bahwa proses pengendalian berulang ke direktori tersebut - pekerjaan cron di atas tidak).

Banyak biaya operasi (setelah menghapus panggilan ke fuser) timbul dari melihat file yang belum basi. Menggunakan (misalnya) satu tingkat subdirektori, dan 16 pekerjaan cron yang mencari di setiap sub direktori (0 /, 1 /, ... d /, e /, f /) akan memuluskan beban gundukan yang timbul.

Menggunakan pengatur sesi khusus dengan substrat yang lebih cepat akan membantu - tetapi ada banyak yang bisa dipilih (memcache, redis, socket mysql handler ...) mengesampingkan kisaran kualitas yang dipublikasikan di internet, yang Anda pilih tergantung pada tepat persyaratan sehubungan dengan aplikasi Anda, infrastruktur dan keterampilan, jangan lupa bahwa sering ada perbedaan dalam penanganan semantik (terutama mengunci) dibandingkan dengan penangan default.

symcbean
sumber
0

Dengan lalu lintas semacam itu, Anda seharusnya tidak membuat sesi tentang dis. Anda harus menggunakan sesuatu seperti memcache. Yang harus Anda lakukan adalah mengatur php dan tidak akan ada perubahan kode yang diperlukan. Lihat misalnya

http://www.dotdeb.org/2008/08/25/storing-your-php-sessions-using-memcached/

Alasannya memakan waktu begitu lama adalah karena besarnya jumlah file yang harus disortir untuk melihat mana yang dapat dihapus. Memcache dapat kedaluwarsa secara otomatis karena lamanya sesi Anda ditetapkan dalam kode Anda.

Mike
sumber