Falcon, backend ve mikroservis geliştirmeyi kolaylaştıran ve yüksek hız sağlayan bir Python frameworkü. Aynı donanım üzerinde daha fazla istekle baş edebileceği konusunda iddialı gözüken bir yapıda. Falcon aynı zamanda PyPy destekliyor ve bu özelliği onu daha da hızlı çalışabilir hale getiriyor. Falcon ile API yazmaksa gerçekten çok kolay. Aslında, bir API’ı yazmak ve Gunicorn veya herhangi bir WSGI sunucusuyla yayına almak için birkaç dakika bile yeterli olabiliyor. Bu yazıda, Falcon ile örnek bir API yazmaya çalışıp, sonra da ona istek göndereceğiz. Falcon’un hızını görmek için de nasıl benchmark çalıştırabileceğimize bakacağız. Benim bilgisayarımda benchmark çalıştırdığımda aldığım sonuçları yazının bir sonraki kısmında bulabilirsiniz.
Code coverage konusunda %100 oranını sağlamak ve sürdürmek Falcon’un temel kriterlerinden/amaçlarından biri. Ayrıca 3. parti kütüphane gereksinimlerini de yaygın kullanılan iki tane ile kısıtlamayı başarmışlar: six ve mimeparse.
Falcon’un GitHub sayfası‘na göre, bugün dünya üzerinde aralarında RackSpace, LinkedIn, OpenStack’in de bulunduğu birçok firma Falcon kullanıyor.
Falcon’un Benchmarkı
Test yapacağınız makinede Docker yüklüyse, beenchmark işlemi kolay bir şekilde yürütülebiliyor. Falcon’un GitHub üzerinde yer alan reposu docker isimli bir dizin içeriyor. Bu dizin içerisinde Dockerfile ve benchmark için kullanılacak kod yer alıyor. Çalıştırmak için gereken tek şey Docker kurulu bir bilgisayar. Bu arada, git reposuna buradan erişebilirsiniz. Benchmarkı nasıl çalıştırabileceğimize bakmadan önce, benim bilgisayarımda elde ettiğim sonuçları paylaşıyorum:
Sistem Özellikleri
- MacBook Pro 15″ / 16GB Ram / 2.9GHz Intel Core i7
- MacOS High Sierra
- Docker for Mac / Docker 17.12.0-ce (testi yaptığım dönemdeki güncel sürüm idi)
- Docker has these resources: 4 CPUs and 2 GB RAM
- Batarya gücü (prize takılı değildi)
Sonuçlar
Testler çalışırken elde edilen çıktıları, sadece sonucu içerecek şekilde kırptım.
Python 2.7.14:
Results:
1. falcon...............89596 req/sec or 11.16 μs/req (20x)
2. falcon-ext...........49007 req/sec or 20.41 μs/req (11x)
3. bottle...............40304 req/sec or 24.81 μs/req (9x)
4. werkzeug.............11977 req/sec or 83.49 μs/req (3x)
5. flask.................6509 req/sec or 153.63 μs/req (1x)
6. django................4592 req/sec or 217.75 μs/req (1x)
Python 2.7.14-Cython:
Results:
1. falcon..............119792 req/sec or 8.35 μs/req (26x)
2. falcon-ext...........71676 req/sec or 13.95 μs/req (15x)
3. bottle...............41571 req/sec or 24.06 μs/req (9x)
4. werkzeug.............12049 req/sec or 83.00 μs/req (3x)
5. flask.................6765 req/sec or 147.82 μs/req (1x)
6. django................4662 req/sec or 214.51 μs/req (1x)
Ve PyPy2! Sonuçlar çok güzel gözüküyor. (Ve evet, bir isteği sadece 0.94 mikrosaniyede cevaplamış)
Results:
1. falcon..............1060109 req/sec or 0.94 μs/req (35x)
2. falcon-ext..........560842 req/sec or 1.78 μs/req (18x)
3. bottle..............516203 req/sec or 1.94 μs/req (17x)
4. werkzeug............178523 req/sec or 5.60 μs/req (6x)
5. flask................31423 req/sec or 31.82 μs/req (1x)
6. django...............30594 req/sec or 32.69 μs/req (1x)
Yazının ortasında uzun uzun test sonucu paylaşmayı çoğu zaman sevmedeem se, Python 3.6.4 ile çalıştığında ? elde ettiğim çıktıları da paylaşmak istedim:
Results:
1. falcon...............67860 req/sec or 14.74 μs/req (16x)
2. falcon-ext...........37718 req/sec or 26.51 μs/req (9x)
3. bottle...............35572 req/sec or 28.11 μs/req (9x)
4. werkzeug.............13437 req/sec or 74.42 μs/req (3x)
5. flask.................7143 req/sec or 139.99 μs/req (2x)
6. django................4117 req/sec or 242.91 μs/req (1x)
Kendi Bilgisayarınızda Benchmark Çalıştırmak
Falcon’un benchmarkını kendi bilgisayarınızda çalıştırmak isterseniz, Docker kurulu bir sistemde şu aşamaları takip etmeniz yeterli:
$ git clone https://github.com/falconry/falcon.git
$ cd falcon/docker
Bu dizinde aralarında PyPy, Python{2,3} vee Cython seçeneklerinin olduğu bazı Dockerfile’lar göreceksiniz. Ayrıca, bu Dockerfile’ları kullanarak tüm imajları üreten bir Makefile burda yer alan dosyalardan. Bir de, Docker imajlarının içine kopyalanıp container içerisinde benchmarkları çalıştıran benchmark.sh dosyasını incelemek isteyebilirsiniz.
Testleri çalıştırabilmek için, öncelikle imajları üretmemiz gerekiyor. Bunun için make komutunu çalıştırmalıyız:
$ make
Bağlantınıza ve donanımınıza göre bu işlemin tamamlanması bir miktar zaman alabilir. Build işlemi yamamlandığında, testleri çalıştırmak için aşağıdaki komutları kullanabilirsiniz. Komutların her biri hangi testi çalıştırdığını az çok açıkladığı için daha fazla detay vermeye gerek duymadım:
$ docker run -it falconry/falcon-bench:py27
$ docker run -it falconry/falcon-bench:py27-cython
$ docker run -it falconry/falcon-bench:py36
$ docker run -it falconry/falcon-bench:py36-cython
$ docker run -it falconry/falcon-bench:pypy2
$ docker run -it falconry/falcon-bench:pypy3
Bu bilgilerin ikna edici olduğunu düşünerek, Falcon kullanarak örnek bir API yazalım.
Falcon ile İlk API
Falcon’un web sitesinde anasayfada basit bir API örneği yer alıyor. Bu yazıda, “Konteynerler ve Docker” kitabını yazarken hazırladığım farklı bir örneğe bakacağız. Bu API, 0 ile 100 arasında rastgele tamsayılar üretiyor ve elde ettiği sayısı JSON olarak döndürüyor. Alt ve üst sınır sırayla 0 ve 100 olarak alınıyor(kapalı aralık). Projeye GitHub üzerinden ulaşabilirsiniz. Lisansını GPL-3.0 olarak belirledim. Kod şu şekilde:
import falcon
import random
import os
import time
waitTime = int(os.environ.get('WAIT_TIME', '2'))
class RandomGenerator(object):
def on_get(self, request, response):
time.sleep(waitTime)
number = random.randint(0, 100)
result = {'lowerLimit': 0, 'higherLimit': 100, 'number': number}
response.media = result
api = falcon.API()
api.add_route('/number', RandomGenerator())
Kod ayrıca sayıları üretirken arada 2 saniye bekliyor. Bu sürenin eklenmesi, yavaş çalışan bir uygulamayı göstermek içindi. Test ederken bu gecikmeyi değiştirebilir veya kaldırabilirsiniz. Bunu generateRandom.py ismiyle kaydedin ve pip kullanarak falcon ile gunicorn kurulumunu tamamlayın:
$ pip install falcon gunicorn
Artık ilk API’ımızı test etmeye hazırız:
$ gunicorn -b 0.0.0.0:8000 generateRandom:api
Bu komut bir Gunicorn sunucusu çalıştırıyor ve 8000 portundan dış dünyaya açıyor. Sonrasında test etmek için cURL ile komut satırından ilerleyebilir veya tarayıcınızı kullanabilirsiniz:
$ curl localhost:8000/number
{"higherLimit": 100, "number": 54, "lowerLimit": 0}
Docker kullanmak ve uygulamayı paketlemek isterseniz, örnek bir Dockerfile olarak şunu verebiliriz:
FROM alpine:latest
RUN apk add --no-cache python2 py2-pip
RUN pip install falcon gunicorn
COPY generateRandom.py /code/generateRandom.py
WORKDIR /code
CMD gunicorn -b 0.0.0.0:80 generateRandom:api
6 satırlık bir Dockerfile’ı yazdıktan sonra imaj oluşturmaya başlayabiliriz. İmajın ismini falcon-example olarak verirsek:
$ docker build -t falcon-example .
İmajı oluşturduktan sonra, artık çalıştırıp test edebiliriz:
$ docker run -it -p 80:80 falcon-example
Sonuç
Bu yazıda Falcon’un ne olduğunu, sağladığı hızı, Falcon kullanılarak yazılan bir API’ı ve Gunicorn ile bir Falcon uygulamasını yayına alacak Dockerfile örneğini gördük. Falcon kendi sınıfında iddialı, basit ve sade bir framework. Bunun birçok mikroservis backendini ve API’ı hazırlarken güzel bir seçim olacağını düşünüyorum.