bdgn

Linux Admin

Wednesday, August 05, 2015

Tuesday, August 04, 2015

A reference Mesos cluster setup - 1

After having my own bare-metal cluster at home, I will try to build a sample system just for fun with overall goals:
  • minimum dependency on any existing *aaS, and make the system self contained for each piece,
  • prevent any kind of vendor-lock-in,
  • make any part of system HA (dc-wide only),
  • zero touch ops, allow system to detect and auto-heal probles,
  • ready to use infra services to cover most usual scenarios like ELK, CI/CD, Monitoring/Alarming
  • (scope is intra-dc, so there will be no inter-dc solutions)
To achieve these goals, I'm thinking about using following components for my own reference implementation.

Before , I played with mesos/docker on CoreOS/Ubuntu on some cloud providers, also tried some DCOS. And I ended up with a Mesos installation on Ubuntu just because I still feel myself more comfortable on Ubuntu while playing around.

Cluster Level Service Management
This was already my starting point for the whole idea. Mesos + Marathon + Chronos will likely do the job.

Service Discovery
Thanks to guys from Mesosphere, we could get some well defined service discovery solutions without a lot of effort. We have mesos-dns (gives us also SRV records) and haproxy-marathon-bridge (will likely replaced by servicerouter.py) nearly for free.
Consul could also help but it needs some not-ready-yet dependencies like an etcd cluster setup.

VPN
Creating an OpenVPN service seems fairly simple with marathon+docker, thanks to Kyle Manna.

Code repository
I will likely use some kind of git repository just for not to depend on github, most likely GitLab, but GitLab is depending on many other components that each should be carefully architectured HA with auto-heal in mind, I did not look into this yet.

CI/CD
Seems like using docker with a self-hosted docker-registry could help a lot with deployment problems. And for building and testing, there is a Jenkins integration with mesos but we need to overcome some set of problems cleaning docker leftovers around. I will try to write about this later, but with the current state of docker problems it could not be suitable running docker builds on random nodes.

ELK stack
We need a kind of central log system, ELK stack for identifying production problems easier. There seems like infinite number of log related tools to use with docker. But for me, this hits the lack of persistent-storage problem in current mesos releases for now, elasticsearch framework could help but I'm just not there yet.

Monitoring
Monitoring in general is an already solved problem. but there are no best practices around about how and what to monitor for Mesos/Marathon/Chronos itself since most of the parts of the system will be HA with auto-heal support, hopefully no extensive alarming/notification systems will be needed for most of the components.
Some monitoring/alarming tools like Prometheus (since it also has mesos-exporter), and Satellite seems promising. But both does not seem like mature enough yet. Seems like most Mesos users have their own customized systems for their monitoring infrastructure.

For now I will leave any kind of persistent-storage dependent components to a later phase (Mesos will likely have persistent-storage support soon), I will focus on these components as a first step:
  • mesos
  • marathon - service scheduler for ephemeral and/or idempotent tasks
  • chronos - cluster-wide chron jobs
  • haproxy-marathon-bridge - for HA and service discovery
  • mesos-dns - service discovery using DNS, also generated SRV records
  • openvpn - so that i can reach my cluster from everywhere
  • docker-registry - my own docker registry, I'll use S3 to store images for now to avoid persistent-storage needs
What I'll be missing in my setup is for now:
  • any kind of persistence, big lack in the whole stack, there is no best practices around yet to run services need some kind of persistence
  • disaster recovery on inter-dc/inter-region level
  • DCOS - which have its own package support for easy installing frameworks, seems like mostly helping with frameworks for persistency related framework installations, I'm not able to use DCOS since it seems like they only support AWS for now
  • any kind of security between different components, will do the mistake of assuming local-network safe

Monday, August 03, 2015

Home cluster setup

Recently as a hobby project I was looking for playing with some recently popular tools like mesos, kubernetes, docker-swarm and many other related. After playing around some tests clusters on Digital Ocean and AWS and spending dozens of dollars each month, I realized that I need some constantly running boxes to see how do these brand new tools behave in long term.

IMAG1480After doing some research to find the cheapest available cloud provider, I found the cheapest cloud option is AWS Spot Instances which could be shut down at any time or I should buy my own bare boxes. I wrote a small script to find the cheapest possible AWS Spot instance. As of today US-WEST-2 c3.large spot instances have reasonable prices (less than 12$/month) to play with and have pretty clean records in last months. So if I'd chose a little higher price than the current bid, I'll possibly be happy for months. But somehow I'm excited with the idea of having my own cluster running on metal.

And I started searching for cheap second hand desktop computers. Thanks to some friends with spare computers, old laptops at home and adverts.ie, I got 6 boxes only spending 45Eur in total.

I also had a chance to cycle around Dublin to collect parts :) And guys from adverts were generous to me, they gave me a spare disk and desktop for free, this was really surprising to me. And overall this adventure ended up being cheaper even than the cheapest cloud option I have.  I enjoyed playing with some hardware as I do in my college days. I gather up different parts to build computers and it was really fun :)

But I'm still curious if this is really cheaper than cloud options in long term, I'll buy a watt-o-meter to measure the monthly electricity bill I pay for running these boxes.

There is a down side in this setup that I have to maintain all those nodes and keep them running, as much as you can and as a result of having nodes running without a stable wireless network and power cords my setup gives me implicit chaos-monkey for free. But for real, that helped me a lot with fixing things properly.

Monday, October 08, 2012

Sonunda Arduino siparis ettim, PIC Linux'cu amatorler icin dandik

Evlendiğimden beri evdeki lambaları yattığım yerden telefonla falan kontrol etmek gibi gereksiz bir isteğim vardı. Yattığım yerden kalkmadan evdeki aletleri ve ışıkları kapatsam saçma bir şekilde mutlu olacakmışım gibi geliyor.

Bu uğurda önce transformatör + rf alıcı + role yi birleştirerek bir şeyler yapabileceğimi sanmıştım. Ama devre mevre yapmak hak getire her ne kadar elektrik-elektronik mühendisliği mezunu da olsam anlamıyorum ki bunlardan hiç bir şey, üzerine de mezun olalı 8 yıl olmuş, zaten bilmediğim bilgileri de tamamen unutmuşum.


Derken bir gün DNR'da 50TL'ye satılan bir pakette bir uzaktan kumanda ve onunla yönetilen 3 adet priz gördüm (resmi yanda), aldım içini açıp devre elemanlarına baktım 433Mhz alıcı verici ve onları sürmek için de iki adet entegre (2262 ve 2272) ile karşılaştım, hatta internette de bir amcanın da aynı yoldan geçtiğini ve üzerine sağlam bir analiz de yaptığını buldum.

Bu işlerden anlayan bir akadaşıma (Samet) danıştım "ne yapalım protheus'ta falan çizsek olur mu?" diye, ama genel devre elemanları dışındaki elemanlar için simülasyonun çok mantıklı olmadığını söyledi ve kendiniz deneyip görün dedi.

Kuzenle biraz uğraşıp 433Mhz rf alıcı'dan gelen sinyalle bir şekilde role'yi süreriz diye başladık ise ama yaptığımız denemeler hep hüsranla sonuçlandı. Bakın karaköyden 10TL'ye aldığımız 433mhz alıcı-verici çifti ile olan ilk girişimimiz yanda, aynı zamanda son da oldu bu. Sanırım aralara bir grup transistör ya da benzer bir şeyler falan da gerekiyordu (ne kadar anladığımı buradan anlayabilirsiniz).

Bu tür şeyleri salt analog devreler ile yapabilmek için çok yetersiz olduğum aşikardı, protheus ile bir kaç deneme yapıp görerek anlayabilirim belki dedim üstelik de basit devre yapılarını anlamak için de faydalı olurdu bir simülatör. Önce protheusu wine ile çalıştırmaya çalıştım, sürekli patlayınca sanal Windows makina içerisine kurduğum protheus/isis kurdum ama gene bitmeyen dertleri ile uğraşmaya başlayıp üstüne de windows üzerinde çalışmaya karşı aşamadığım bir direncim ve linux'ta yapabildiğim bir çok şeyi Windows'ta yapamayıp kendimi çok rahatsız hissetmem eklenince durdum gene. Biraz da VMWare ve VirtualBox yerine açık kaynak olan KVM kullanmaya çalışmamın da etkisi var, gene amaçtan sapıp saçma notlarda takılmışım. Ama hobi için yaptığım bir şeyi yapma sürecinde eğlenme beklentim oluyor ve Windows bunu elimden alıyor.

Çevremde bu konular hakkında fikri olan bir kaç kişi de durmadan "PIC ile yapabilirsin" diyordu. Bu sayede bir çok karmaşık devre tasarımından kurtulabilecektim, ben de artık sadece basit devre elemanları ile başaramayacağımı kabul edip mikrodenetleyicilere kayayım yavaştan dedim. Yazılımdan anlıyor ve yeni dillere ve ortamlara hızlı uyum sağlayabiliyordum ne de olsa. Biraz PIC falan bakındım, kuzende bir PIC yazıcı ve bir kaç PIC vardı ama gene widows gerekmesi (sadece win sürücüsü vardı nanenin) ve PIC'in genellikle windows üzerinde yürüyen yapısı nedeniyle gene kaçtım yandan yandan. Çevremde Linux üzerinde PIC ile uğraşan birileri olsa durum farklı olurdu belki.

Little Wire
Bir yıl kadar bir süredir unutmuştum bu konuyu ancak bir süre önce istanbul hakcerspace'de İhsan Kehribar'in anlatimina gittim, little wire diye bir şeyler anlatıyordu, aralarda "AVR programlayıcı değil" falan gibi şeyler diyordu. O günün karı benim için şunlar oldu ve aslında oldukça da karlı bir gündü, sağol hackerspace:

  1. PIC dışında da mikrodenetleyiciler var (AVR) ve bunların da etkin kullanıcı grupları var,
  2. Arduino AVR programlamak için uygun ve çok kolay,
  3. yurtdışından (özellikle çinden) parça getirtmek karaköyden getirtmekten daha ucuz olabilir (ama çok uzun sürede gelir),
  4. gerekirse az sayıda PCB çinde uygun fiyata bastırılabilir
  5. Açık kaynak gibi bir de açık donanım akımı var ve günden güne güç kazanıyor
  6. Elektronik hobicisi kimselerin kendi aralarında oturmuş bir alt-kültürü oluşmuş (makers)
Eve gelip bir kaç gün bakındım PIC gibi diğer mikrodenetleyicilere ve şunlarla karşılaştım:
PIC, nedenini anlamadığım şekilde ülkemde standart olmuş, Karaköy'de PIC satışı yaygın ama AVR veya MSP430 için gördüğüm kadarıyla aynı şey geçerli değil. Ya da ben öyle biliyorum.

Samet de bir süredir MSP430 ve onun geliştirme kartı Launchpad'den bahsediyordu ama o bunlardan bahsederken neyin ne olduğunu anlamadığım için aslında benim de yapmaya çalıştığım şeye paralel olabilecek şeyler yaptığını anlamamıştım.

Benim gibi hobicilerin (daha hiç bir şey yapmadan nasıl hobici oldum tartışılır) kullanması için bir çok farklı geliştirme kartı mevcutmuş. MSP430 için launchpad; pic için PICAXE, oopic, PICKit gibileri varmış; AVR için olanları bilmiyorum çünkü işin aslı Arduino ile karşılaştıktan sonra AVR için olanları pek araştırmadım.

By messi (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons (http://commons.wikimedia.org/wiki/File%3AArduino_Closeup.jpg)
Arduino Uno
Arduino içinde de bir AVR var ve kendisi bir AVR programlayıcı olarak da kullanılabiliyor ve wiring diliyle (amaca özel üretilmiş C türevi dillerden güzel bir tanesi) çok rahat programlanabiliyor.

Benim açımdan Arduino'nın görünen büyük faydalarından birisi Linux kullandığım halde kendimi dışlanmış hissetmemek. Oysa PIC kullanmaya çabaladığım dönemde MPLab ve proteus benim için yöklardı ama bulabildiğim her belge bir şekilde MPLab ile nasıl programlanabileceğini ve proteus'ta nasıl simüle edilebileceğini anlatıyordu. Ben bir çok şeyi ancak kendim yapınca kavrayabilen bir insanım.

Arduino IDE
Arduino'nun geliştirme ortamı linux windows ve maç'de aynı şekilde çalışıyor, kurulumu vakit almıyor (benim için sadece "apt-get ınstall arduino"). Bu da nette bulduğum örnek projelerden kimin nerede yaptığından bağımsız olarak faydalanabileceğim anlamına geliyor.

Prototip geliştirmek için çok sayıda algılayıcı ve hazır bileşenleri Arduino uyumlu eklenti (shield) halinde bulmak mümkün. Hem de  bir çoğu örnek kodlarla ve hatta özgür donanım olarak (yani isterseniz kendiniz de yapabilmeniz için gereken her şeyi açık).

Üstüne üstlük yarın bir gün kurduğum devreyi basitleştirmek istediğimde yazdığım kodu basitçe daha uygun bir AVR'ye uyarlayıp yükleyebilecek ve tüm Arduino kartına gerek kalmadan sadece gereken elemanlar ile kurduğum daha basit devre ile kullanabileceğim (başarabilirsem tabii ki). Bütün bunlar biraz daha ucuz olsun diye tabii ki, evin orasına burasına bir dolu sensor bağlamak istersem her birine bir arduino kat harcamak çok pahalı olur.

Arduino almaya karar verdikten sonra başlangıç yapabilmemi sağlayacak kit ararken bir çok kit bakındım ama sonuçta gene dealextreme'den şunları sipariş verdim:
  • 92TL (51.60$) Arduino Compatible UNO 2011 Component Basic Element Pack Starter Kit-142572
  • 99TL (55.10$) ARDUINO Compatible 37-in-1 Sensor Module Kit - Black-142834   
  • 7TL (3.9$) Ultrasonic Sensor Distance Measuring Module-138563
  • 6.3TL (3.5$) IR Infrared Motion Detection Sensor Module (DC 5V~20V)-139624
  • 3.5TL (2$) 38KHz IR Infrared Transmitter Module for Arduino-135040 
Toplam ~ 210TL (116.1$)

Dealextreme'den bu tür şeyleri almak iyi güzel ancak verdiğiniz siparişlerin ülkeme teslim süresi 1 ay kadar sürüyor. Bu yazıyı yazarken siparişimi vereli 28 gün olmuş (paketler de siparişten 9 gün sonra yola çıktılar) ve paketler hala Türkiye'ye girmiş görünmüyor veya bir yerlerde takıldı. Çinden almanın riski bu işte.

Siparişimdeki ilk iki öğenin içindekiler de şunlar:

- 1 x Arduino UNO board
- 1 x Development expansion board
- 1 x Breadboard
- 1 x LED emitter kit (red / blue / yellow; each 5pcs)
- 5 x 10K resistors
- 5 x 1K resistors
- 8 x 220R resistors
- 1 x 74hc595
- 2 x Buzzers
- 1 x Seven-segment display (1-digit)
- 1 x Seven-segment display (4-digit)
- 10 x Push button switches
- 3 x Light dependent resistors
- 1 x Adjustable resistor
- 1 x LM35 temperature sensor
- 1 x 1602 LCD display
- 1 x PS2 joystick
- 1 x Stepping motor
- 1 x Stepping motor driver board
- 1 x Steering engine
- 1 x RGB module
- 30 x Breadboard cables
- 10 x Dupont lines
- 1 x 2.54mm pin header
- 2 x Mercury switches
- 1 x Flame sensor
- 1 x Infrared receiver
- 1 x USB cable (80cm)
- 1 x Remote control (1 x CR2025 included)
- 1 x Battery case


- 1 x Small passive buzzer module KY-006
- 1 x 2-color LED module KY-011
- 1 x Hit sensor module KY-031
- 1 x Vibration switch module KY-002
- 1 x Photo resistor module KY-018
- 1 x Key switch module KY-004
- 1 x Tilt switch module KY-020 
- 1 x 3-color full-color LED SMD modules KY-009
- 1 x Infrared emission sensor module KY-005 
- 1 x 3-color LED module KY-016
- 1 x Mercury open optical module KY-017
- 1 x Yin Yi 2-color LED module 3MM KY-029
- 1 x Active buzzer module KY-012 
- 1 x Temperature sensor module KY-013
- 1 x Automatic flashing colorful LED module KY-034
- 1 x Mini magnetic reed modules KY-021
- 1 x Hall magnetic sensor module KY-003
- 1 x Infrared sensor receiver module KY-022
- 1 x Class Bihor magnetic sensor KY-035
- 1 x Magic light cup module KY-027
- 1 x Rotary encoder module KY-040
- 1 x Optical broken module KY-010
- 1 x Detect the heartbeat module KY-039
- 1 x Reed module KY-025
- 1 x Obstacle avoidance sensor module KY-032
- 1 x Hunt sensor module KY-033
- 1 x Microphone sound sensor module KY-038
- 1 x Laser sensor module KY-008
- 1 x 5V relay module KY-019
- 1 x Temperature sensor module KY-001
- 1 x Temperature sensor module KY-028
- 1 x Linear magnetic Hall sensors KY-024
- 1 x Flame sensor module KY-026
- 1 x Sensitive microphone sensor module KY-037
- 1 x Temperature and humidity sensor module KY-015
- 1 x XY-axis joystick module KY-023
- 1 x Metal touch sensor module KY-036
- 1 x Box


Geliştirmeye başlamak için dikkatimi çeken ülkemdeki alınabilir kitleri not almıştım. Aşağıda, özellikle robitshop inanılmaz yüksek fiyat çekmiş sanki ama gördüğüm kadarıyla fiyat konusunda dealextreme ile yarışabilecek durumda değiller.

243,08 TL (%36 daha pahali) robitshop'ta sanirim aynisi
* Arduino Uno R3
* Arduino and Breadboard Holder
* New and Improved SIK Manual
* Translucent Red Bread Board
* 74HC595 Shift Register
* 2N2222 Transistors
* 1N4148 Diodes
* DC Motor with wires
* Small Servo
* 5V Relay
* TMP36 Temp Sensor
* Flex sensor
* Softpot
* 6' USB Cable
* Jumper Wires
* Photocell
* Tri-color LED
* Red and Yellow LEDs
* 10K Trimpot
* Piezo Buzzer
* Big 12mm Buttons
* 330 and 10K Resistors
* Male Headers

Yukardaki kite benziyor farkları gördüğüm kadarıyla şunlar (olmayanlar için başa "-", fazladan olanlar için "+" koydum), aslında ucuz ve alınabilir gibi:
- 74HC595 Shift Register
- Small Servo
- 5V Relay
- Softpot
- Piezo Buzzer
- Male Headers
- Flex sensor
- New and Improved SIK Manual
- Arduino and Breadboard Holder
+ 16x2 LCD ekran (yeşil)
+ 7 Segment Display
+ AT24C02 EEPROM
+ 9V Pil Başlığı
+ 7" Mano Malzeme Kutusu

169,45 TL (%57 daha pahali) robitshop'ta sanirim eski modeli 
* Arduino UNO: En yeni Arduino USB kartı, eksiksiz olarak montajlı ve test edilmiş.
* 15 cm USB A’dan B’ye kablo
* Mini Breadboard
* Jumper Wires Premium 3'' M/M Pack of 10: Bunlar, dişi bağlantıları Arduino üzerinden bileşenlere ve breadboard’a bağlantı kurmanıza izin veren yüksek kalitedeki kablolardır.
* Fotosel: Çevredeki ışığı algılamaya yarayan sensör. Bir çekmecenin açılmasını ya da gece vaktinin geldiğini algılama işleri için uygun.
* Isıl Direnç: Çevre sıcaklığını ve sıcaklık değişimlerinin algılamaya yarayan sensör.
* Üç Renkli LED: Bu LED’i ihtiyaç duyduğunuz herhangi bir rengi PWM ile karıştırmak için kullanın.
* Temel LED'ler
* Linear Trimpot: Aynı zamanda değişken direnç olarak bilinmektedir, bu cihaz genel olarak ses kontrolü, kontrast için kullanılmaktadır ve genel kontrol girişi için iyi bir cihazdır.
* Buzzer: Harika, kafa patlatan sesler, alarmlar ve belki de müzik yapabilirsiniz!
* 12mm buton
* 330 Ohm Dirençler
* 10K Direnç
* Titreşim sensörü: Titreşimleri algılamanıza yarayan sensör.

Friday, September 28, 2012

Raspberry Pi ile ortam yürütücü

Bir süredir evde salondaki projector (720p) ile kullanmak için bir ortam yürütücü cihaz uydurasım vardı ama 1) çok para yatırmak istmiyordum 2) üzerinde linux koşan bir cihaz alayım da farklı işleri de üzerine yıkabileyim diye düşünüyordum.

Salonda film izlemek istediğimizde sürekli olarak içerden laptop'u getir, harici disk'i getir gibi uğraşlara girmek sıkıntı verici oluyor. Biraz da lüks ve böyle linuxlu minukslu oyuncak peşindeyim açıkçası.

Bir süre Dreambox alayım diye düşündüm, biraz araştırdım. Evde kablonet vardı ve DVB-C modülü olan bir Dreambox almam gerekiyordu ve türkiyede bulamadım ya da bulduklarım hep pahalıydı, yurtdışından da bu tür bir cihaz getirtme riskine girmedim.

Aylar sonra geçenlerde gaza gelip Raspberry PI sipariş ettim. Üzerine bir XBMC kurup HDMI çıkışından projectore de sabitleyebileceğim, raspberry'i de projector'ün masasının altına sabitleyip ortalıktan gizleyebileceğim. Üstelik üzerine torrent client ve benzeri uygulamalar da kurabilmek de güzel oalcak gibi.


Bir de evde arka odadaki bilgisayardaki disklerdeki filmeleri izlemek için o diski bir şekilde zeroconf, upnp ya da nfs gibi bir şeylerle wireless üzerinden raspberry'e taşımayı düşünüyorum.

Ama raspberry alınca bir grup daha malzemeye ihtiyacınız oluyor:
  • işletim sisteminin duracağı bir SD card
  • bir microusb kablo
  • ikiden fazla USB cihaz istiyorsanız, (fare, klavye, wireless kart) bir USB hub
  • harici disk gibi USB'den güç çeken bir cihaz bağlayacaksanız güç beslemesi dışardan olan (prize takılan) bir USB hub (raspberry USB'den sınırlı miktarda güç verebiliyor)
  • eğer klavye ve fare taşımak istemiyorsanız birer tane de kalvye ve fare gerek
  • ekrana bağlayabilmek için hdmi kablo ya da svideo kablosu
SD card alırken biraz araştırdım bu nanelerin farklı hızlarda olanları var ve hızlı olanlar daha pahalı, class 10 en hızlısı.

Bir de klavye ve fare için de bir uzaktan kumanda boyutunda ve üzerinde laptop dokunmatiği gibi fare alanı olan ikisi bir arada bir cihaz aldım, nasıl bir şey olduğunu sayfasının alt tarafındaki video'dan izleyebilirsiniz, bu nane eğlenceli bir şeye benziyor. Buyrun resmi de yanda.

Bunları sağlamak için para harcadığım parça listesi:
  1. 43$ (77.3TL) Raspberry Pi
  2. 31.99$ (57.54TL) Wireless Keyboard with TrackPad
  3. 11.90$ (21TL) 8GB SDHC SD Card (Class 10)
  4. 10.40$ (18.7TL) 7-Port USB 2.0 Hub with External Power Source
  5. 7.50$ (13.5TL) USB 2.0 802.11n/g/b Wireless Network Adapter
  6. 3.40$ (7TL) Gold Plated 1080i HDMI V1.3 M-M Connection Cable 
Toplam: 108$ (193TL)

Üzerinde linux çalışan (debian), hdmi çıkışı olan, klavye ve fareli uzakdan kumandalı, dışardan istediğim cihazı bağlayabileceğim, kablosuz baplantıya izin veren bir cihaz için oldukça iyi bir ücret bence.

Raspberry Pi dışındaki parçaları DealExtreme'den aldım (bizim 1 milyoncuların Çin versiyonu bu), siparişler 30 gün içerisinde üstelik kargo ücreti olmadan geliyor. Siparişinizin gümrüğe takılma ihtimali var ama siparişinizi 100$ altında tutarsanız muhtemelen takılmıyorlar (burada durum biraz Allah'lık). Daha önce deal extreme'den iki kez sipariş verdim ve ikisinde de aldığım ürünler bana ulaştı. Ama 30 gün çok üzün bir süre haberiniz olsun, aldığınız ürünler onları aldığınızı unuttuğunuz zman elinize ulaşıyor.

Raspberry Pi'ı da alabileceğiniz iki satıcı var zaten hangisinden aldığınız çok farketmiyor sanırım ama ben alırken teslim süresi için 13 hafta diyordu. Umarım çok beklemem.

Ben sipariş vereli daha sadece 2 hafta oldu, sanrım 1 ay içinde elimde olurlar. Aletleri alıp kurcaladıktan sonra sonuçları buraya yazarım.

Wednesday, August 01, 2012

REST API yazarken nelere dikkat etmeli


Bir süre önce şirkette kullandığımız bir uygulama için API yazmamız gerekince REST ile yapayım diyerekten bu konuda biraz araştırma yapıp notlar almıştım, paylaşsam birilerinin işine yarayabilir belki diyerek buraya da koyuyorum.

REST in maalesef yaygin kabul görmüş bir standartı yok. Ancak REST yapısı genellikle HTTP metodlarına dayandığı için ideal bir REST servisi dendiğinde HTTP protokolünü adam gibi uygulamış olması ve genel URL ilkelerine uyulması gibi genel bir beklenti var.

HTTP: http://www.ietf.org/rfc/rfc2616 (Hypertext Transfer Protocol -- HTTP/1.1)
URI in WWW: http://www.ietf.org/rfc/rfc1630 (A Unifying Syntax for the Expression of Names and Addresses of Objects on the Network as used in the World-Wide Web)

API Versiyonu

Versiyon bilgisine sunduğunuz API'de bir şekilde yer vermeniz özellikle önemli çünkü yazdığınız API kullanılmaya başlandığında artık onu değiştiremeyeceğinizi farkedeceksiniz.

API'nizin versiyonu Path'in içinde, "Query String" olarak ya da HTTP header olarak olabilir.

Path:
GET /v1/users/bekir HTTP/1.1
Query String:
GET /users/bekir?version=1 HTTP/1.1
Version Header:
GET /user/123 HTTP/1.1
Host: api.example.com
X-API-Version: 1
Accept: application/json
Accept Header:
GET /user/123 HTTP/1.1
Host: api.example.com
Accept: application/json-v1
İşin aslı URL'in tanımına bakınca bir kaynağın tek bir URL'i olması gerekli ve bu bağlamda path'e "/v1/" eklenmesi ilgili kaynağın bir kaç farklı URL'i olması gibi geçersiz görünen yöntem oluyor ancak burada teknik anlamda ideal olan yerine daha çok pratik yöntemi seçmek bana daha akıllıca geliyor.

Versiyon bilgisini Path'in bir parçası haline getirmek şu dertleri çözüyor:
  • Birden fazla versiyonu aynı anda yükleyebiliyor ve bir diğerini etkilemeden güncelleme/hata düzeltmeleri yapabiliyorsunuz,
  • Bir versiyon için yaptığınız yükleme işlemi diğer versiyonları etkilemiyor,
  • Sunucu'da farklı yapılandırmalar ile yönetebiliyorsunuz, hatta farklı sunucuya koymanız da kolay oluyor,
  • Farklı dizinlerde kurulu ve kendi path'lerinde çalışan farklı veriyonları aynı anda kullanırken hata ayıklamak çok daha kolay oluyor, genellikle loglarını da ayırmış oluyorsunuz zaten bu yöntemle.

Kimlik doğrulama

Her istekte kullanıcı adı ve parola göndermek çok mantıklı değil, bu yöntemi tercih etmeyin:
GET http://api.example.com/v1/songs?artist=michael&username=[apiuser]&pass=[apipass]
Eğer kodunuzu bu şekilde yazarsanız şu durumlar oluşabilir:
  • Özellikle GET metodu kullandığınızda URL icinde giden bu gibi istekler sunucularda öntanımlı olarak loglanırlar ve loglarda kullanıcı adı ve parolaları görmek çok takdir alan bir davranış değildir.
  • her istekte yetkilendirme bilgileri tekrar ve açık olarak gönderilir
Yukarıdaki yontem yerine en azından HTTP Basic Auth kullanabilirsiniz ama bu senaryoda da her istekle login bilgisini göndermeniz gerekiyor. Gene de bu yöntemi tercih edebilirsiniz.

Yukarıdaki yöntemleri kullanmak yerine en azından kullaniciniza bir token dönen ayrı bir istek olusturup, login bilgisinin POST ile buraya gönderilmesini sağlayın (genellikle /auth path'i kullanılıyor.)
POST https://api.example.com/v1/auth
Host: api.example.com
...
username=[apiuser]&pass=[apipass]
Geriye geçici bir süre geçerli olacak bir token dönebilirsiniz, istemci sonraki isteklerinde bu token'i kullanarak gelebilir (Query String ya da HTTP header ile alabilirsiniz Token'i), bu sayede loglara erisimi birisi kullanıcıya ait kritik bilgileri göremez ve oturumunu ontanımlı ayarları değiştirilmemiş bir sunucu üzerinden çalamaz. Ancak bu yöntem sizi bir çok kötü durumdan koruyamaz.

Halka açık bir API geliştiriyorsanız en uygun yöntem OpenID+OAuth gibi yöntemler kullanın. Kendizinkini keşfetmeye çalışmayın, çok zaman alır ve büyük hatalar yapabilirsiniz. Konu güvenlik olunca uzman değilseniz kendize güvenmemek daha güvenilir oluyor.

Kimlik doğrulama adımları için her zaman "https" kullanın, http isteklerini izlemek fazla kolay.
Daha çok çeşitli yöntemler de mevcut ancak şimdilik bu kadarı yeterli sanirim.

Belgeleme

Yardım sayfası
Belgeleriniz için dev.example.com, developer.example.com adreslerini tercih edebilirsiniz.
Yönlendirme
API'nizin kök adresine bir tarayıcıdan ile gelen GET istelerini API'nin belgelerinin olduğu yere yönlendirmeniz kullanacak insanlara çok yardım eder.
Test sayfası
İnsanlara servisinizi tarayıcıdan test edebilecekleri bir arayüz sunarsanız çok mutlu olurlar. (Ama bu durum servisinizde sadece GET ve POST yazarsanız mümkün olabilir, aşağıda PUT, DELETE ve PATCH gibi işlevleri de kullanmanız durumunda size yardımcı olabilecek bir çakallıktan ayrıca bahsettim.)
API'nizin yardım sayfalarında şunlara yer vermeniz gerek:
  • hangi kaynaklar (Path) bulunuyor
  • farklı kaynakların hangi özellikleri mevcut,
  • en önemlisi her olası istek için (Header'ları da içeren) örnek istek ve cevap
  • eğer API'nizin versiyonları varsa (ki bence her türlü olmalı) belgelerinizi de versiyonlarsanız güzel olur
  • farklı programlama dillerinde nasıl kullanılabileceğini anlatan örnekler koyarsanız daha güzel olur

Cevap(Dönüş) biçimleri

Servisinizin cevaplarını XML, HTML, JSON gibi formatlarda dönebilirsiniz. Bunları aynı anda desteklemeniz de mümkün ancak hangi durumda hangi tip cevap göndereceğinize karar vermeniz için bir kaç yöntem mevcut.
Uzantı kullanımı: İsteğinizi gönderirken şu formatta gönderebilirsiniz:
GET /v1/users.json?username=bekir

GET /v1/users/bekir.json
Query String Kullanımı:format gibi bir anahtar kelime ile:
GET /v1/users?format=json

"Accept" HTTP Header: İsteği yaparken istediğimiz cevap formatını isteğin başlığında iletebilirsiniz:
GET /v1/users?username=bekir
Host: api.example.com
Accept: application/json
...

HTTP/1.1 200 OK
Content-Type: application/json
Her üç durumda da döndüğünüz cevabın HTTP Header'ında "Content-Type" değerini göndermek gerekli. Bir yöntemin diğerlerine üstün olup olmadığı hakkında bir yorumum yok, ucunu birlikte kullanmanızda da bir sakınca yok.

Uzantı olarak yazmak insan olarak basta daha sıcak geliyor ancak bir içeriğin tek bir URL'i olması ilkesini çiğnediği için servisinizi REST olmaktan uzaklaştırıyor.

CRUD işlemleri

REST API'lerde genellikle bir liste ifade eden koleksiyonlar ve onların içinde yer alan ögeler bulunurlar. Bu öğeler üzerinde uygulanan işlemler genellikle CRUD olarak ifade edilir ve bunları gerçeklemek için uygun HTTP metodları tercih edilir.
  • create (yarat, POST)
  • read (oku/getir, GET)
  • update (güncelle, PUT/PATCH)
  • delete (sil, DELETE)
API'nizde PUT/PATH/DELETE gibi çağrılar kullanmak istemeyebilirsiniz, bunun nedenleri genellikle şunlardır:
  • API'nizin kullanıcıları GET ve POST dışındaki HTTP metodlarından haberdar olmayabilir
  • API'nizin tarayıcılar üzerinden de kolaylıkla çalışmasını ver test edilebilmesini isteyebilirsiniz
Eğer siz de benim gibi tarayıcılardan test edilebilen bir API istiyorsanız HTTP "method override" yönteminden faydalanabilir ya da REST uyumluluğunuzu biraz daha kırarak URL'lerinize eylemler ekleyebilirsiniz.

Method Override

PUT/POST/DELETE yerine POST kullanabilir ve Query string ile isteğinizin bu 3 tarayıcı dışı çağrı gibi yorumlanmasını sağlayabilirsiniz.

Bu yöntem normal çalışma yapınızı kırmaya zorlamadan tarayıcılar üzerinde de çalışan test sayfaları oluşturacaksanız işinize yarar ve istekleri ele alan katmanın önüne ekleyeceğiniz basit bir kod ile
POST /users/bekir?method=put

POST /users/bekir?method=delete
Ya da benzer şekilde HTTP header'larından faydalanabilirsiniz:
POST /users/bekir HTTP/1.1
Host: api.example.com
X-HTTP-Method-Override: DELETE
...

Eylemin path uzerinde verilmesi

CRUD işlemlerini path'e gömebilirsiniz, ancak REST uyumlu bir API geliştiriyorsanız bu yöntem hatalı kullanım olarak yorumlanır. GEnel pratik olarak URL'lerde eylemlere yer verilmemelidir.
create:
POST /users/bekir/create
update:
POST /users/bekir/update
delete:
POST /users/bekir/delete
Bu yöntemin en büyük olumsuz yönü yapıya hakim olmayan insanların yeni eylemler eklemeye çalışması. Yeni gelen bir kişi farkında bile olmadan yeni bir eylem ekleyiverir ve mevcut CRUD yapınız daha siz farkına biel varmadan kırılır:
POST /users/bekir/move

Koleksiyonlar ve Öğeler

Koleksiyonlar için çoğul isim tercih edin, bu sayede tek bir kayıt dönen bir URL olmadığı daha anlaşılır oluyor ve kullanan kişiye yardımcı oluyor.

create

Yeni öğe yaratmak için:
POST /v1/users/bekir

HTTP/1.1 201 Created
Yeni kolksiyon oluşturmak genellikle sık karşılaşılmayan bir durum ancak gene de gerekli ise öğe yaratıeken kullandiginiz yöntemleri izleyebilirsiniz.

read

Bir koleksiyon içindeki ögeleri sorgulamak için:
GET /v1/users
Ya da bir öğeyi edinmek için:
GET /v1/users/bekir
koleksiyon hakkında
Eger kullandığınız koleksiyona dair bilgileralmak isterseniz /info gibi bir path eklentisi kullanabilirsiniz:
GET /v1/users/info
koleksiyonlarda sayfalama
Çok fazla ya da sınırsız sayıda öğenin bulunduğu durumlar için sayfalama yapmak gerekebilir, bu durumda şöyle yapılar kullanabilirsiniz:
GET /v1/users?offset=200&count=100

GET /v1/users?page=2&count=100
koleksiyon içerisinde filtreleme/arama
koleksiyonlarda filtreleme/sorgulama yapmak isterseniz "Query String"lerden faydalanabilirsiniz:
GET /v1/users?uid=1053

GET /v1/users?lastname=doğan
sonuç içinde istenen alanlar
Eğer sorgu sonucunda bütün alanları değil de sadece belli alanları istiyorsanız fields gibi bir anahtar kelime ile bunu yapabilirsiniz:
GET /v1/users?fields=displayname,team,department

update

Koleksiyonlar üzerinde güncelleme konusuna girmiyorum. Ancak öğeler üzerinde güncelleme yapmak için:
PUT /v1/users/bekir
Kısmi güncellemeler: PUT metodu genellikle tüm öğeyi güncellemek için kullanılır ancak tüm öğeyi değil de sadece belirli alanlarını güncelleyeceksek PATCH metodunu kullanabiliriz:
PATCH /v1/users/bekir

delete

Koleksiyon silmek de pek sık karşılaşılmayan bir durum ancak gerekirse bir koleksiyonu silmek için:
DELETE /v1/user/bekir/playlists/benden+size
silme işlemi genellikle koleksiyon dahilindeki öğeler için uygulanıyor:
DELETE /v1/users/bekir

Hata Durumları

HTTP durum kodlarını doğru kullanın ( http://tr.wikipedia.org/wiki/HTTP_durum_kodlar%Ç4%B1 ), hata kodları bilgisayarlar içindir ve hata durumları için uygun durum kodları kullanmazsanız API kullanıcılarınızı metin ayrıştırmaya zorlarsınız.

Hata cevabınızda genel bir şablon belirleyin ve insanların anlayabileceği de bir mesaj alanınız daima olsun. Gelen istek ne olursa olsun hata durumunda belirlediğiniz şablona uyun.

HTTP durum kodunu hata şablonunuzun içine de fazladan eklemek genellikle mantıklı bir yöntem oluyor, API kulanıcılarınız hatayı ayrıştırırken daha rahat ederler.
GET /companies/acme/customers?token=1234 HTTP/1.1
Host: api.exampla.com
...

HTTP/1.1 403 Forbidden
Content-Length: ...
...

{"status": 403, "message": "You are not auhtorized to access this content."}
Not: Yazımda sıkça kullandığımız terimleri Türkçe'ye çevirmedim. Bu şekilde yarı türkçe yarı ingilizce bir yazı okumak rahatsız edici olabiliyor ancak bu şekilde yapmasaydım anlaşılırlıktan fazlaca taviz vermem gerekecekti.

Friday, May 11, 2012

IETT'nin sagladigi otobus konum bilgisi

Mobil cihazlar için 2 gencin geliştirdiği gayet güzel çalışan Nerde bu Otobüs adlı bir uygulama var, istanbulda otobüs bekleyen bir çok insanın en büyük yardımcısı, harita üzerinde otobüslerin konumlarını gösteriyor ve bu sayede beklediğim otobüsün bulunduğum durağa ne zaman otobüs geleceğini tahmin edebiliyorum. Aşağıdaki testleri ve denemeleri yapana kadar otobüs konum bilgilerinin sık sık güncellendiğini düşünüyordum, Nerde bu Otobüs uyglamasının internet'teki sss sayfasında da hat bilgilerinin 4 dakikada bir güncellendiği'ne dair bir ibare var. Uygulamanın sağladığı otobüs konumlarının güncellenip güncellenmediğini heniz tam test etmedim ama bu güncelleme sadece İETT'nin sağladığı verileri sorgulama sıklığı olabilir ki İETT zaten en sık yarım saatte bir kez güncelleme yapıyor gibi.

Verileri nereden alıyor bu amcalar, bunun daha düzgünü de yapılabilir diyerek kayınçoyla oturup biraz (2 saatten uzun sürdü hepsi) inceledik. önce http://mobil.iett.gov.tr/ sayfasındaki otobüsüm nerede bağlantısını farkettik, herhalde buralardan alıyorlar verileri diye düşündük. Ama ayrıştırması çok zor bir veri gibi görünüyordu.

Sonra asıl uygulamanın veriyi nasıl çektiğine bakalım dedik ve nasıl yapsak, nasıl yapsak diye düşünürken şöyle bir yöntem bulduk: Benim android telefonumu SSHTunnel ile bilgisayarım üzerinden proxy'ledik ve bilgisayarda wireshark ile trafiği izlerken "nerde bu otobüs"ü açtık hat listesi aldık, otobüs konumlarını aldık, şöyle bir gezindik. Uygulamanın arka tarafındaki servis düz HTTP olduğu için güzelce eriştiği bütün URL'leri alabildik.

Nerde bu Otobüs uygulamasının arka tarafı ASP ile yazılmış, zaten gelistiren cocuklar da Microsoft Student Partner'lar falan, benim tabirimle microsoft'çu çocuklar (maalesef M$ bu yetenekli gençleri daha okulları bitmeden kazanmış bile). Baktık uygulama verileri kendi sitelerinden http://nerdebuotobus.com/getLineBusses.aspx?line=19Z&points=1http://nerdebuotobus.com/getLineStopSchedules.aspx?line=19B&stop=A1871&output=json gibi URL'ler ile çekiyor.

Sonra bu verilerin iett'nin mobil sitesinde bulduğumuzdan çok daha düzgün yapıya sahip olduğu sonucuna varıp başladık fikir yürütmeye. Kendi çapında uygulama geliştiren iki gencin İETT ile anlaşması olamaz, demek ki bu verileri İETT açıktan bir yerlerden sağlıyor dedik. Nedense çok sonra İETT'nin sitesinden de otobüs konumlarının sorgulanabildiğini hatırlayıp bir baktık ki İETT harita sayfalarını gezerken bir yandan firebug açıp izleyince İETT'nin harita arayüzünde gösterdiği verileri zaten javascript/ajax ile xml olarak çektiğini ve Nerde bu Otobüs'çü gençlerin de dolaylı olarak bu XML'i döndüğünü anladık. Hat kodları, duraklar, otobüs konumları falan İETT baştan beri bize sunmuş zaten XML olarak. Nerde bu Otobüs için bunu json'a dönüştüren bir şey yazmışlar anlaşılan, çünkü gelen veri yapısı aynı idi.

İETT'nin XML'leri ortadaydı ve kolayca erişilebilirdi: http://harita.iett.gov.tr/XML/34otog.xml

Benzer şekilde hat kodları, otobüs saatleri ve diğer veriler de başından beri elimizde varmış, boşuna kasmışız Nerde bu Otobüs ile uğraşarak.

İstediğimiz verilere erişebildiğimizi anladıktan sonra bu verilerin ne kadar güvenilir olduğuna geldi sıra, önce iki otobüs hattı için (metrobüs olan 34 ve karşıya sık giden 112'yi seçtim) cron'a bir şey yazayım bir gün sonra bakayım ne sıklıkta güncelleniyor diye biraz izleyeyim diyordum ama dün farkettim ki iki haftadır o cron'ları unutmuşum. Bu sayede sık seferi olan iki otobüs hattı için iki haftalık güncelleme verisi toplamış oldum.

Geçtiğimiz 13 günde 112 ve 34 hatları için 10 dakikaya bir ilgili xml'leri şöyle topladım:

bekir@hede:~$ crontab -e

*/10 * * * * cd /free/iett; wget --header='Referer: http://harita.iett.gov.tr/' http://harita.iett.gov.tr/XML/112otog.xml
5,15,25,35,45,55 * * * * cd /free/iett; wget --header='Referer: http://harita.iett.gov.tr/' http://harita.iett.gov.tr/XML/34otog.xml

Toplanan dosyalar şu şekilde biriktiler:

bekir@hede:/free/iett$ ls -lrt
toplam 54328
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.9
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.8
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.7
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.6
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.5
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.4
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.3
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.2
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.15
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.14
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.13
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.12
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.11
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.10
-rw-r--r-- 1 bekir bekir   886 Nis 29 02:15 112otog.xml.1
...
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1662
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1661
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1660
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1659
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1658
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1657
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1656
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1655
-rw-r--r-- 1 bekir bekir   673 May 11 02:19 112otog.xml.1654
-rw-r--r-- 1 bekir bekir  1303 May 11 05:41 112otog.xml.1681
-rw-r--r-- 1 bekir bekir  1303 May 11 05:41 112otog.xml.1680
-rw-r--r-- 1 bekir bekir  1303 May 11 05:41 112otog.xml.1679
-rw-r--r-- 1 bekir bekir  1303 May 11 05:41 112otog.xml.1678
-rw-r--r-- 1 bekir bekir  1303 May 11 05:41 112otog.xml.1677
-rw-r--r-- 1 bekir bekir  1303 May 11 05:41 112otog.xml.1676
-rw-r--r-- 1 bekir bekir  1303 May 11 05:41 112otog.xml.1675
-rw-r--r-- 1 bekir bekir 16710 May 11 06:36 34otog.xml.1673
-rw-r--r-- 1 bekir bekir 16710 May 11 06:36 34otog.xml.1672
-rw-r--r-- 1 bekir bekir 16710 May 11 06:36 34otog.xml.1671
bekir@hede:/free/iett$ 


Sonra bu verileri inceleme faslına gelince farkettim ki 10 dakikaya bir durmadan aynı dosyaları almışım, örneğin yukarıda ilk 15 kadar istek sürekli aynı veriyi almış. Bunun anlamı o dosyanın 15*10=150 dakikadır güncellenmediği. Sonra ben de otobüs konumlarını içeren bu XML'lerin ne sıklıkta güncellendiğine bakmak için şunları yaptım, aşağıdaki çıktılar 34 ve 112 hatları için hangi saatte kaç GPS güncellemesi geldiğini gösteriyor.

bekir@hede:/free/iett$ ls 112* | wc -l
1682
bekir@hede:/free/iett$ ls -lrt 112* | cut -d. -f1,2 | sort -u  | awk '{print $8" "$9}' | cut -d: -f1 | sort |uniq -c | sort -n | awk '{print $2, $1/13}' | sort 
00 1.53846
01 1.46154
02 0.230769
05 0.384615
06 0.230769
07 1.07692
08 0.769231
09 1.38462
10 1.84615
11 2.07692
12 1.69231
13 1.23077
14 1.92308
15 2.15385
16 1.84615
17 2.07692
18 1.61538
19 2
2011 0.0769231
20 2
21 1.69231
22 2.23077
23 2

bekir@hede:/free/iett$ ls 34* | wc -l
1674
bekir@hede:/free/iett$ ls -lrt 34* | cut -d. -f1,2 | sort -u  | awk '{print $8" "$9}' | cut -d: -f1 | sort |uniq -c | sort -n | awk '{print $2, $1/13}' | sort 
00 3.92308
01 2.69231
02 1.07692
05 0.692308
06 0.615385
07 1.15385
08 2.23077
09 3.69231
10 3.53846
11 3.53846
12 3.30769
13 3.84615
14 3.53846
15 2.84615
16 3.69231
17 3.46154
18 2.92308
19 3.61538
20 3.23077
21 3.15385
22 3.92308
23 4.30769
bekir@hede:/free/iett$ 

Otobüs konum verileri en yoğun saatlerde ancak 2-3 kez güncelleniyor, gece de 02:00-05:00 arasında servisi de kapatıyorlar gibi, yani her şey yalanmış. İnanmadım bir de IETT'nin harita sayfasında da denedim, maalesef sonuçlar doğru çıktı. Öyle otobüs beklerken falan otobüs konumlarına bakmak çok anlamsızmış.

Bu arada yukarıda bahsettiğim "otobüsüm nerede" bağlantısı sık sık güncelleniyor gibi, doğruluğunu test etmedim ama belki oradaki veri gerçekten daha sık güncelleniyordur.

Saturday, March 17, 2012

bilgisayar bolumlerindekiler, okul bitmeden bir seyler yapin

Gecen ay icinde sirkette bir toplanti yapip kariyer gunlerine katilalim ama gittigimiz kariyer gunlerinde neler sunacagiz diye konusuytorduk. toplantida genellikle proje gelistirme sureclerimize, belli araclarin nasil etkili kullanilabilecegine ya da kod yazma teknik/metodolojilerine dair fikirler ortaya cikti. Bende kariyer gunlerindeki ogrencilerin zaten daha bu konularda fikirleri bile olmadigini daha ogrencilerin islerine yarayacak seyler bulmamiz gerektigini soylemistim.

Toplantida ornek olarak insanlarin bu gunlere nasil geldiklerini anlatalim demistim, cevremde genellikle basarili ve yaptigi is konusunda hevesli insanlarin baslangic noktalari merak ve kollari sivayip bir ucundan kendileri baslamis olmalari idi, ilk kayda deger bir seyler ogrenmeye/yapmaya basladiklarinda onlara yol gosteren okul ya da is degildi. Ogrencileri de bu sekilde okullari bitmeden bir seyler yapmaya tesvik etmek gerektigini soylemeye calismistim. sonra ne oldu bilmiyorum birden kendimi Yeditepe Univ. Kariyer Gunlerinde "Mahalle bakkalindan e-ticaret portalina" adli bir sunum yapacakken buldum.

Sunum icerigi hakkinda bir kac arkadasimla ve ozellikle de samet ve nesli ile konustuktan sonra 
sunum biraz basligi ile alakasiz olsa da icerigini hazirladim. Sunumu Freemind uzerinde hazirladim ve sundum. Internet uzerinde de suradan freemind indirmeden de bakabilirsiniz.

Sunuma gelen ogrenciler genellikle 2,3,4. sinif bilgisayar muh. ve yonetim bilisim sistemleri ogrencileri idi, donem ortasinda oldugumuzdan 4. siniflar da dahil bir cogunun kafasinda mezun olunca neler yapacagina dair sorular henuz belirlemisti.

Sunuma once kendi hikayemi anlatarak basladim, ben ve arkadaslarim okul bitince neler yasadik, nasil islere girdik, bosluga dusme surecini anlattim. Sunum boyunca da cocuklarin kafalarina "okulunuz bitirmeden kayda deger bir seyler yapin, sirket kuracaksaniz simdi kurun, fikriniz varsa harekete gecin, okul icin gerekmese de staj yapin" diye vurdum durdum. ilginc bir sekilde "kendi sirketini kurmak isteyen var mi?" soruma koca salondan sadece 2 parmak kalkti, bana ilginc gelmisti ama simdi anlayabiliyorum ki kendi isini kurmak isteyenlerin is kurma fikri genellikle bir yerlere girip bir sure calistiktan sonra olusuyor. Buyuk cogunluk da o saatten sonra harekete gecemiyor bir turlu.

Thursday, March 08, 2012

cloud yapiya neden gecmedik

Gecen gun Roy ile birlikte CLOCODILE calistayinda bir konusma yaptik, konusmada neden cloud'a gecmemek gerekebilir diye aldigim bir kisim not asagida (notlar ingilizce oldugu icin kusura bakmayin sunum ingilizceydi e turkceye cevireyim dersem bloga asla koymayacagimi farkettim, ingilizce de olsa koyuyorum)

haa bu arada asla gecmeyecegiz diye bir planimiz da yok, openstack gibi projeleri denemek icin laboratuar kurma girisimindeyiz.

Why not to migrate to cloud:

pay less:
* cloud is expensive if you dont use its cloud features:
** no purchase needed for machines and side-products and less expense for buyers or other needed stuff
** less sysadmin
** scales automatically if needed
** automatic deployment
** less idle machines of our own (special days)

migration:
* migration of existing systems could need extensive effort.
* every saas should comes with many advanced features and takes some from
you, (user auth. mechanism)

procedure/experience changes:
* if you already have your own system high optimised, why do you need to change it, it is expensive to migrate
* if you have mature policies about your system management and you have sufficient personnel it could be preferred to stay out of cloud
* if you already have extensive experiencesolutions about existing problems, cloud comes with everything new to resolve

Others
* every problem in your provider, affects you (google ip addresses blocked)
* If you are doing boutique bussiness, every customer have different needs so they want their special cloud like thing, cloud is not that small
* contracts with old customers prevent you to swith to cloud

Monday, June 07, 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.

Saturday, May 22, 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 diski 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/hosts'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:~$

Monday, July 27, 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

Sunday, June 07, 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.

Tuesday, June 02, 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.