Mehmet

WFN Üye
Konular
1,851
Mesajlar
1,852
Çözüm
0
Ticaret Puanı
0
Üyelik
1 Ay 6 Gün
Konum
YurtDışı
Web Sitesi
Var
Alanı
Google Adsense
1/1
Konu sahibi
PHP’de varsayılan dosya tabanlı oturum işleyicisi kullanılıyorsa aynı oturum kimliğine sahip istekler, session_start() sonrasında oturum verisi üzerinde kilit oluşturur. İlk istek kilidi bırakana kadar aynı kullanıcıya ait ikinci istek genellikle bekler. Bu nedenle uzun süren bir işlem oturum açıkken çalışıyorsa, kullanıcının diğer AJAX veya sayfa istekleri de yavaşlayabilir. Oturum verisine artık ihtiyacınız kalmadığında session_write_close() çağırmak kilidi erken bırakır.

Oturum kilidi nasıl çalışır?​


İstek session_start() çağırdığında PHP oturum kaydını açar ve kullanılan handler’ın davranışına göre kilitler. Varsayılan dosya handler’ında bu kilit, oturum kapatılana veya istek sona erene kadar tutulur. Aynı PHPSESSID çerezini taşıyan başka bir istek aynı kaydı açmaya çalışırsa bekler.

Bu kilit kullanıcılar arasında genel bir PHP kilidi değildir. Farklı oturum kimlikleri kullanan iki kullanıcının istekleri normalde birbirini bu nedenle bekletmez. Sorun, aynı oturumu paylaşan paralel isteklerde görülür. Ayrıca özel bir session handler kullanılıyorsa kilitleme davranışı handler’ın uygulamasına bağlıdır; dosya handler’ındaki davranış otomatik olarak diğer depolara genellenmemelidir.

Kilidin amacı, iki isteğin aynı oturum verisini aynı anda okuyup yazarken birbirinin değişikliklerini ezmesini önlemektir. Ancak kilit açıkken yapılan ağ çağrısı, dosya işlemi, yoğun hesaplama veya uzun sleep() çağrısı gereksiz bekleme oluşturur.

Somut örnek​


Aşağıdaki dosya, aynı oturumla yapılan ilk isteği birkaç saniye bekletir. session_write_close() çağrısı bu beklemeden sonra çalıştığı için ikinci istek, ilk istek kilidi bırakmadan yanıt üretemez.

PHP:
<?php
header('Content-Type: text/plain; charset=utf-8');
session_start();
$label = $_GET['label'] ?? 'normal';
if (!is_string($label)) $label = 'normal';
$label = substr($label, 0, 40);
$_SESSION['last_label'] = $label;

$early = ($_GET['early'] ?? '') === '1';
if ($early) session_write_close();
if (($_GET['hold'] ?? '') === '1') sleep(5);
if (session_status() === PHP_SESSION_ACTIVE) session_write_close();
echo 'Tamamlandı: ' . $label;

Ayrı ve boş bir yerel deneme dizininde dosyayı lock.php olarak kaydedin. Aşağıdaki komut ve curl akışı POSIX kabuğu bulunan Linux/macOS içindir. Varsayılan php -S tek işçiyle çalışır; istekleri zaten sıraya aldığı için session kilidi deneyini tek başına kanıtlayamaz. PHP’nin desteklenen geliştirme ortamında en az iki işçiyle, yalnız loopback üzerinde başlatın:

Kod:
PHP_CLI_SERVER_WORKERS=2 php -S 127.0.0.1:8000

Bu çok işçili CLI seçeneği Windows’ta desteklenmez. Windows’ta eşzamanlı istek işleyebilen ayrı bir test web sunucusu veya Linux geliştirme ortamı kullanın; tek işçili sunucudaki beklemeyi oturum kilidi sanmayın. Geliştirme sunucusunu genel ağa açmayın. Aynı oturum çerezini kullanarak önce oturumu oluşturun, ardından iki isteği başlatın:

Kod:
curl -s -c cookie.txt "http://127.0.0.1:8000/lock.php?label=initial" > /dev/null
curl -s -b cookie.txt "http://127.0.0.1:8000/lock.php?label=uzun&hold=1" > ilk.txt &
sleep 1
curl -s -b cookie.txt "http://127.0.0.1:8000/lock.php?label=ikinci"
wait
cat ilk.txt

Beklenen davranış, ikinci curl komutunun hemen tamamlanmaması ve ilk istek yaklaşık beş saniyelik beklemesini bitirip session_write_close() çağırana kadar beklemesidir. Sonra uzun isteğin URL’sine early=1 ekleyip aynı denemeyi tekrarlayın. Oturum bu kez sleep öncesinde kapandığı için ikinci istek ilk isteğin beş saniyelik beklemesini beklememelidir. Aynı denemede farklı oturum çerezi kullanmak da karşılaştırma sağlar. Ağ, işçi sayısı ve zamanlama değişebileceğinden yalnız toplam süreyi kesin kanıt saymayın.

DenemeBeklenen davranışYorum
Aynı oturum, geç kapatmaİkinci istek session_start içinde bekleyebilirOturum kilidi adayı
Aynı oturum, early=1Uzun işlem sürerken ikinci istek ilerleyebilirKilidi erken bırakmanın etkisi
Tek sunucu işçisiİki denemede de istekler sıraya girebilirSunucu eşzamanlılığı ayrı darboğaz

Uygulanabilir kararlar​


  1. İsteğin başında yalnızca gerçekten gereken oturum verilerini okuyun veya güncelleyin.
  2. Oturum verisiyle işiniz biter bitmez session_write_close() çağırın. Bundan sonra $_SESSION üzerinde yaptığınız değişiklikler kaydedilmeyeceği için gerekli tüm yazmaları bu çağrıdan önce tamamlayın.
  3. Ağ isteği, uzun sorgu veya yoğun hesaplama yapacaksanız bunları oturum kilidi kapandıktan sonra yürütün. İşlem sırasında oturum bilgisine yeniden ihtiyaç duyarsanız akışı iki bölüme ayırın.
  4. İşlemin ilerlemesini oturum değişkenine sürekli yazmak yerine ayrı bir iş durumu veya görev depolama yaklaşımı kullanmayı değerlendirin. Böylece her durum güncellemesinde kullanıcı oturumunu uzun süre kilitlemezsiniz.
  5. Aynı oturumla gelen AJAX çağrılarını tarayıcı geliştirici araçlarında inceleyin. Bir isteğin süresi uzunken diğerlerinin beklemesi, oturum kilidi çekişmesine işaret edebilir; ancak veritabanı, ağ ve PHP çalışanı sınırlarını da ayrıca kontrol edin.

İstek yalnızca oturum verisini okuyacaksa oturumu okuma sonrasında kapatmaya yönelik PHP seçenekleri kullanılabilir; fakat bu yaklaşımda oturum üzerinde yapılacak değişikliklerin kaydedilmeyeceği varsayılmalıdır. Yazma gereken yerlerde açıkça session_write_close() kullanmak davranışı daha görünür kılar.

Sık yapılan hatalar​


  • Sadece veri okuduğu için kilit alınmayacağını düşünmek: Varsayılan dosya handler’ında salt okuma amacı da diğer isteğin beklemesine yol açabilir.
  • İsteğin sonunda kilidin kendiliğinden bırakılmasını yeterli görmek: Uzun işlemden sonra bırakmak, işlem boyunca tüm paralel istekleri bekletir.
  • Oturumu erken kapattıktan sonra yapılan $_SESSION değişikliğinin kaydedileceğini sanmak: Yazma işlemleri kapatma çağrısından önce yapılmalıdır.
  • Her yavaş isteği oturum kilidine bağlamak: Aynı veritabanı sorgusu, dış servis, PHP çalışanı havuzu veya istemci bağlantısı da benzer belirti oluşturabilir.
  • Özel session handler’ın dosya handler’ı gibi davrandığını varsaymak: Kilitleme, eşzamanlılık ve yazma garantileri kullanılan handler’ın belgelerine ve uygulamasına göre doğrulanmalıdır.

Kaynaklar​



Sık sorulan sorular​


Oturumu erken kapattıktan sonra session verisine yeniden ihtiyaç duyarsam ne yapmalıyım?​

İşlemi iki aşamaya ayırıp gerektiğinde oturumu yeniden açabilirsiniz; ancak yeniden açmak tekrar kilit alma ve bekleme oluşturabilir. Yeniden açmadan önce ilk bölümdeki oturum yazmalarının tamamlandığından emin olun.

İki farklı kullanıcı aynı anda istek gönderirse birbirlerini bekletir mi?​

Genellikle hayır. Her kullanıcı farklı oturum kimliği taşıdığı sürece oturum kilidi ayrı kayıtlarda tutulur. Yine de ortak veritabanı, dosya veya uygulama kaynaklarının kendi kilitleri olabilir.
 

Sende şimdi bize katılmak ister misin?

Kayıt ol

Bize katılım kolay ve ücretsizdir!

Konuyu görüntüleyenler

Bu konuyu şu anda görüntüleyen üye bulunmuyor.