Apakah Anda ingin meningkatkan kinerja aplikasi Anda dengan cara yang efisien dan akurat? Jika ya, maka Anda perlu tahu tentang stacktrace sampling. Stacktrace sampling adalah metode untuk mengumpulkan data kinerja aplikasi dengan cara mengambil sampel dari call stack aplikasi secara berkala. Dengan stacktrace sampling, Anda dapat mengurangi overhead CPU dan memori yang dibutuhkan untuk mengumpulkan data kinerja, menyediakan gambaran yang akurat dan representatif tentang perilaku aplikasi dalam kondisi normal maupun stres, dan memungkinkan Anda untuk mengidentifikasi dan mengoptimalkan bagian kode yang paling sering atau paling lama dieksekusi. Dalam artikel ini, kami akan menjelaskan apa itu stacktrace sampling, mengapa itu penting, bagaimana cara melakukan stacktrace sampling, dan alat-alat apa saja yang bisa Anda gunakan untuk stacktrace sampling. Mari kita mulai!
Pada artikel kali ini saya akan membahas apa yang terjadi pada permasalahan dan cara mengatasi kegagalan PHP Sesion Hang disini saya akan mencoba memeriksa kenapa itu bisa terjadi dan bagaimana menyelesaikan masalah jika terjadi seperti ini.Â
kita akan mulai dengan mencoba membuat masalah sesason hang.
Bisa di coba Saat aplikasi tidak digunakanÂ
Tulis skirp Php berikut.
Â
<?php
function useful_function() {
sleep(1);
}
useful_function();
?>
Kemudian gunakan ab perintah untuk mengirim 10 permintaan silmutan ke server.
ab -c 10 -n 10 http://localhost:8999/first.php
Hasilnya akan terlihat seperti berikut
...
Concurrency Level: 10
Time taken for tests: 1.003 seconds
Complete requests: 10
...
Karena saya telah mengirim 10 permintaan simultan per detik, waktu eksekusi dari perintah di atas tentu saja 1 detik. Sekarang mari tambahkan fungsi untuk menunjukkan jumlah kunjungan halaman menggunakan PHP Session.
<?php //session_test1.php
function useful_function(){
sleep(1);
}
session_start();
if(isset($_SESSION['visit_count'])===FALSE){
$_SESSION['visit_count'] = 1;
}
else{
$_SESSION['visit_count'] += 1;
}
$visit_count = 'visit_count = '.$_SESSION['visit_count'];
echo $visit_count;
aries_add_message_profile($visit_count); //add 'visit_count' to jennifer profiles
useful_function();
?>
Mengirim satu permintaan melalui url, hasilnya akan terlihat seperti berikut:
curl -v http://localhost:8999/session_test1.php
* Trying 127.0.0.1...
...
< HTTP/1.1 200 OK
< Date: Wed, 05 Dec 2018 05:34:53 GMT
< Server: Apache/2.2.22 (Ubuntu)
< Set-Cookie: PHPSESSID=lmrfduhgfm6oik62fi2c9q4ek7; expires=Wed, 05-Dec-2018 13:34:53 GMT; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
...
visit_count = 1%
Didalam respon kita dapat melihat bahwa jumlah kunjungan adalah 1(visit_count=1) Karena PHPSESSID telah ditambahkan ke cookie respons HTTP, pengendali sesi default PHP menggunakan cookie, dan nilai cookie PHPSESSID digunakan sebagai pengenal Sesi.
Mari kita kirim permintaan lain dengan curl, kali ini kita akan menambahkan PHPSESSID di cookie.
curl --cookie "PHPSESSID=lmrfduhgfm6oik62fi2c9q4ek7" http://localhost:8999/session_test1.php
...
visit_count = 2%
Kali ini kita dapat melihat bahwa visit_count=2 . Jadi fitur kunjungan halaman yang baru ditambahkn berfungsi dengan baik. kita lihat apa yang terjadi di server web. Jika mencantumkan isi direktori /tmp, Anda akan melihat bahwa file lmrfd… . coba periksa konten file, Anda akan melihat bagaimana sesi disimpan:
visit_count|i:2;
Kasus Kegagalan Sesi PHP 1 (Mengatasi Kegagalan)
saya akan mengirim lagi mengirim 10  permintaan simultan lagi menggunakan ab perintah, kali ini kita akan menentukan PHPSESSID sebagai cookie.
Hasil dari perintah tersebut akan terlihat seperti berikut.
ab -c 10 -n 10 -C PHPSESSID=lmrfduhgfm6oik62fi2c9q4ek7 http://localhost:8999/session_test1.php
...
Concurrency Level: 10
Time taken for tests: 10.006 seconds
Complete requests: 10
...
Anda dapat segera melihat bahwa ketika tidak menggunakan fungsi Sesi, waktu eksekusi perintah ab adalah 1 detik, namun, setelah menggunakan sesi, 10 permintaan yang sama membutuhkan waktu 10 detik.
Apm Jennifer X-View menunjukkan pola berikut.
X-View memplot waktu permintaan pada sumbu X dan waktu respons pada sumbu Y. Kita dapat melihat bahwa semua 10 permintaan datang pada saat yang sama, tetapi waktu pemrosesannya berbeda.
Jika kita memeriksa detail transaksi, kita dapat melihat bahwa waktu mulai sama untuk 10 permintaan, 16:12:52. Namun, waktu responsnya adalah 1 detik, 2 detik, 3 detik … 10 detik untuk masing-masing dari 10 permintaan. Selain itu, fungsi session_start dari permintaan yang diproses terakhir membutuhkan waktu 9 detik untuk dieksekusi. Ini karena file session handler mengunci file session.
Kasus Kegagalan Sesi PHP 2
Kali ini saya akan membuat masalahnya sedikit lebih serius. Misalkan kita memperbarui fungsi_berguna kita menambahkan koneksi database untuk fungsi itu.
<?php //session_test2.php
function useful_function($db){
sleep(1);
}
$db = mysql_connect('...');
session_start();
if(isset($_SESSION['visit_count'])===FALSE){
$_SESSION['visit_count'] = 1;
}
else{
$_SESSION['visit_count'] += 1;
}
$visit_count = 'visit_count = '.$_SESSION['visit_count'];
echo $visit_count;
aries_add_message_profile($visit_count);
useful_function($db);
Â
mysql_connect dipanggil sebelum session_start (). Dalam hal ini, jika permintaan satu Sesi dipanggil N pada saat yang sama, nomor koneksi DB juga bertambah N, untuk menghindari ini, anda tidak boleh memperoleh sumber daya sebelum session_start.
Pada saat anda mengubah kode untuk mendapatkan sumber daya DB setelah memanggil session_start (), bagan Koneksi DB Aktif terlihat seperti ini: Perhatikan bahwa jumlah koneksi DB disimpan di 1.
Â
Pemecahan masalah dengan session_write_close
PHP .net memperingatkan masalah di atas dan menyarankan solusi berikut. Gunakan fungsi session_start dengan  opsi read_and_close (Opsi ini hanya tersedia untuk PHP 7.0 dan yang lebih baru.)
Setelah memodifikasi data sesi, gunakan session_commit atau session_write_close untuk melepaskan kunci sesi sesegera mungkin. Saya akan mencoba menyelesaikan masalah dengan mengambil metode kedua.
<?php
function useful_function($db){
sleep(1);
}
session_start();
if(isset($_SESSION['visit_count'])===FALSE){
$_SESSION['visit_count'] = 1;
}
else{
$_SESSION['visit_count'] += 1;
}
session_write_close(); //release session lock
$visit_count = 'visit_count = '.$_SESSION['visit_count'];
echo $visit_count;
$db=mysql_connect('...');
aries_add_message_profile($visit_count);
//Change _SESSION['visit_count']
$_SESSION['visit_count'] = 'write data after session_write_close()';
aries_add_message_profile($_SESSION['visit_count']);
useful_function($db);
?>
 Setelah memodifikasi kode, seperti yang ditunjukkan di atas, saya akan mengirimkan 10 permintaan sekaligus.
ab -c 10 -n 10 -C PHPSESSID=lmrfduhgfm6oik62fi2c9q4ek7 http://localhost:8999/session_test3.php
...
Concurrency Level: 10
Time taken for tests: 1.007 seconds
...
Masalah teratasi. Semua permintaan diproses secara bersamaan. Namun, harus berhati-hati. Kode di atas telah mengubah $_SESSION ['visit_count'] setelah panggilan session_write_close().
Bagaimana cara kerjanya? Mari kita lihat profil APM Jennifer.
Nilai $_SESSION['visit_count'] adalah 'tulis data setelah session_write_close()' . Anda dapat melihat bahwa itu telah dimodifikasi. Sekarang mari kita periksa isi file sess yang disimpan di direktori /tmp.
cat /tmp/sess_lmrfduhgfm6oik62fi2c9q4ek7
visit_count|i:40;
Anda dapat melihat bahwa nilai visit_count adalah 40  'tulis data setelah session_write_close ()'. Ini berarti bahwa nilai variabel $_SESSION diubah karena panggilan valid selama durasi permintaan, tetapi tidak dicatat dalam data Sesi. Ini adalah salah satu kelemahan dari session_write_close solusi.
Jika Anda mengubah sesi. Jika anda membuat kesalahan, nilai yang anda lihat dan nilai yang disimpan dalam Sesi mungkin akan berbeda.Â
Pemecahan masalah dengan Redis Session Handler
Kita akan menggunakan pengendali sesi Redis yang tidak mengunci sesi untuk menyelesaikan masalah. (Anda juga dapat menggunakan Kunci sebagai opsi.) Panggil session_test2.php (skrip yang tidak menggunakan session_write_close) yang ditentukan di atas 10 kali secara bersamaan.
ab -c 10 -n 10 -C PHPSESSID=lmrfduhgfm6oik62fi2c9q4ek7 http://localhost:8999/session_test2.php
...
Concurrency Level: 10
Time taken for tests: 1.006 seconds
Masalah telah hilang. semua permintaan diproses secara bersamaan. Juga, periksa Data Sesi.
# redis-cli
127.0.0.1:6379> KEYS *
1) "PHPREDIS_SESSION:lmrfduhgfm6oik62fi2c9q4ek7"
127.0.0.1:6379> GET "PHPREDIS_SESSION:lmrfduhgfm6oik62fi2c9q4ek7"
"visit_count|i:6;"
127.0.0.1:6379>
visit_count dicatat sebagai 6 bukan10. Jika Anda memutuskan untuk menggunakan Redis Session Handler tanpa mengunci, Anda harus menyadari hal ini dan jangan berharap bahwa nilai yang disimpan dalam Session akan tetap utuh. Data yang membutuhkan integritas dan tidak boleh disimpan dalam Sesi.
Di atas adalah profil yang dapat diperiksa ketika database ditetapkan sebagai sesi di CodeIgniter. coba periksa SQL Query, pemanggilan metode session_start () membutuhkan waktu lebih dari 2 detik, yang menunjukkan bahwa kunci menyebabkan masalah. Kode CodeIgniter Controller yang digunakan untuk mereproduksi di atas ditunjukkan di bawah ini.
<?php
class Welcome extends CI_Controller {
function __construct(){
parent::__construct();
$this->load->library('session');
}
public function index()
{
sleep(1);
$this->load->view('welcome_message');
}
}
Kodenya session_start dan session_write_close tersembunyi.
Â
Kesimpulan (Dalam Mengatasi Kegagalan)
Sejauh ini, saya mencoba membuat dan memecahkan masalah yang disebabkan oleh Session Lock. Melalui proses ini, Anda dapat memperoleh rekomendasi berikut:
- Anda perlu mengetahui kebijakan penguncian yang digunakan oleh pengendali sesi anda.
- Pengendali sesi default PHP adalah file, yang mengunci Data Sesi.
- Penanganan Sesi Redis tidak menglock. Opsi memungkinkan Anda mengubah lock.
- Handler Sesi Memcached terlock. Opsi memungkinkan Anda mengubah kebijakan lock.
- Jika pengendali sesi menggunakan lock, Anda harus membuka locknya setelah memodifikasi Sesi. (session_write_close).
- Anda harus menyadari bahwa masalah konkurensi dapat terjadi jika pengendali sesi tidak menglock, dan Anda tidak boleh menyimpan data yang memerlukan integritas dalam Sesi.
Pada artikel sebelumnya saya membahas, tentang Analisis Kinerja Berbasis Sampling Stacktrace karena transaksi menjalankan tugas yang relatif sederhana, daftar stacktrace dapat membantu anda memahami semua yang terjadi dalam sebuah method. Namun jika kita beramsusi bahwa transaksi yang berjalan untuk beberapa waktu yang lama dan memiliki sekitar 100 stacktrace yang dikumpulkan, maka akan sangat memakan waktu untuk memeriksa setiap stacktrace.
Apm Jennifer menyediakan dua pungsi tampilan yang berbeda dan dapat menampilkan analisis yang mudah dalam situasi seperti itu.
Summary Viewing
Summary Viewing dan menganalisis, meringkas panggilan dari setiap method yang menampilkan hasil dari chart setiap transaksi, ditampilkan sebagai chart mewakili method dalam stacktrace dan memiliki informasi sebagai berikut.
 Flame chart memiliki karakteristik sebagai berikut
- Setiap warna menunjukkan itu adalah method dari paket yang sama.
- Ukuran luas persegi panjang adalah jumlah koleksi.
- method di bagian bawah grafik adalah titik awal stacktrace.
- method di bagian atas grafik adalah method yang sedang berjalan.
Berdasarkan fakta diatas, untuk menemukan method yang paling sering dipanggil selama periode tersebut, anda harus menemukan area dengan ukuran terbesar. kemungkinan method yang anda temukan merupakan penyebab utama selama ini (penggunaan CPU, penundaan waktu respons).
Sekarang, mari kita menganalisis keadaan dengan menggunakan fungsi stacktrace yang ditingkatkan oleh APM JENNIFER. dan mari kita periksa informasi detail transaksi yang lambat di jendela pop-up X-View.
Node yang tidak diprofilkan menempati sebagian besar waktu proses. Kita dapat melihat bahwa node yang tidak diprofile memiliki sub node yang disebut STACK-TRACE. Ini adalah tampilan dari kumpulan stacktrace berdasarkan setiap profil dan informasi waktu. gambar di atas menunjukkan bahwa 95 tumpukan jejak dikumpulkan di area tidak diprofilkan. sekarang, klik node STACK-TRACE untuk pindah ke tab stacktrace di mana grup tumpukan yang cocok dipilih secara otomatis.