bdgn

07 Haziran 2010

Turkseniz ve rooted android'iniz varsa

bekir@hede:/tmp$ adb remount
remount succeeded
bekir@hede:/tmp$ adb shell
# vi /etc/hosts
# cat /etc/hosts
127.0.0.1 localhost
66.102.13.101 android.clients.google.com
66.102.13.104 www.google.com
66.102.13.103 google.com
# exit
bekir@hede:/tmp$


Suradan aldim.

22 Mayıs 2010

Laptopta sanal sunucu, KVM içerisinde linux-vserver

Çalıştığım şiskette sistem yöneticiliği yapıyorum, ofis içerisinde küçük bir sunucu odamız var ve burada çeşitli teslerimiz için laboratuvar ortamımız mevcut. Ama kişisel olarak yapmak istediğim testleri kendi laptopumda yapmak evde de çalışabilmemi sağladığım için işime geliyor. Gün boyunca bir çok uygulama görüp iş yerindeki laboratuvar ortamına ya da internete bağlı kalmadan test etmek istiyorum ama bütün bu uygulamaları kurarak bilgisayarımı çöplük haline getirmek de istemiyordum.

Ben de bilgisayarımda yapacağım testler için KVM ile oluşturduğum sanal sunucuları kullanıyordum, ancak:
  • bir kaç sanal cunusu çalıştırmam gerekince toplamda sahip olduğum 1GB ram'in hatırı sayılır kısmını sanal sunuculara ayırıyordum
  • sunucular'a kaynaklar istesemde istemesem de atanmış oluyordu,
  • toplam 10GB kadar olan boş alanıma çok sunucu kuramıyordum, her sunucu için ne kadar diske ihtiyacım olacağını da bilemiyordum, sonradan diski büyütebilsem de bu çok kolay değildi
Bir süre sonra KVM gibi tam sanllaştırma yapan araçlardan vazgeçip işletim sistemi seviyesinde sanallaştırma yapmak için bilgisayarıma linux-vserver çekirdeği (linux-image-vserver-686) kurdum. Böyle yaptığımda da şu sorunlar ile karşılaştım:
  • çekirdeğim değiştiği için nvidia ve madwifi gibi sürücular için tekrar modül derlemem gerekti, hoş hani zaten bunu modüle-assistant benim adıma yapıyor ama gene de rahatsız edici bir durum
  • gittiğim her yerde ağ yapılandırmam değişiyordu ve linux-vserver sunucularına dinamik ip vermek çok kolay olmuyordu
Sonunda yeni gelen bir güncelleme sırasında kendimi vserver çekirdeğini kaldırırken bulunca farklı bir yöntem kullanmak gerektiğini düşündüm ve şöyle bir çözüm buldum:
  • Bir adet KVM kurup içerisine linux-vserver çekirdeği kurdum
  • KVM'in ağ yapılandırmasını ayarlayarak KVM ve içerisindeki sanal sunucuları ayrı bir ağa koydum, böylece sabit ip verebildim ve nat ile nete çıkardım: http://www.linuxquestions.org/questions/linux-networking-3/kvm-qemu-and-nat-on-the-host-machine-mini-tutorial-697980/
  • Tüm sanal sunucuların içinde bulunduğu disk alanına toplamda 10GB ayırdım, tümü bunu paylaşıyorlar, her yeni sunucunun disk maliyeti yalnızca 200MB ölüyor (benim imajımın sıfır boyutu bu kadar)
  • Tüm sanal sunuculara ayrı ayrı ram ayırmaktansa toplamda 300MB ram ayırdım ve tümü bunu paylaşıyorlar, 10 kadar sanal cunucu ile daha pek yavaşlama olmadı.
Nasıl yaptığıma gelince:
bekir@laptop:~$ sudo aptitude install kvm
KVM'in ağ yapılandırmasını düzenleyelim:
bekir@laptop:~$ for i in /etc/kvm/*; do echo ===== $i =====; cat $i; done
===== /etc/kvm/kvm-if.conf =====
#see /home/bekir/bin/testing
BRIDGE=kvmnat
NETWORK=192.168.172.0
HOST=192.168.172.1
MASK=255.255.255.0
===== /etc/kvm/kvm-ifdown =====
#!/bin/sh
#see /home/bekir/bin/testing

. /etc/kvm/kvm-if.conf

echo "$0:"

echo "Tearing down network bridge for $1"
ip link set $1 down
brctl delif "$BRIDGE" $1

ifconfig kvmnat 0.0.0.0
ip link set "$BRIDGE" down
brctl delbr "$BRIDGE"

exit 0
===== /etc/kvm/kvm-ifup =====
#!/bin/sh
#see /home/bekir/bin/testing

. /etc/kvm/kvm-if.conf

echo "$0:"
echo "Setting up the network bridge for $1"
brctl addbr "$BRIDGE"
brctl addif "$BRIDGE" "$1"
ifconfig "$BRIDGE" "$HOST" netmask "$MASK"
ip link set "$1" up
ip link set "$BRIDGE" up

if iptables -t nat -L POSTROUTING -n | grep ^MASQUERADE | awk '{print $4}' | cut -d/ -f1 | grep "$NETWORK" >/dev/null
then
echo "IP masquerading already set up"
else
echo "Setting up IP masquerading"
iptables -t nat -A POSTROUTING -s "$NETWORK"/"$MASK" -d ! "$NETWORK"/"$MASK" -j MASQUERADE
fi

echo "Setting up IP forwarding"
sysctl net.ipv4.ip_forward=1

exit 0

===== /etc/kvm/kvm-ifup-bak =====
#! /bin/sh
# Script to bring a network (tap) device for qemu-kvm up
# The idea is to add the tap device to the same bridge
# as we have default routing to.

switch=$(ip route ls | \
awk '/^default / {
for( i = 0; i < NF ; i++ ) { if ($i == "dev") { print $(i+1); exit; } }
}'
)
/sbin/ifconfig $1 0.0.0.0 up

# only add the interface to default-route bridge if we
# have such interface (with default route) and if that
# interface is actually a bridge.
if [ -n "$switch" -a -d /sys/class/net/$switch/bridge/. ]; then
/usr/sbin/brctl addif $switch $1 || :
fi
bekir@laptop:~$
KVM içerisine kurulum için debian kurulum CD'sini indirelim:
Ben debian'ın sitesinden indirdim, şuradan bulabilirsiniz: http://www.debian.org/CD/
bekir@laptop:/media/free$ wget http://cdimage.debian.org/debian-cd/5.0.4/i386/iso-cd/debian-504-i386-CD-1.iso

Sanal sunucuları koyacağımız disk alanını ayıralım (ben 10GB ayırdım)
bekir@laptop:~/media/free$ dd if=/dev/zero of=kvm_vserver_kernel bs=100M count=100
KVM icerisine ilk kurulumu yapalim linux-vserver cekirdegi koyalim:
bekir@laptop:~/media/free$ sudo kvm -hda kvm_vserver_kernel -cdrom debian-504-i386-CD-1.iso -m 300 -net nic,vlan=0 -net tap,vlan=0
Sistem CD'den açılıyor ve şu ayarları yapıyorum:
  • Tüm dışkı kendisi bölümlendirsin (tek parça)
  • Ağ ayarları için elle yapılandırma seçip şunları kullandım:
  • * address 192.168.172.2/255.255.255.0
  • * gateway 192.168.172.1
  • * dns-nameservers 192.168.172.1
  • Sisteme neler kurayım diye sorduğunda hiç bir şey seçmedim
Kurulum bittikten sonra KVM'i kurduğumuz sistemden açalım:
bekir@laptop:~$ sudo kvm -hda /media/free/kvm_vserver_kernel -m 300 -net nic,vlan=0 -net tap,vlan=0
Ben bu komutu her seferinde hatırlamak zorunda kalmamak için su betiği yazdım:
bekir@laptop:~$ cat bin/start-kvm-host
#!/bin/bash
# /etc/kvm/ altındaki dosyaları elledim: http://www.linuxquestions.org/questions/linux-networking-3/kvm-qemu-and-nat-on-the-host-machine-mini-tutorial-697980/
#IP address: 192.168.172.12
#Netmask: 255.255.255.0
#Gateway: 192.168.172.1
#DNS: 192.168.0.1
# -cdrom /media/free/debian-504-i386-CD-1.iso
exec sudo kvm -vnc :0 -hda /media/free/kvm_vserver_kernel -m 300 -net nic,vlan=0 -net tap,vlan=0
bekir@laptop:~$
Şimdi makinanın arayüzüne bağlanmak için sunu kullanabilirsiniz (Eğer bir şeyler doğru gitmezse açılan kvm'in ekranını buradan görebilirsiniz)
bekir@laptop:~$ sudo aptitude install vncviewer
bekir@laptop:~$ vncviewer localhost
Şimdi KVM içerisine kurduğumuz debian'a yerleşmeye başlayabiliriz:
bekir@kvm:~$ sudo aptitude install linux-image-vserver-686 util-vserver ssh
bekir@kvm:~$ sudo reboot
bekir@kvm:~$ sudo vserver vserver_template build -m debootstrap --hostname vserver_template.laptop.bdgn.net --interface eth0:192.168.172.3/24 -- -d lenny -m http://ftp.de.debian.org/debian # biraz uzun sürüyor
bekir@kvm:~$ sudo vserver vserver_template start
Starting enhanced syslogd: rsyslogd.
Starting OpenBSD Secure Shell server: sshd.
bekir@kvm:~$ sudo vserver vserver_template enter
root@vserver_template:~# # artık yeni sunucu içindesinizistediğiniz paketeri kurun ve template'de olması gerektiğini düşündüğünüz yapılandırmaları yapın
root@vserver_template:~# aptitude install ssh
root@vserver_template:~# adduser bekir
root@vserver_template:~# visudo # bekir ALL=(ALL) ALL
root@vserver_template:~# # key'lerinizi koyabilir ve daha istediğiniz değişiklikleri de burada yapabilirsiniz
root@vserver_template:~# logout
bekir@kvm:~$
Hemen yeni makinamiza ssh ile girmeyi deneyelim:
bekir@kvm:~$ ssh 192.168.172.3
The authenticity of host '192.168.172.3 (192.168.172.3)' can't be established.
RSA key fingerprint is 3c:fd:16:d0:04:43:39:32:c5:14:5b:49:7a:cd:f9:5b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.172.3' (RSA) to the list of known hosts.
Last login: Wed May 19 03:51:19 2010 from 192.168.172.3
bekir@vserver_template:~# sudo aptitude install vim emacs bash-completion
bekir@vserver_template:~# sudo aptitude install locales
bekir@vserver_template:~$ sudo dpkg-reconfigure locales
bekir@vserver_template:~# # ev dizinime gereken dosyalari tasidim ve ssh key'imi de koydum
bekir@vserver_template:~# sudo update-alternatives --config editor # vim.basic
bekir@vserver_template:~$ sudo apt-get clean # çok büyük boyutlu olabilir, her makina için kopyalanacağından temizlemekte fayda var
bekir@vserver_template:~$ logout
bekir@kvm:~$
Artık template'imiz hazır, template makinamızı açık tutmayalım:
bekir@kvm:~$ sudo vserver vserver_template stop
Yeni makinalar yaratmak için de alttaki gibi bir betik yazdım. Bu betik şu işleri de yapıyor:
  • sıradan bir ip bulup makineye veriyor, ismiyle ulaşabilmemiz için /etc/hoşts'a makina adını ekliyor
  • bütün sanal makinalarının /home ve /var/cache/apt/archives dizinleri kvm makinasındaki ile ortak oluyor.
  • sanal makinaların kvm makinası açılışında kendiliğinden başlamalarını sağlıyor.
bekir@kvm:~$ cat /usr/local/bin/create_vserver
#!/bin/bash
V_NAME=$1

[ "$USER" == "root" ] || { echo "You must bee root"; exit 1; }
[ -z "$V_NAME" ] && { echo "Give a vserver name"; exit 1; }

MAX_IP=$(cat /etc/vservers/*/interfaces/0/ip | cut -d. -f4 | sort -n | tail -1 )
V_IP=192.168.172.$[MAX_IP + 1]

echo "Creating new vserver $V_NAME with ip $V_IP ..."

vserver $V_NAME build -m clone --hostname $V_NAME.laptop.bdgn.net --interface eth0:$V_IP/24 -- --source /var/lib/vservers/debian
echo -e '/home\t/home\tbind\tbind\t0\t0' >> /etc/vservers/$V_NAME/fstab
echo -e '/var/cache/apt/archives/\t/var/cache/apt/archives/\tbind\tbind\t0\t0' >> /etc/vservers/$V_NAME/fstab
echo "default" > /etc/vservers/$V_NAME/apps/init/mark
vserver $V_NAME start
vserver $V_NAME exec bash -c 'rm /etc/ssh/ssh_host_*'
vserver $V_NAME exec bash -c 'dpkg-reconfigure openssh-server'

echo $V_IP $V_NAME >> /etc/hosts

echo "Created new vserver $V_NAME with ip $V_IP"

exit 0
bekir@kvm:~$
Artık sanal makina yaratmak ve silmek su kadar basit:
bekir@kvm:~$ sudo create_vserver test_makinasi
Creating new vserver test_makinasi with ip 192.168.172.4 ...
Starting enhanced syslogd: rsyslogd.
Starting OpenBSD Secure Shell server: sshd.
Creating SSH2 RSA key; this may take some time ...
Creating SSH2 DSA key; this may take some time ...
Restarting OpenBSD Secure Shell server: sshd.
Created new vserver test_makinasi with ip 192.168.172.4
bekir@kvm:~$ ssh test_makinasi
The authenticity of host 'test_makinasi (192.168.172.4)' can't be established.
RSA key fingerprint is 1a:50:a9:51:8e:5b:c3:a9:96:d6:85:51:8c:00:ea:0b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'test_makinasi,192.168.172.4' (RSA) to the list of known hosts.
Last login: Tue May 18 01:05:32 2010 from 192.168.172.1
bekir@test_makinasi:~$ logout
bekir@kvm:~$ sudo vserver-stat
CTX PROC VSZ RSS userTIME sysTIME UPTIME NAME
40006 21 214.3M 93.9M 3m32s63 2m22s18 17h40m26 veli
40008 6 43.5M 8M 0m02s10 0m00s64 17h40m26 pyldap
40009 3 23.5M 2.2M 0m02s52 0m01s25 28m22s75 test_makinasi
bekir@kvm:~$ sudo vserver test_makinasi delete
Are you sure you want to delete the vserver test_makinasi (y/N) y
Stopping enhanced syslogd: rsyslogd.
Asking all remaining processes to terminate...done.
All processes ended within 1 seconds....done.
bekir@kvm:~$
Şimdi kendi makinamizdan sanal sunuculara da ip adresleri ile erişebiliriz:
bekir@laptop:~$ ssh 192.168.172.4
The authenticity of host '192.168.172.4 (192.168.172.4)' can't be established.
RSA key fingerprint is 1a:50:a9:51:8e:5b:c3:a9:96:d6:85:51:8c:00:ea:0b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.172.4' (RSA) to the list of known hosts.
Last login: Wed May 19 21:23:00 2010 from 192.168.172.4
bekir@test_makinasi:~$
SSH ile sanal sunuculara laptoptan erişebilmek için de laptop'umda şu ayarı yaptım:
bekir@hede:~$ sudo sh -c 'echo 192.168.172.2 kvm >> /etc/hosts'
bekir@hede:~$ cat >> ~/.ssh/config
> Host t-*
> ProxyCommand ssh $DEBUG -t kvm nc -w 1 -q 1 $(echo %h|sed 's/^t-//') %p
bekir@hede:~$ ssh kvm
bekir@kvm:~$ logout
bekir@hede:~$ ssh t-test_makinasi
The authenticity of host 't-test_makinasi ( < no hostip for proxy command>)' can't be established.
RSA key fingerprint is 86:a2:55:22:20:5c:57:43:e2:b5:dc:9a:2c:0d:87:90.
Are you sure you wat to continue connecting (yes/no)? yes
Warning: Permanently added 't-test_makinasi' (RSA) to the list of known hosts.
Last login: Wed May 19 21:36:21 2010 from 192.168.172.4
bekir@test_makinasi:~$ logout
bekir@hede:~$

27 Temmuz 2009

Üreticilerin İş Takvimi ve Yöneticilerin İş Takvimi

Paul Graham'ın Temmuz 2009 tarihli bir makalesinin Türkçe çevirisi.

Uzun zamandır acısını çektiğim bir konu. Ana dilinde okumak isteyenler için Türkçe'ye çevirdim. Buyrun, afiyet olsun:


Üreticilerin İş Takvimi ve Yöneticilerin İş Takvimi
Temmuz 2009

Programcıların toplantıları sevmemesinin bir nedeni de onların diğer insanlardan farkli bir iş takviminde çalışmasıdır. Toplantıların onlara maliyeti daha yüksektir.

Benim "üreticilerin iş takvimi" ve "yöneticilerin iş takvimi" olarak adlandirdigim iki tür çalışma saati düzeni var. Yöneticilerin iş takvimleri patronlar içindir. Bir günün saatlik parçalara bölündüğü geleneksel bir randevu sistemi içerir. İsterseniz bir kaç saati tek iş için gruplayabilirsiniz fakat çalıştığınız işi ontanimli olarak her saat değiştirirsiniz.

Bu yöntemi kullandığınız zaman, birileriyle görüşmek sadece pratik bir problemdir. Takvimde boş bir saat bulur, orayı dolu olarak işaretler ve bitirirsiniz.

En güçlü insanlar yönetici iş takviminde çalışırlar. Bu, emir verme iş takvimidir. Fakat programcılar ve yazarlar gibi iş yapan insanlar arasında zamanı kullanmanın başka bir yöntemi daha vardır. Onlar zamanlarını, genellikle yarım günlük birimlere ayırarak kullanmayı tercih ederler. Saatlik birimlerle program yazamazsınız. Bu, ancak başlamak için gereken süredir.

Üretici iş takviminde çalışıyorsanız toplantılar tam bir faciadır. Tek bir toplantı tüm öğleden sonrayı iş yapılamayacak iki parçaya bölerek uçurabilir. Üstüne toplantıya gitmeyi hatırmalanız da gerekir. Bu, yönetici iş takviminde çalışanlar için sorun değildir. Her zaman bir sonraki saat için sırada olan yani bir iş vardır, tek soru ne olduğudur. Fakat üretici iş takviminde, bir toplantı olduğu zaman, bir de onu hatırlamak zorundadırlar.

Üretici iş takviminde çalışanlar için toplantılar istisna fırlatmak gibidir. Bu sadece bir işten diğerine geçmenize neden olmaz, çalıştığınız kipi de değiştirir.

Bir toplantının bazen bütün bir günü etkilediğini farkettim. Bir toplantı, sabahı ya da öğleden sonrayı bölerek genellikle en az yarım günü yer. Fakat ek olarak bazen kademeli bir etkisi olur. Eğer öğleden sonranın bölüneceğini biliyorsam sabahları da işe istekle başlayacak hevesim olmaz. Bunun aşırı duygusal gibi göründüğünü biliyorum ama bir üretici iseniz kendi durumunuzu düşünün. Tüm günün, hiç toplantı olmadan çalışmak için serbest olması sizi heyecanlandırmaz mı? Böyle olmadığında içinizde bir sıkıntı olur. İddalı projeler tanım olarak sizin kapasitenizin sınırlarındadır. Hevesinizdeki küçük bir azalma onları öldürmek için yeterlidir.

Her takvim sistemi kendi başına gayet güzel çalışır. Sorunlar bu iki takvim sistemi birbirleri ile karşılaştıklarında ortaya çıkar. En güçlü insanlar yöneticilerin iş takviminde çalıştıkları için isterlerse diğerlerini kendi düzenlerine uymaya zorlayabilirler. Fakat daha zekice olanları, eğer kendileri için çalışan insanaların calışabilmek için uzun aralıklara ihtiyaçları olduğunu biliyorlarsa kendilerini frenlerler.

Bizim durumumuz alışılmadık bir durumdur. Neredeyse tüm yatırımcılar (bildiğim tüm risk sermayedarları dahil) yönetici iş takviminde çalışırlar. Fakat "Y Combinator" üretici iş takviminde çalışır. Rtm, Trevor ve ben de zaten öyle çalışıyorduk. Genellikle Jessica da öyle çünkü o da bizimle uyumlu olmalıydı.

Bizimki gibi şirketler artarsa şaşırmayacağım. Kurucuların artan şekilde yöneticiye dönüşmeye direneceği ya da en azından geciktireceğini düşünüyorum. Sadece bir kaç onyıl önce kot pantolondan kumaş pantolona dönmek için direnmeye başladılar.

Biz üretici iş takvimi kullanarak bir çok yeni kurulan şirkete danışmanlık yapmayı nasıl başarıyoruz? Yönetici is takvimini taklit eden alışılmış yöntemi kullanarak: ofis saatleri. Haftada bir kaç kez ödenek sağladığımız kurucular ile görüşmek için zaman aralıkları ayarlıyorum. Bu zaman aralıklarını benim iş günümün sonunda, belirli ofis saatlerine yerleştiren bir kayıt uygulaması yazdım. Toplantılar günümün sonunda olduğu için asla günümü bölmüyorlar. (Görüşecegim insanların iş günleri benimkinden farklı zamanlarda bitiyorsa onların takvimi bölünüyor, ama görüşme isteğini onlar yaptığından dolayı, onlar için buna değse gerek.) Yoğun dönemlerde ofis saatleri bazen günü sıkıştıracak kadar uzayabiliyor ama günü sıkıştırsalar da asla bölmüyorlar.

Biz 90'larda kendi şirketimizi kurduğumuz dönemlerde günümü bölmek için başka bir numara geliştirmiştim. Akşam yemeğinden gece 3'e kadar program yazıyordum çünkü gece çalışmamı kimse bölemiyordu. Sonra sabah 11'e kadar uyuyordum ve işe gelip akşama kadar çalışıyordum, bunu "iş şeyleri" diye adlandırıyordum. O zamanlar bunu hiç bu şekilde düşünmemiştim, fakat aslında her gün iki işgünüm vardı, birisi yönetici iş takviminde ve diğeri üretici iş takviminde.

Yönetici iş takviminde çalışıyorsanız üretici iş takviminde asla yapmayı istemeyeceginiz kimi şeyleri yapabilirsiniz: kuramsal toplantılar yapabilirsiniz. Birileriyle sadece birbirinizin ne yaptığını öğrenmek için toplanabilirsiniz. Eğer takviminizde bir boşluk varsa neden olmasın? Belki de işler birilerine hiç beklemediğiniz şekilde yardım etmenizle sonuçlanabilir.

Silikon Vadisi'ndeki (ve dünyanın kalanındakı) işadamları sürekli kuramsal toplantılar yaparlar. Eğer yönetici iş takviminde çalışıyorsanız sürekli uygun şekilde boşturlar. Aralarında kullandıkları "bir kahve içelim" gibi bir belirgin bir dilleri vardır ve görüşmek için bunu sıkça kullanırlar.

Eğer üretici iş takviminde çalışıyorsanız kuramsal toplantılar son derece masraflıdır. Bizi usandırır. Herkes, diğer yatırımcılar gibi bizim yönetici iş takviminde çalıştığımızı varsayar. Bizi gerekli gördükleri insanlar ile görüştürürler ya da eposta ile bir kahve içme önerisinde bulunurlar. Bu noktada iki seçeneğimiz vardır, iki seçenek de pek iyi değildir: onlarla görüşebilir ve yarım günlük işimizden olabiliriz ya da onlarla görüşmemeye çalışır ve muhtemelen onları gocundururuz.

Bu güne kadar sorunun kaynağı hakkında kafamız net değildi. Bunu, ya takvimimizi fırlatıp atmak zorundaymışız ya da insanları kırmamız gerekiyor gibi ele almıştık. Fakat artık ne olup bittiğini biliyorum, belki de bir üçüncü seçenek vardır: iki farklı iş takvimini anlatan bir şeyler yazmak. Belki sonunda, yönetici iş takvimi ile üretici iş takvimi arasındaki çakısma daha çok anlaşılır ve zamanla daha az sorun olmaya başlar.

Üretici iş takviminde olan bizler uzlaşmaya istekliyiz. Belirli miktarda toplantılara girmemiz gerektiğini biliyoruz. Yönetici iş takviminde çalışanlardan tüm istediğimiz bu bedeli anlamaları.


Sam Altman, Trevor Blackwell, Paul Buchheit, Jessica Livingston ve Robert Morris'e bunun taslaklarını okudukları için teşekkürler.

Paul Graham

08 Haziran 2009

The Other Half of "Artists Ship"

Paul Graham'in bir makalesinden alinti:

Buyuk sirketler ile sifirdan baslayan sirketler arasindaki farklardan birisi buyuk sirketlerin kendilerini hatalardan korumak icin surec gelistirmesidir. Sifirdan baslayan sirketler yeni yurumeye baslayan cocuklar gibi surekli oraya buraya carpip duserler. Buyuk sirketler daha tedbirlidir.

Bir kurulusta zamanla biriken denetimler kaynagini gecmis felaketlerden alan bir ogrenme seklidir. Ornegin batmakta olan bir bayi ile anlasma imzalayan bir sirket, musterilerine mallari teslim edemezse tum bayileri icin odeme gucu olduguna dair bir belge saglamayi zorunlu tutabilir.

Sirketler buyudukce gerek felaketlerden edindikleri deneyimler ile gerekse daha buyuk sirketlerden aldiklari yeni calisanlarin getirdigi deneyimler ile denetimlerinin sayisi surekli artar.

Hatalardan ogrenmek kuruluslarin dogasinda vardir. Asil sorun yeni denetimler oneren insanlarin neredeyse hic bir zaman denetimin kendi maliyetini dusunmemeleridir.

Her denetimin bir maliyeti vardir. Ornegin bayilerin odeme guclerini dogrulamalari durumunu ele alalim. Bu saf ongoru degil mi? Fakat aslinda bunun azimsanmayacak bir maliyeti olabilir. Her iki tarafta da odeme gucu icin kanitlari hazirlayan ve inceleyenler insanlarin zaman masrafi oldukca net. Fakat asil maliyet gormediginiz yerlerdedir: en iyi bayi olabilecek sirket teklif vermeyebilir, onaylanmak icin bosa caba harcamak istemiyorlardir. Ya da odeme gucu belirlenen esik degerin altinda kalan en iyi muhtemel bayi, ne de olsa belirlenen esik degerini yukseltmenin gorunen bir maliyeti yok.

Kurumlarda ne zaman birisi yeni bir denetim onerse faydalarinin yaninda zararlarini aciklamali. Bu ust-denetim, analizinin ne kadar iyi yapildigindan bagimsiz olarak, denetimin ayni zamanda bir maliyeti oldugunu da hatirlatacak ve bunu arastirmaya itecektir.

...

Yillardir kendi calistigim sirkette destekledigim yontemler nedeniyle cevremdekiler tarafindan duzen karsiti birisi, bir anarsist olarak anildim. Yazdigimiz her kural ve yonerge maddesinin zararlarini farkli sekillerde dile getirmeye calistim. Bunca zamandir sanirim hic bir cabam anlatmak istediklerim konusunda bu yazi kadar net olamadi. Dile getirdiklerimin bir kismini Paul Graham bu yazida cok net bir dille ele almis. Uzgunum ve mutluyum.

03 Haziran 2009

PHP Oturumlari Uzerine Kisa(!) Bir Hikaye

Son zamanlarda Zeitin'de gelistirdigimiz bir goruntu yayin aracinin arayuzunu PHP ile yazmayi tercih ettik. Bir canli yayin uygulamasi. Herhangi bir internet kamerasindan (webcam) aldigimiz goruntuyu canli olarak yayinlayabiliyoruz. Ornegi icin bizim sirketin sitesine bakabilirsiniz, ofisimiz 24 saat hizmetinizde.





Yayin yapacak olan kisi kamera takili bir bilgisayar ile yayin arayuzune giriyor ve bir flash uygulamasi araciligiyla yayin hemen basliyor. Biz bu is icin sirketteki eski dizustu bilgisayarlardan birisine bir kamera bagladik, yayin sayfasini actik, giris yaptik ve dizustu bilgisayari ofiste uygun dolabin uzerine tozlanmaya terkettik.


Kameranin surucusu daha sorunsuz calistigi icin dizustune Windows kurup oldugu yerden tekrar indirmemek icin de uzerine bir vnc sunucu kurduk. Oldu, calisti. Ne de olsa tum isi bir internet sayfasini acik tutmak, gunlerdir basariyla yapiyor bunu.

Ancak yayincida cok uzun sure (bir kac gun/hafta) acik kalan flash uygulamasi bir sure sonra tarayiciyi yoruyor. Bunun icin yayin sayfasi saatte bir kendisini yeniliyor (bildiginiz META tag'i ile). Yayincinin oturumunu unutmamasi ve her yenilenmesinde giris ekranina geri donmemesi icin de PHP oturumuna yayincinin bilgisini kaydettik.

Sistemi kurduk, her sey bir kac hafta gayet guzel calisti, gun gelip de uygulamaya yeni ozellikler eklememiz gerektiginde giris mekanizmasini da biraz degistirdik. Ancak bu degisiklikten sonra yayincinin oturumu her 4-5 saatte bir zaman asimina ugramaya basladi.

Hatanin nedenini anlamayinca git teslimleri uzerinden tum yamalari satir satir inceledik. Hatanin nedenini gene bulamadik. Haftalarca calisan kod durduk yerde calismaz olmustu ve ortada hataya neden olacak tek satir yoktu.



Artik kodda hata olmadigindan emindik (oysa onca zaman hatanin kodda oldugundan emin gibiydik), kod disinda bizi etkileyebilecek bilesenleri incelemeye basladik. Apache ayarlari, php.ini, yayincidaki cerezlerle (Cookie'ler) ilgili ayarlar...

Sorun uzerinde 2-3 kisi dusundugumuz halde gunlerce nedenini bulamadik. Sonunda PHP'nin oturumlari nasil yonettigini anlamak icin php.net'teki ilgili sayfalari okurken uc adet calisma zamani yapilandirmasi dikkatimi cekti.

Birisi session.cache_expire degiskeni idi. Bir oturumun ne kadar hayatta kalacagini belirtiyordu. Ontanimli degeri 3 saat idi ama bizim 30 dakikada bir kendini yenileyen sayfa oturumunu duzenli olarak 3 saat'te bir unutmuyordu, bazen 4-5 saati bile geciyordu. Hem yarim satte bir yeniden baslayan oturum neden zaman asimina ugrasindi ki.

Diger iki degiskeni pek anlamlandiramadim: session.gc_divisor ve session.gc_probability. Bu degiskenler oturumlari temizleme isleminin kac oturum baslatma (session_start()) basina yapilacagini belirtiyordu. Bu pek makul gelmedi.

PHP arka planda calisan ve surekli ayakta duran bir hizmete (daemon) sahip degil. Sonucta PHP, istekler geldikce (sayfalar acildikca) Apache tarafindan cagrilan bir uygulamadan ibaretti. Dolayisiyla zaman asimi gibi belli surelerde bir yerine getirmesi gereken gorevlerin zamanlamasi icin ince cozumler gerektiriyor.

PHP gelistiricileri oturumlarin zaman asimina ugratmak icin her session_start() isleminde %1 ihtimalle temizlik yapmayi uygun bulmuslar. Aslinda cok cakma bir cozum ama anlasilan pratikte ihtiyaci karsiliyor ki yillardir farkina bile varmamisim.

Bizim sistemimizde ise calisan tek site bahsettigim yayinci sayfasi ve oturum kullanmayan izleyici sayfalarindan ibaret diyebilirim. Bu durumda session_start() cagri sayimiz da her yarim saatte sadece "bir". Dolayisiyla 3 saat gectikten sonra oturumun kapanma olasiligi her yarim saatte %1.

Bunlari anlayinca aralarda gordugumuz 4-5 saat boyunca zaman asimina ugramama durumunu aciklayabildim. Kucuk bir hesapla oturumun 3 saatlik zaman asimi sonrasinda her yarim saat icin sadece 1/100 ihtimal ile temizlenecegini dusunursek, diyelim ki %1 ihtimal 50. denemede denk geldi. Bu durumda sistemin 30dk*50 = 25saat kadar dayanabilmesi gerekirdi. Ancak sistemin en cok 5-6 saat kadar dayandigini biliyordum.

PHP'nin oturum degiskenlerini /tmp altinda bir dosyada tuttugunu bilyordum, biraz inceleyince buldum ki benim kullandigim Debian Lenny sistemde aslinda /var/lib/php5 dizininde duruyordu. (PHP'yi hic elle derlemedigim icin kullandigi dizinlerin yerine pek asina degilim.)

Uzun bir sure /var/lib/php5'i nereden hatirladigimi cikartamadim. Sonra surekli olarak /var/log/messages'da bununla ilgili kayitlari gordugumu hatirlayabildim:
Jun 2 21:39:01 farmer /USR/SBIN/CRON[25973]: (root) CMD ( [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -type f -cmin +$(/usr/lib/php5/maxlifetime) -print0 | xargs -n 200 -r -0 rm)
Cron'dan yarim saatte bir calisan bu betik /var/lib/php5/ altinda son degisiklik tarihi belli sureden daha eski olan dosyalari temizliyordu.

/usr/lib/php5/maxlifetime da bir bash betigiydi ve yaptigi is de /etc/php5/*/php.ini dosyalarini okuyarak aralarinda en uzun zaman asimi suresini donmekti. PHP'den boyle cakma bir cozum beklemiyordum dogrusu. Gerci bu cozumu belki de Debian paketcileri yapmistir, pesine dusup incelemedim.

/usr/lib/php5/maxlifetime betigi de benim sistemimde 24 degeri donuyordu. Crondan da 30 dakikada bir calistigina gore en kotu durumda 24+30=54dk kadar gecikme ile tum oturumlari temizleyecekti.

Bu durum galiba bizim gibi session_start()'i seyrek araliklar ile cagiranlar icin dusunulmustu ve aslinda daha onceki hesabimin sonucunda bulabildigim gibi benim oturumunun asla bir gunu bulmamasini acikliyordu.

Oturumum zaman asimi suresi geldikten sonra en kotu ihtimal ile 54 dakika sonra silinecekti.

Geriye cozemedigim tek soru kaldi: yarim saatte bir session_start() cagiriyorsam zaman asimi suresi de devamli olarak yarim saat otelenecek ve asla zaman asimina ugramayacakti. Ancak kodlarda hata olmadigi halde 3 saat sonra sonra oturum kapaniyordu.

Neyse ki eldeki verilerle cozumu bulmam zor olmadi. PHP oturumlarini /var/lib/php5 dizininde sakliyordu ve syslog'daki saitirdan anladigim kadariyla oturumlari silmek icin de dosya sisteminin tuttugu degisiklik zamani bilgisinden faydalaniyordu. Bu durumda kurdugum oturumun degisiklik zamanini izleyerek sorunun nedenini bulabilirdim.

Oncelikle oturumu baslattim ve oturumumun oldugu dosyayi buldum. Allah'tan PHP oturumlari karmasik sekillerde saklamiyordu:
bekir@farmer:/var/lib/php5$ sudo cat /sess_76995dd9473835f06e03d0da59275eef
publisher|s:6:"kaplan";token|s:9:sts18683140";
Sonra stat komutu ile benim oturum dosyamin bilgilerine baktim, asagida gordugunuz "Change:" yazan kisim dosyada en son ne zaman degisiklik yapildigini gosteriyor.

bekir@farmer:/var/lib/php5$ sudo stat ./sess_76995dd9473835f06e03d0da59275eef
File: `./sess_76995dd9473835f06e03d0da59275eef'
Size: 45 Blocks: 8 IO Block: 4096 regular file
Device: 904h/2308d Inode: 15705843 Links: 1
Access: (0600/-rw-------) Uid: ( 33/www-data) Gid: ( 33/www-data)
Access: 2009-06-03 00:37:44.000000000 +0300
Modify: 2009-06-03 00:37:26.000000000 +0300
Change: 2009-06-03 00:37:26.000000000 +0300
PHP oturumlari temizlerken sadece degisiklik zamanina baktigi icin artik tum is sadece bu dosyanin son degistigi zaman ("Change:") degerinin ne zaman kuruldugunu kesfetmeye kalmisti.

Bir kac deneme yaptim. Oturum olustugunda dogal olarak yukaridaki gibi bir kayit olusuyordu ancak yarim saatte bir gelen sayfa guncellemelerinde bu ozellik guncellenmiyordu. Oysa ki her seferinde session_start()'i cagiriyordu ancak dosyayi takip ettigimde sadece erisim ("Access:") zamaninin degistigini farkettim.

Yazdigimiz kodlara dondum oturumla ilgili kisimlarini tekrar okudum. Eger kurulu bir oturum varsa sayfayi kullaniciya gosteriyor ve oturum uzerinde uzerinde hic islem yapmiyorduk. Cok guzel.

Ancak oturum uzerinde islem yapmadigimiz icin PHP oturum dosyasini asla guncellemiyor ve dolayisi ile dosya sisteminedeki degisiklik zamani ("Change Time") bilgisinin guncellenmesini tetiklemiyordu.

Belkedigimin aksine session_start() oturum dosyasinin degisiklik zamanini guncellemiyordu. Aslinda yapiyi anladiktan sonra cok normal bir davranis oldugunu anlayabiliyorum.

Tum bu incelemelerden sonra koda tek satir ekleyerek uyguladigim cozum her sayfa acilisinda oturum olsa da sadece bir oturum degiskenine atama yapmak oldu.

Gunlerdir aradigimiz sorunun cozumu soyle tek satir imis:
$_SESSION["reset_session_timeout_hack"] = 1;

Sistem su anda iki gundur sorunsuz calisiyor. Tum yazdiklarimi buldugum gece php.net sitesini gezip hatayi ayiklamak 2 saat kadar vaktimi almisti ama bu yaziyi hazirlamak icin 6 saat kadar caba harcadim, hala bir yerlerde ciddi yanlislik yapiyorum sanirim.

17 Eylül 2008

Kod gozden gecirme sureci ve GvR amcanin katkilari

Gecen gun Google App Engine ile bir seyler denerken farkettim ki sundugu SDK'de bulunan appcfg.py ile elimizdeki kodu teslim etmeden once yaptigimiz degisikliklere gozatma imkanimiz yok. Kodlarimizi svn gibi bir surum denetim dizgesi kullanmamiz gerekiyormus. oysa app engine'deki surum numaralarini gorunce sonuncu ve simdiki araasindaki degisikliklere bakabileceimi sanmistim.

google'da "google app engine pre commit diff" gibi bir arama yapinca karsima http://code.google.com/p/rietveld/ geldi. parkyeri'nde zamanla ve acilar cekerek kesfettigimiz kod gozden gecirme surecinin cok benzerini google'da da kullaniyorlarmis ve Guido van Rossum(GvR - python'un yaraticisi ve hala yon vericisi, etkin kod gozden gecirici) amcamiz google'a girdikten sonra ilk proje olarak bu sureci iyilestirmek icin kollari sivamis, mondrian diye bir arac yazmis.

bizim mevcut yapimiz asagidaki gibi ve google'daki ile fazlasiyla benzerlik gosteriyor, meraklilari icin parantez icerisine kendi kullandigim araclari yazdim:

  1. bir kisigereken kodu yazar (emacs ... | vim ...)

  2. yama uretir (svn diff > ticket_no.patch)

  3. ilgili gelistirme grubuna gozden gecirme icin eposta atar (mutt -a ticket_no.patch hede@parkyeri.com)

  4. gruptan bir kisi kendi deposuna yamayi uygular (patch -p0 < ticket_no.patch)

  5. kodu inceler (emacs ... | vim ...)

  6. kodu inceleyen kisi epostadaki yama icerisine notlarini yazar ve kodun yazarina gonderir, (mutt)
    (ya da benim genelde yaptigim gibi yazan adam ile dogrudan konusarak sosyal yollarla da cozebilir (finch, konusma))

  7. kodu ilk yazan kisi kodu tekrar duzenler ve tekrar yama uretip gonderir (svn diff ... , mutt -a ...)

  8. bu surec, kodu gozden geciren kisi "eline saglik teslim edebilirsin"(este) (Enver'den bize miras olarak kaldi) diyene kadar tekrarlar (bazen yamalarimiza changelog eklemedigimiz icin "este" yerine "changelog ekleyip teslim edebilirsin[cete]" cevabi da gelebilir)

  9. son olarak da "este" alan kodlarimizi teslim ederiz (svn commit)


Kullandigim araclar basit gozukebilir, ama genel olarak islerini guzel yapan araclar ve cok da fazla dis yardima ihtiyac kalmiyor. Genellikle kodlarimizi ssh ile eristigimiz uzaktaki makinalar uzerinde gelistirdigimiz icin diger gelistiricilerin ev dizinlerinden onlarin neler yaptigini izleyebiliyoruz ve yama alisverisi eposta uzerinden olmak zorunda kalmiyor hatta bir cok durumda yama alisverisi bile olmuyor, girip diger bir gelistiricinin proje dizininde "svn diff | vim -" diyerek kodlari okuyabiliyorum, ancak bunlar gorece kucuk olmamizin getirileri.

Kucuk projelerde artik gozden gecirme surecimiz dahi olmuyor, degisikliklerin takibi ve teslim sonrasi gozden gecirme icin svn teslim epostalari, Trac ve eklentileri yeterli.

Gozden gecirmenin onemini anlatip duran ve bunu python gibi buyuk bir projeyi yonettigi icin yapmak da zorunda olan GvR amcamiz zamaninda ortaya koydugu mondrian'i fazla google bagimli oldugu icin (perforce ve bigtable gibi bagimliliklar yuzunden) acik kaynak haline getirememis, ancak daha sonra Rietveld adiyla acik kaynak olarak da yayinlamis ve diger acik kaynak projelerin kullanimina CodeReview adiyla google app engine uzerinden acmis.

Aracin (rietveld) ornek kullanimi burada.

22 Temmuz 2008

Yeni bisiklet, Sariyer

Uzun zamandir bisiklet alma hevesiyle ortalarda dolanip duruyordum. Samet ve
Yigit ile Hasim-Iscan Gecidine gidip oradaki vahim durumu gordukten sonra
sonunda cuma gunu Samet ile Velespit'ten son model bisikletimi gonul rahatligi
ile aldim.

Ayni gece geziye cikayim bogaz sahillerinde gezineyim dedim. Saat 02:00'de
evden ciktim, Sisli'den Taksim'e ve oradan Besiktas uzerinden sahilden devam
ettim. Eglence mekanlarinin onu oldukca kalabalikti. Sahilden devam ettim.
Sahil seridinde gece fareler ve kopekler cirit atiyormus. Evet evet, bir suru
boyut ve cesitte fare gordum, hatta bir kismiyla sahilde birlikte yol aldik.

Ortakoy, Bebek, Istinye derken Tarabyaya geldim, gecenin 3'unde hala balik
tutan bir suru insan vardi. Oralardaki bir tekel bayine ugradim ama param
olmadigi icin neredeyse su alamiyordum. Neyseki tekelci sadece 1.5 litre suyu
bankamatikten cekti de susuz kalmadim, Sariyer'e cok fazla kalmadigini
ogrendim, yola devam ettim.

Dolunay sayesinde sahilin isiklandirilmamis kisimlari da karanlik degildi ama
kopekler zaman zaman tehlike arzedebiliyordu.

Saat 3:40'da Sariyer'e vardim ve oradaki bankadan para cekip gerisin geri
tekelciye dondum; Cokonat, Hobby ve yarim litrelik bir su daha aldim, bu kez
para ile odedim.

Donuste kopekler ve fareler disinda sahildeki bos bira siselerine de dikket
etmek gerekti. Ozellikle Rumeli Hisari'ni gectikten sonraki park baya demlenme
mekani haline gelmis.

Bebek'e geligimde bufe gordum dayanamadim bir sosisli yemek icin durdum, bu
sirada sabah ezani okunmaya basladi.

Bebek'ten cikip ortakoye gelirken gunun aydinlanmaya baslamasiyla sahilde balik
tutmaya gelmis oldukca yogun (en azindan o saatler icin) bir kalabalik vardi.

Ortakoye gelmeden ictigim sular etkisini gosterinde bir benzincide mola vermek
zorunda kaldim, mola vermisken iki de King Top alip icinden cikan alti
cikolatayi mideye indirdim.

Ortakoyde hayatimin en tezat goruntulerinden biriyle karsilastim, eglence
mekanlarindan cikip, arabalarini getiren valeye bahsis veren insanlarin tam
yanindaki copu kurcalayan bir amca vardi, cok fotograflik bir andi.

Goruntuye cok da takilamadim cunku eglence sonrasi kafayi bulan insanlarin
kirdigini sandigim siselerin cam parcalarindan kacinmaya calisiyordum.

Ortakoye geldigimdehenuz gunes'in dogmasina vakit olsa da artik hava
aydinlanmaya baslamisti. Gunes dogmadan Besiktas Stadi'nin yanindaki yokusu
tirmanmayi tamamlayabildim

Mecidiyekoye geldigimde saat 06:00 olmustu, hava iyiden iyiye aydinlanmisti ama
gunes hala ortalarda gozukmuyordu.

Hakkımda

Fotoğrafım
Bekir Dogan
Istanbul, Turkey
Profilimin tamamını görüntüle