TEKNİK YAZI / Backend Sistemleri

Kill ve PID: Linux Process Yönetiminin Temelleri

Linux'ta PID bulma, SIGTERM ve SIGKILL sinyallerini doğru sırayla kullanma ve takılan süreçleri güvenle sonlandırma rehberi.

Linux’ta kill komutu bir süreci doğrudan “öldürmekten” çok, belirtilen PID’ye bir sinyal gönderir. Güvenli akış; hedef PID’yi kesin olarak bulmak, komutunu doğrulamak, önce SIGTERM göndermek, sürece kapanması için süre tanımak ve yalnızca kapanamıyorsa SIGKILL kullanmaktır.

PID nedir?

PID (Process ID), çalışan bir sürecin sayısal kimliğidir. Aynı uygulamanın birden fazla örneği farklı PID’lerle çalışabilir; ayrıca bir süreç kapandıktan sonra PID daha sonra başka bir sürece verilebilir. Bu nedenle eski bir nottaki PID’yi kullanmak yerine işlemden hemen önce hedefi yeniden doğrulamak önemlidir.

Süreçleri genel olarak incelemek için:

ps aux
top

Belirli bir süreç adını tam eşleşmeyle bulmak için pgrep -x, PID ile birlikte komut satırını görmek için de -a kullanılabilir:

pgrep -a -x firefox

Uzun süreç adları veya yorumlayıcı üzerinden çalışan betikler için ad alanı yeterli olmayabilir. Böyle bir durumda pgrep -a -f tam komut satırında arama yapar; ancak daha geniş eşleşebileceği için sonucu mutlaka inceleyin.

Güvenli sonlandırma adımları

Aşağıdaki örneklerde 1234, doğruladığınız gerçek PID ile değiştirilmelidir.

1. Süreci bulun

pgrep -a -x my-app

Tek bir sonuç beklerken birden fazla PID görürseniz hepsine sinyal göndermeyin. Önce hangi örneğin hedef olduğunu belirleyin.

2. PID’nin çalıştırdığı komutu doğrulayın

ps -p 1234 -o pid,ppid,user,stat,etime,cmd

Çıktıda PID, üst süreç, kullanıcı, durum, çalışma süresi ve komut satırı birlikte görünür. Yanlış kullanıcıya veya benzer adlı başka bir servise ait süreci durdurma riskini bu adım azaltır.

STAT alanındaki ilk harf sürecin durumunu bildirir ve sinyalin nasıl karşılanacağını doğrudan etkiler:

HarfAnlamı
RÇalışıyor veya çalışmaya hazır
SUyuyor; bekliyor fakat sinyal geldiğinde uyanır
DKesintiye uğratılamaz uyku; sinyal geldiğinde uyanmaz
TDurdurulmuş (SIGSTOP veya Ctrl+Z)
ZZombie

İlk harften sonra gelen ekler de bilgi taşır: s sürecin oturum lideri olduğunu, + ön plandaki process group’ta bulunduğunu, l çok iş parçacıklı olduğunu gösterir. Denetleyen terminali olmayan bir daemon tipik olarak Ss görünür ve + taşımaz.

3. Önce SIGTERM gönderin

kill sinyal belirtilmediğinde varsayılan olarak SIGTERM gönderir:

kill -s TERM 1234

Sinyal adını -s ile vermek önemlidir. Kabuklarda kill hem yerleşik bir komut hem de ayrı bir program (/bin/kill, util-linux) olarak bulunur ve yerleşik olan her zaman önceliklidir. Util-linux’a ait --signal uzun seçeneğini bash ve zsh’in yerleşik kill komutu tanımaz; kill --signal TERM 1234 etkileşimli bir kabukta invalid signal specification hatası verir. -s TERM biçimi hem yerleşik komutlarda hem /bin/kill içinde çalışır ve POSIX tarafından tanımlıdır.

SIGTERM, uygulamaya kapanış işleyicisini çalıştırma fırsatı verir. Uygulama yeni istek almayı durdurabilir, açık dosyaları kapatabilir ve tamponlanmış veriyi yazabilir. Bu davranış uygulamanın sinyali nasıl ele aldığına bağlıdır; sinyalin “nazik” olması sürecin mutlaka kapanacağı anlamına gelmez.

4. Bekleyin ve durumu yeniden kontrol edin

Uygulamaya uygun bir süre tanıdıktan sonra aynı PID’yi kontrol edin:

ps -p 1234 -o pid,stat,etime,cmd

Komut başlık dışında sonuç döndürmüyorsa süreç artık yoktur. Uzun kapanış yapan veritabanı veya worker süreçlerinde bekleme süresini uygulamanın dokümantasyonuna göre seçin.

5. Yalnızca gerekirse SIGKILL kullanın

Süreç SIGTERM sonrasında kapanmıyor ve başka bir güvenli kurtarma yolu bulunmuyorsa:

kill -s KILL 1234

SIGKILL yakalanamaz, engellenemez veya yok sayılamaz. Uygulama temizleme kodunu çalıştıramadan çekirdek tarafından sonlandırılır; tamponlanmış durum, yarım yazılmış dosya veya tamamlanmamış işlem kaybı oluşabilir. Bu yüzden ilk adım değil, son çaredir.

Bir portu dinleyen süreci bulma

Örneğin TCP 8080 portunu dinleyen süreci ve PID bilgisini görmek için:

sudo ss -lptn 'sport = :8080'

Alternatif olarak lsof kuruluysa:

sudo lsof -nP -iTCP:8080 -sTCP:LISTEN

Bulduğunuz PID’yi yine ps ile doğruladıktan sonra aynı SIGTERM → bekle → gerekirse SIGKILL sırasını izleyin.

Sık kullanılan sinyaller

Numaralar bazı mimarilerde farklılaşabildiği için betiklerde kill -s TERM veya kill -TERM gibi sinyal adları daha okunaklıdır.

Sinyal gönderildiği anda uygulanmaz

Sinyal, sürece anında ulaşan bir mesaj değildir. kill çağrıldığında çekirdek hedef sürecin kaydına bekleyen sinyal bayrağını koyar; bayrak yalnızca süreç çekirdek alanından kullanıcı alanına dönerken denetlenir ve etkisi o anda uygulanır.

Bu ayrım, SIGKILL gönderildiği hâlde ölmeyen süreçleri açıklar. STAT alanında D görünen bir süreç kesintiye uğratılamaz uykudadır: bir çekirdek çağrısının ortasında donanım yanıtı bekler. Disk arızası, kopmuş bir ağ dosya sistemi bağlantısı veya çıkarılmış bir aygıt tipik sebeplerdir. Süreç kullanıcı alanına dönmediği için bekleyen sinyal hiç denetlenmez; SIGKILL kaybolmaz, sırasını bekler ve G/Ç tamamlandığı anda uygulanır.

Bu durumda süreci sonlandırmak mümkün değildir; çözüm altındaki G/Ç sorununu gidermektir. Linux’ta D durumundaki süreçlerin yük ortalamasına dahil edilmesi de belirgin bir ipucudur: CPU kullanan hiçbir şey yokken yük ortalamasının yükselmesi genellikle takılı G/Ç anlamına gelir.

Özetle SIGKILL’in etkisiz kaldığı iki durum vardır: süreç henüz sonlandırılamayacak durumdadır (D) veya zaten sonlanmıştır (Z).

Eksi işaretli PID: process group’a sinyal göndermek

kill komutunda hedef değeri yalnızca bir PID olarak okunmaz; işareti ve büyüklüğü hedefin kapsamını belirler:

DeğerSinyalin gittiği yer
1234Yalnızca 1234 numaralı süreç
0Çağıran sürecin kendi process group’u
-1234PGID’si 1234 olan process group’un tamamı
-1Çağıranın yetkili olduğu tüm süreçler (PID 1 hariç)

Process group, kabuğun birlikte başlattığı süreçleri tek hedef altında toplar. cat dosya | grep hata | wc -l boru hattındaki üç süreç aynı gruptadır; Ctrl+C bastığınızda üçünün birden sonlanmasının sebebi, terminalin SIGINT sinyalini tek bir sürece değil ön plandaki process group’a göndermesidir. STAT alanındaki + eki de sürecin ön plan grubunda olduğunu belirtir.

Bir sürecin grubunu görmek için:

ps -o pid,pgid,comm -p 1234

Grup hedeflemek, alt süreç doğuran bir betiği durdururken işe yarar: yalnızca ana süreci sonlandırmak alt süreçleri öksüz bırakır ve çalışmaya devam ederler. Aynı özellik dikkatsiz kullanıldığında risklidir. kill -9 -1 root olarak çalıştırıldığında sistemdeki hemen her süreci sonlandırır; ayrıca kill -9 1234 yerine yanlışlıkla kill -9 -1234 yazmak tek süreç yerine bir grubu hedefler ve bu hata sessizce gerçekleşir.

Systemd’nin varsayılan KillMode=control-group davranışı bu fikrin daha güvenli hâlidir: sinyal process group’a değil servisin cgroup’una uygulanır. Bir süreç setpgid() ile process group’undan ayrılabilir, fakat cgroup’undan ayrılamaz.

İsimle sonlandırma neden dikkat ister?

pkill bir desene uyan birden fazla sürece sinyal gönderebilir. İsimle işlem yapmak zorundaysanız önce aynı eşleşmeyi yalnızca listelemek için kullanın:

pgrep -a -x my-app

Sonuç hedeflediğiniz süreçlerle birebir uyuşuyorsa yine de PID’leri tek tek incelemek en güvenli yöntemdir. Komut ikamesiyle kill -9 $(pidof ...) çalıştırmak, beklenmedik sayıda PID’yi doğrulama fırsatı olmadan hedefleyebilir; bu nedenle operasyonel örneklerde kullanılmamalıdır.

Yetki hataları ve servis yöneticileri

Bir kullanıcı normalde yalnızca yetkili olduğu süreçlere sinyal gönderebilir. sudo kullanmadan önce hedef PID’nin gerçekten doğru olduğunu iki kez kontrol edin. Süreç systemd tarafından yönetiliyorsa PID’ye doğrudan sinyal göndermek yerine çoğunlukla servis yöneticisini kullanmak daha doğrudur:

sudo systemctl stop my-app.service

Bu yaklaşım servisin tanımlı kapanış süresini, yeniden başlatma politikasını ve bağlı süreç grubunu dikkate alır.

Servis yöneticisini tercih etmenin bir sebebi daha vardır. PID ile çalışan her akışta doğrulama ile sinyal gönderme arasında bir boşluk kalır; bu araya sıkışan durum değişikliğine kontrol-kullanım yarışı (TOCTOU, time of check to time of use) denir. ps çıktısı doğrulandıktan sonra hedef süreç kendiliğinden sonlanabilir, PID serbest kalabilir ve aynı numara başka bir sürece atanabilir; ardından gönderilen sinyal yanlış hedefe ulaşır. Boşluk bir betikte milisaniyelerle ölçülür, çıktıyı okuyan bir kişi söz konusuysa dakikalara çıkar. Sistemdeki PID sınırı cat /proc/sys/kernel/pid_max ile görülebilir; sınırın düşük olduğu ve süreç döngüsünün yoğun olduğu makinelerde numaraların yeniden kullanılması hızlanır.

Systemd bu yarışa açık değildir, çünkü servisi PID ile değil cgroup üyeliğiyle izler. Kendi araçlarınızda aynı güvenceye ihtiyaç duyarsanız Linux 5.3 ile gelen pidfd arayüzü süreci numarayla değil dosya tanıtıcısıyla adresler:

import os, signal

fd = os.pidfd_open(1234)
# ... hedefi doğrulayın ...
signal.pidfd_send_signal(fd, signal.SIGTERM)

Tanıtıcı belirli bir süreç örneğine bağlıdır. Süreç sonlanmışsa çağrı ESRCH ile başarısız olur ve yeniden kullanılmış bir PID’ye sinyal gönderilmesi mümkün olmaz. Bir süreci kendiniz fork() ile başlattıysanız bu yarış zaten oluşmaz: PID, wait ailesiyle toplanana kadar yeniden kullanılamaz.

Zombie süreçler

ps çıktısındaki STAT alanında Z görünen zombie süreç zaten çalışmasını tamamlamıştır; ona ek sinyal göndermek çıkış kaydını ortadan kaldırmaz. Üst sürecin çocuğun durumunu wait ailesiyle toplaması gerekir. Sorun tekrarlanıyorsa üst uygulamanın çocuk süreç yönetimi düzeltilmelidir; üst süreci rastgele sonlandırmak genel bir çözüm değildir.

Birincil kaynaklar