Apa kelemahan menggunakan koneksi persisten di PDO


181

Dalam PDO, koneksi dapat dibuat gigih menggunakan PDO::ATTR_PERSISTENTatribut. Menurut manual php -

Koneksi persisten tidak ditutup pada akhir skrip, tetapi di-cache dan digunakan kembali ketika skrip lain meminta koneksi menggunakan kredensial yang sama. Tembolok koneksi yang persisten memungkinkan Anda menghindari overhead untuk membuat koneksi baru setiap kali sebuah skrip perlu berbicara dengan database, menghasilkan aplikasi web yang lebih cepat.

Manual ini juga merekomendasikan untuk tidak menggunakan koneksi persisten saat menggunakan driver PDO ODBC, karena dapat menghambat proses Pooling Koneksi ODBC.

Jadi tampaknya tidak ada kelemahan dalam menggunakan koneksi persisten dalam PDO, kecuali dalam kasus terakhir. Namun, saya ingin tahu apakah ada kerugian lain dari menggunakan mekanisme ini, yaitu situasi di mana mekanisme ini mengakibatkan penurunan kinerja atau sesuatu seperti itu.


Wow, Anda membayar 1000 rep bayaran untuk pertanyaan sederhana ini?
Pacerier

Jawaban:


287

Pastikan untuk membaca jawaban ini di bawah ini , yang merinci cara untuk mengurangi masalah yang diuraikan di sini.


Kelemahan yang sama ada menggunakan PDO seperti dengan antarmuka database PHP lain yang melakukan koneksi tetap: jika skrip Anda berhenti tiba-tiba di tengah operasi database, permintaan berikutnya yang mendapatkan koneksi sisa akan mengambil di mana skrip mati ditinggalkan. Sambungan diadakan terbuka pada level manajer proses (Apache untuk mod_php, proses FastCGI saat ini jika Anda menggunakan FastCGI, dll), bukan pada level PHP, dan PHP tidak memberi tahu proses induk untuk membiarkan koneksi mati ketika script berakhir secara tidak normal.

Jika skrip mati mengunci tabel, tabel tersebut akan tetap terkunci hingga koneksi mati atau skrip berikutnya yang membuat koneksi membuka kunci tabel itu sendiri.

Jika skrip mati berada di tengah-tengah transaksi, yang dapat memblokir banyak tabel hingga penghenti waktu deadlock masuk, dan bahkan saat itu, penghitung waktu deadlock dapat membunuh permintaan yang lebih baru alih-alih permintaan yang lebih lama yang menyebabkan masalah.

Jika skrip mati berada di tengah-tengah transaksi, skrip berikutnya yang mendapatkan koneksi itu juga mendapatkan status transaksi. Sangat mungkin (tergantung pada desain aplikasi Anda) bahwa skrip berikutnya mungkin tidak pernah benar-benar mencoba untuk melakukan transaksi yang ada, atau akan melakukan ketika itu tidak seharusnya, atau memutar kembali ketika itu tidak seharusnya.

Ini hanya puncak gunung es. Itu semua dapat dikurangi sampai batas tertentu dengan selalu mencoba untuk membersihkan setelah koneksi yang kotor pada setiap permintaan skrip tunggal, tetapi itu bisa menjadi sakit tergantung pada database. Kecuali Anda telah mengidentifikasi membuat koneksi database sebagai satu hal yang menjadi hambatan dalam skrip Anda (ini berarti Anda telah melakukan pembuatan kode menggunakan xdebug dan / atau xhprof ), Anda tidak boleh menganggap koneksi persisten sebagai solusi untuk apa pun.

Lebih lanjut, kebanyakan basis data modern (termasuk PostgreSQL) memiliki cara sendiri yang disukai untuk melakukan penggabungan koneksi yang tidak memiliki kelemahan langsung seperti koneksi persisten berbasis vanilla PHP.


Untuk memperjelas suatu hal, kami menggunakan koneksi terus-menerus di tempat kerja saya, tetapi tidak dengan pilihan. Kami menjumpai perilaku koneksi yang aneh , di mana koneksi awal dari server aplikasi kami ke server database kami memakan waktu tepat tiga detik, padahal seharusnya sepersekian detik. Kami pikir itu adalah bug kernel. Kami menyerah untuk mencoba memecahkannya karena itu terjadi secara acak dan tidak dapat diproduksi ulang sesuai permintaan, dan IT outsourcing kami tidak memiliki kemampuan konkret untuk melacaknya.

Bagaimanapun, ketika orang-orang di gudang memproses beberapa ratus bagian yang masuk, dan setiap bagian mengambil tiga setengah detik, bukannya setengah detik, kami harus mengambil tindakan sebelum mereka menculik kami semua dan membuat kami membantu mereka. Jadi, kami membalikkan beberapa bit dalam sistem ERP / CRM / CMS kami yang tumbuh sendiri di rumah dan mengalami semua kengerian dari koneksi persisten secara langsung. Kami butuh berminggu - minggu untuk melacak semua masalah kecil yang halus dan perilaku aneh yang terjadi secara acak. Ternyata kesalahan fatal sekali seminggu yang para pengguna kami rajin peras dari aplikasi kami adalah meninggalkan meja terkunci, transaksi terbengkalai, dan keadaan sial lainnya yang tidak menguntungkan.

Kisah sedih ini ada benarnya: Ini menghancurkan hal-hal yang kami tidak pernah harapkan akan hancur, semua atas nama pertunjukan. Pengorbanannya tidak sepadan, dan kami sangat menunggu hari di mana kami dapat kembali ke koneksi normal tanpa kerusuhan dari pengguna kami.


2
Saya harap saya telah membaca jawaban ini sebelum menjalankanSELECT orders.* FROM orders LEFT JOIN items USING(item_id)
Ast Derek

31
Saya tahu situs web besar yang telah menggunakan koneksi terus-menerus selama hampir satu dekade sekarang. Caranya adalah menggunakan layer di atas ekstensi DB, dan membuatnya mengingat hal-hal yang perlu dibersihkan dengan menggunakan register_shutdown_function(). Jika proses mati, koneksi juga mati. Jika tidak, koneksi diatur ulang ke kondisi semula (mis., Transaksi terbuka dibatalkan). Jika ini gagal, koneksi ditutup dan yang baru akan dibuka oleh permintaan berikutnya untuk proses yang sama. Tidak perlu menjelekkan koneksi yang terus-menerus.
Walter Tross

Saya ingin tahu @ Charles ... apakah masalah Anda pernah teratasi?
Tschallacka

@MichaelDibbets Kami mengganti server aplikasi beberapa bulan yang lalu, dan mematikan pconnect untuk melihat apakah bug ketiga masih ada. Bukan itu. Sudah diselesaikan dengan proxy, saya kira. Jawaban di bawah ini berkaitan dengan mysqli_change_usermungkin masih solusi terbaik bagi orang-orang yang harus melakukan koneksi gigih dalam aplikasi yang tidak dirancang untuk menangani masalah negara.
Charles

5
Kami mengalami keterlambatan 5 detik pada koneksi, yang kami berhasil mengisolasi sebagai masalah DNS + IPv6. Server sedang mencari alamat v6, gagal, dan kemudian menggunakan alamat IPv4.
Nigel Atkinson

45

Menanggapi masalah Charles di atas,

Dari: http://www.php.net/manual/en/mysqli.quickstart.connections.php -

Keluhan umum tentang koneksi terus-menerus adalah bahwa negara mereka tidak diatur ulang sebelum digunakan kembali. Misalnya, transaksi terbuka dan belum selesai tidak secara otomatis dibatalkan. Tetapi juga, perubahan otorisasi yang terjadi pada waktu antara menempatkan koneksi ke kolam renang dan menggunakannya kembali tidak tercermin. Ini dapat dilihat sebagai efek samping yang tidak diinginkan. Sebaliknya, nama gigih dapat dipahami sebagai janji bahwa negara dipertahankan.

Ekstensi mysqli mendukung kedua interpretasi koneksi yang persisten: status tetap ada, dan status reset sebelum digunakan kembali. Standarnya diatur ulang. Sebelum koneksi terus-menerus digunakan kembali, ekstensi mysqli secara implisit memanggil mysqli_change_user()untuk mengatur ulang keadaan. Koneksi persisten muncul kepada pengguna seolah-olah itu baru saja dibuka. Tidak ada artefak dari penggunaan sebelumnya yang terlihat.

The mysqli_change_user()Fungsi adalah operasi yang mahal. Untuk kinerja terbaik, pengguna mungkin ingin mengkompilasi ulang ekstensi dengan flag kompilasi MYSQLI_NO_CHANGE_USER_ON_PCONNECTditetapkan.

Terserah kepada pengguna untuk memilih antara perilaku aman dan kinerja terbaik. Keduanya adalah tujuan optimasi yang valid. Untuk kemudahan penggunaan, perilaku aman telah dijadikan default dengan mengorbankan kinerja maksimum.


+1, jika bukan karena kami telah membereskan kekacauan dengan cara lain, saya ingin melihat apakah secara manual memanggil change_user akan memperbaiki masalah keadaan tidak dikenal yang aneh.
Charles

Apa yang setara dengan koneksi persisten PDO Postgres? Saya memiliki masalah serupa seperti @Charles miliki, di mana setelah beberapa saat pengguna akan mendapatkan kesalahan seperti mengambil sql - server menutup koneksi secara tak terduga Ini mungkin berarti server dihentikan secara tidak normal Saat menjalankan kueri SELECT sederhana (bahkan transaksi).
Carmageddon

1
@Carmageddon, itu lebih cocok untuk pertanyaan baru, tetapi tl; dr adalah Postgres tidak melakukan pconnect dan Anda harus menggunakan salah satu kumpulan koneksi eksternal sebagai gantinya.
Charles

@ Charles, apa maksudmu dengan itu? menggunakan koneksi persisten PDO tidak setara dengan menggunakan "kolam koneksi eksternal"? atau apa maksudmu
Carmageddon

@Carmageddon, yang saya maksud adalah bahwa komunitas Postgres memutuskan koneksi pooling sebagai solusi yang lebih baik daripada pconnect. Lihat pgbouncer atau pgpool-II. Saya tidak yakin bahwa PDO melakukan pconnect Postgres, tetapi saya mungkin benar-benar tidak aktif.
Charles

13

Koneksi yang terus-menerus adalah ide yang baik hanya ketika dibutuhkan waktu (relatif) lama untuk terhubung ke database Anda. Sekarang ini hampir tidak pernah terjadi. Kelemahan terbesar dari koneksi yang terus-menerus adalah ia membatasi jumlah pengguna yang dapat Anda jelajahi di situs Anda: jika MySQL dikonfigurasikan untuk hanya mengizinkan 10 koneksi bersamaan sekaligus ketika orang ke-11 mencoba menelusuri situs Anda, itu tidak akan berfungsi untuk mereka .

PDO tidak mengelola kegigihan. Driver MySQL tidak. Ini menggunakan kembali koneksi ketika a) mereka tersedia dan host / user / password / database cocok. Jika ada perubahan maka itu tidak akan menggunakan kembali koneksi. Efek bersih kasus terbaik adalah bahwa koneksi yang Anda miliki akan dimulai dan dihentikan begitu sering karena Anda memiliki pengguna yang berbeda di situs dan membuatnya gigih tidak ada gunanya.

Hal utama yang perlu dipahami tentang koneksi persisten adalah bahwa Anda TIDAK boleh menggunakannya di sebagian besar aplikasi web. Mereka terdengar menarik tetapi mereka berbahaya dan tidak berguna.

Saya yakin ada utas lain tentang hal ini tetapi koneksi persisten berbahaya karena tetap ada di antara permintaan. Jika, misalnya, Anda mengunci tabel selama permintaan dan kemudian gagal membuka kunci maka tabel itu akan tetap terkunci tanpa batas. Koneksi persisten juga cukup berguna untuk 99% aplikasi Anda karena Anda tidak tahu apakah koneksi yang sama akan digunakan di antara permintaan yang berbeda. Setiap utas web akan memiliki set sendiri sambungan yang persisten dan Anda tidak memiliki cara untuk mengontrol utas mana yang akan menangani permintaan mana.

Pustaka mysql prosedural PHP, memiliki fitur di mana panggilan selanjutnya ke mysql_connect akan mengembalikan tautan yang sama, daripada membuka koneksi yang berbeda (Seperti yang mungkin diharapkan). Ini tidak ada hubungannya dengan koneksi persisten dan khusus untuk perpustakaan mysql. PDO tidak menunjukkan perilaku seperti itu


Resource Link: tautan

Secara umum Anda bisa menggunakan ini sebagai "aturan" kasar:

YA , gunakan koneksi persisten, jika:

  • Hanya ada beberapa aplikasi / pengguna yang mengakses database, yaitu Anda tidak akan menghasilkan 200 koneksi terbuka (tetapi mungkin idle), karena ada 200 pengguna berbeda yang dibagikan di host yang sama.
  • Basis data berjalan di server lain yang Anda akses melalui jaringan

  • Suatu (satu) aplikasi mengakses database sangat sering

TIDAK , jangan gunakan koneksi persisten, jika:

  • Aplikasi Anda hanya perlu mengakses database 100 kali dalam satu jam.

  • Anda memiliki banyak, banyak webservers yang mengakses satu server basis data

Menggunakan koneksi persisten cukup cepat, terutama jika Anda mengakses database melalui jaringan. Itu tidak membuat banyak perbedaan jika database berjalan di mesin yang sama, tetapi masih sedikit lebih cepat. Namun - seperti namanya - koneksi tetap ada, yaitu tetap terbuka, meskipun tidak digunakan.

Masalahnya adalah, bahwa dalam "konfigurasi default", MySQL hanya mengizinkan 1000 "saluran terbuka" paralel. Setelah itu, koneksi baru ditolak (Anda dapat mengubah pengaturan ini). Jadi, jika Anda memiliki - katakanlah - 20 Webservers dengan masing-masing 100 Klien, dan masing-masing dari mereka hanya memiliki satu akses halaman per jam, matematika sederhana akan menunjukkan kepada Anda bahwa Anda akan membutuhkan 2000 koneksi paralel ke database. Itu tidak akan berhasil.

Ergo: Hanya gunakan untuk aplikasi dengan banyak permintaan.


4
Setelah baris, jawaban Anda adalah salin tempel dari stackoverflow.com/a/51583/718224
Tony Stark

1
"YA, gunakan koneksi persisten, jika: [...] Hanya ada beberapa aplikasi / pengguna yang mengakses database" bertentangan dengan "Hanya gunakan untuk aplikasi dengan banyak permintaan.". Namun yang terakhir ini benar. Situasi: ribuan permintaan per detik akan menghasilkan ratusan koneksi database aktif. Ketika suatu sistem skala secara linear, itu juga akan secara linear skala jumlah koneksi ke database. Jadi lebih banyak permintaan (lebih banyak pengguna) akan menghasilkan lebih banyak koneksi. Jadi Anda perlu koneksi terbatas (!) Namun banyak aktif ketika Anda memiliki banyak permintaan (pengguna)
Ken Van Hoeylandt

12

Pada tes saya, saya memiliki waktu koneksi lebih dari satu detik ke localhost saya, sehingga dengan asumsi saya harus menggunakan koneksi persisten. Tes lebih lanjut menunjukkan itu adalah masalah dengan 'localhost':

Hasil pengujian dalam detik (diukur dengan php microtime):

  • host web: connectDB: 0,0038912296295166
  • localhost: connectDB: 1.0214691162109 (lebih dari satu detik: jangan gunakan localhost!)
  • 127.0.0.1: connectDB: 0,00097203254699707

Menariknya: Kode berikut ini secepat menggunakan 127.0.0.1:

$host = gethostbyname('localhost');
// echo "<p>$host</p>";
$db = new PDO("mysql:host=$host;dbname=" . DATABASE . ';charset=utf8', $username, $password,
    array(PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

Sepertinya PDO mengalami kesulitan menerjemahkan nama domain! Terima kasih, saya bertanya-tanya mengapa setiap koneksi sangat lama di mesin quad core saya!
Mustafa

@Gunnar Bernstein +1 temukan bagus. "localhost" tentu membutuhkan waktu lebih lama dan ini agak meningkatkan kecepatan aplikasi web saya (ini membuat banyak koneksi).
imperium2335

1
Ini bagus. Ada yang salah dengan resolusi pada mesin pengembangan saya ... menggunakan IP mengambil skrip saya dari 6.1s ke 1.1s
Pete

localhostmenggunakan koneksi soket, koneksi soket terkenal buruk pada sejumlah besar koneksi
mente

@mente Ada referensi, sumber daya yang dapat membuktikan fakta itu? Saya cenderung berpikir bahwa UDS lebih disukai daripada TCP. Terima kasih.
Nuxwin

6

Koneksi yang gigih harus memberikan peningkatan kinerja yang cukup besar. Saya tidak setuju dengan asumsi bahwa Anda harus "Menghindari" kegigihan ..

Sepertinya keluhan di atas didorong oleh seseorang yang menggunakan tabel MyIASM dan meretas versi transaksi mereka sendiri dengan mengambil kunci meja .. Yah tentu saja Anda akan menemui jalan buntu! Gunakan beginTransaction () PDO dan pindahkan tabel Anda ke InnoDB ..


2
Setahun belakangan, saya sadar, tetapi sebagai catatan: kisah saya berasal dari database yang seluruhnya terdiri dari tabel-tabel InnoDB, dengan satu-satunya pengecualian dari beberapa klon yang didenormalkan yang tertahan di rawa MyISAM untuk dukungan pengindeksan fulltext.
Charles

Pfft, Sphinx sudah tua dan rusak, ElasticSearch adalah hal baru. Suatu hari nanti, kita akan benar-benar menggunakannya untuk aplikasi lama kita, bukan hanya yang baru ...
Charles

Pencarian teks lengkap di PostgreSQL adalah pemenang sesungguhnya. Luar biasa. Tidak memerlukan alat / server lain berjalan untuk melakukan tugasnya. Tidak perlu khawatir tentang menjaga data tetap sinkron. Kontrol yang sangat terperinci. Kamus berganda atau tulis sendiri. Dan karena PostgreSQL secara otomatis menggunakan kueri multi-indeks, Anda cukup memasukkannya dengan kueri lain yang sedang Anda jalankan.
brightball

2
MySQL 5.6 menawarkan dukungan teks lengkap untuk tabel InnoDB.
timetofly

2

Sepertinya saya memiliki koneksi persisten akan memakan lebih banyak sumber daya sistem. Mungkin jumlah yang sepele, tapi masih ...


Seringkali perdagangan banyak waktu manusia untuk mikrodetik waktu komputer
Andy Chase

1

Penjelasan untuk menggunakan koneksi persisten jelas mengurangi jumlah koneksi yang agak mahal, meskipun faktanya mereka jauh lebih cepat dengan MySQL dibandingkan dengan database lain.

Masalah pertama dengan koneksi yang terus-menerus ...

Jika Anda membuat 1000's koneksi per detik Anda biasanya tidak memastikan bahwa itu tetap terbuka untuk waktu yang sangat lama, tetapi Sistem Operasi tidak. Berdasarkan protokol TCP / IP, Port tidak dapat didaur ulang secara instan dan juga harus berinvestasi sebentar dalam tahap "FIN" sebelum menunggu untuk didaur ulang.

Masalah ke-2 ... menggunakan banyak koneksi server MySQL.

Banyak orang tidak menyadari bahwa Anda dapat meningkatkan variabel * max_connections * dan mendapatkan lebih dari 100 koneksi bersamaan dengan MySQL, yang lain dikalahkan oleh masalah Linux yang lebih lama tentang ketidakmampuan untuk menyampaikan lebih dari 1024 koneksi dengan MySQL.

Mengizinkan bicara sekarang tentang mengapa koneksi persisten dinonaktifkan di ekstensi mysqli. Terlepas dari kenyataan bahwa Anda dapat menyalahgunakan koneksi gigih dan mendapatkan kinerja yang buruk yang bukan alasan utama. Alasan sebenarnya adalah - Anda bisa mendapatkan lebih banyak masalah dengannya.

Koneksi persisten dimasukkan ke dalam PHP di seluruh kesempatan MySQL 3.22 / 3.23 ketika MySQL tidak begitu sulit yang berarti Anda dapat mendaur ulang koneksi dengan mudah tanpa masalah. Namun, dalam versi yang lebih baru, jumlah masalah muncul - Jika Anda mendaur ulang koneksi yang memiliki transaksi tidak berkomitmen, Anda akan mendapat masalah. Jika Anda mendaur ulang koneksi dengan konfigurasi set karakter khusus, Anda berada dalam bahaya lagi, serta kemungkinan berubah per variabel sesi.

Satu masalah dengan menggunakan koneksi persisten adalah itu tidak benar-benar skala itu dengan baik. Bagi mereka yang memiliki 5.000 orang yang terhubung, Anda akan membutuhkan 5.000 koneksi persisten. Untuk menjauh dari persyaratan untuk kegigihan, Anda mungkin memiliki kemampuan untuk melayani 10.000 orang dengan jumlah koneksi yang sama karena mereka berada dalam posisi untuk berbagi koneksi individu ketika mereka tidak bersama mereka.


0

Saya hanya ingin tahu apakah solusi parsial akan memiliki kumpulan koneksi sekali pakai. Anda dapat menghabiskan waktu membuat kumpulan koneksi saat sistem sedang digunakan, hingga batas tertentu, membagikannya dan membunuhnya ketika mereka telah selesai atau kehabisan waktu. Di latar belakang Anda membuat koneksi baru saat sedang diambil. Dalam kasus terburuk, ini seharusnya hanya lambat seperti membuat koneksi tanpa kumpulan, dengan asumsi bahwa membangun tautan adalah faktor pembatas?

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.