Python cho người Việt

Python cho người Việt

Entries tagged “fcgi”

Lập trình web với Python (6)

written by Nguyễn Thành Nam, on Jul 1, 2011 5:05:00 PM.

Phần trước chúng ta đã xem xét mô hình hoạt động của một ứng dụng FCGI. Trong phần này chúng ta sẽ viết thử một chương trình FCGI như đã đề cập.

Trước tiên, chúng ta sẽ cần cài đặt thư viện flup của tác giả Allan Saddi. Làm việc này khá đơn giản, chúng ta chỉ việc tải tập tin ez_setup.py từ địa chỉ http://peak.telecommunity.com/dist/ez_setup.py về một nơi nào đó trên máy, ví dụ như C:\Python26\Scripts. Sau đó chúng ta sẽ gọi lệnh ở màn hình DOS như sau:

C:\>c:\Python26\scripts\ez_setup.py flup

Gói flup sẽ được cài đặt trong C:\Python26\lib\site-packages.

Ở bước 2, chúng ta sẽ tải về tập tin http://www.fastcgi.com/dist/mod_fastcgi-2.4.6-AP22.dll, đổi tên nó thành mod_fastcgi.dll và đặt nó trong C:\Program Files\Apache Software Foundation\Apache2.2\modules.

Kế tiếp bước 3, chúng ta sẽ cần cấu hình Apache thành một FCGI client. Chúng ta cần sửa tập tin httpd.conf để thêm vào các dòng sau ở dưới cùng:

LoadModule fastcgi_module modules/mod_fastcgi.dll
Alias "/fcgi-bin/hello.py" "C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin/hello.py"
<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin/">
    Order allow,deny
    Allow from all
</Directory>
FastCgiExternalServer "C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin/hello.py" -host localhost:8888

Dòng LoadModule bảo Apache nạp mô-đun mod_fastcgi mà chúng ta vừa làm ở bước 2. Dòng Alias cho Apache biết rằng mọi yêu cầu đến đường dẫn (URI) /fcgi-bin/hello.py thật chất là đến tập tin C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin/hello.py. Chúng ta cần dòng này bởi vì hello.py sẽ được tạo ở ngoài DocumentRoot. Cũng chính vì thư mục fcgi-bin không nằm trong DocumentRoot nên chúng ta cũng cần lệnh Directory để cho phép Apache phục những yêu cầu truy cập vào thư mục đó. Và cuối cùng lệnh FastCgiExternalServer bảo Apache rằng tập tin hello.py thật chất là một ứng dụng FCGI đã được chạy sẵn tại địa chỉ localhost ở cổng 8888. Chính câu lệnh này sẽ chuyển Apache thành một FCGI client, chuyển tiếp yêu cầu từ trình duyệt đến FCGI server do chúng ta phát triển. Vì chúng ta đang cài đặt trên Windows nên chúng ta chỉ có một lựa chọn là sử dụng FCGI theo chế độ trao đổi qua socket, do đó chúng ta phải dùng FastCgiExternalServer.

Bước 4 là tạo tập tin hello.py trong thư mục C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin. Nếu chưa có thư mục này, bạn đọc hãy tự tạo ra nó. Tập tin hello.py sẽ có nội dung như sau:

#!C:\Python26\python.exe
from flup.server import fcgi

count = 0

class HelloApp(fcgi.WSGIServer):

	def handler(self, req):
		global count
		count += 1
		req.stdout.write('Content-Type: text/plain\n')
		req.stdout.write('\n')
		req.stdout.write('Hello World %d' % count)

if __name__ == "__main__":
	HelloApp(application=None, bindAddress=("localhost", 8888)).run()

Trước hết, chúng ta nhập mô-đun flup.server.fcgi. Kế tiếp chúng ta khai báo một biến đếm tên count với giá trị khởi tạo là 0. Sau đó chúng ta khai báo ứng dụng của chúng ta bằng cách định nghĩa lớp HelloApp kế thừa lớp WSGIServer trong mô-đun flup.server.fcgi. HelloApp sẽ định nghĩa lại hàm handler để xử lý các yêu cầu nhận được.

Hàm handler nhận vào một tham số đó là đối tượng req chứa thông tin về các biến môi trường, các dòng dữ liệu chuẩn như stdin, stdout. Chúng ta sẽ cộng một vào biến đếm toàn cục, và xuất giá trị này ra lại cho trình duyệt. Như một ứng dụng CGI (FCGI) thông thường, trước hết chúng ta cần phải xác định kiểu dữ liệu trả về thông qua Content-Type, theo sau bởi một dòng trống đánh dấu sự chấm dứt các đầu đề (header) và bắt đầu của nội dung, và cuối cùng là nội dung.

Hai dòng lệnh cuối chỉ đơn giản là chạy ứng dụng FCGI này ở địa chỉ localhost và cổng 8888.

Để kiểm tra, chúng ta sẽ cần thực hiện ba việc: chạy ứng dụng hello.py, chạy Apache, và dùng trình duyệt xem trang http://localhost/fcgi-bin/hello.py**. Để chạy ứng dụng hello.py chúng ta chỉ cần nhập lệnh sau ở màn hình DOS:

c:\Program Files\Apache Software Foundation\Apache2.2\fcgi-bin>python hello.py

Khi dùng trình duyệt vào xem trang web như trên thì chúng ta sẽ nhận được hình sau:

hello1.png

Nếu làm tươi trình duyệt thì chúng ta sẽ thấy giá trị đếm tăng lên:

hello2.png

Như vậy chứng tỏ rằng các yêu cầu đều được phục vụ bởi một tiến trình duy nhất. Đây chính là lợi điểm của FCGI so với CGI.

Trong bài sau, chúng ta sẽ xem xét cách phát triển ứng dụng web với WSGI.

Lập trình web với Python (5)

written by Nguyễn Thành Nam, on Mar 24, 2011 5:39:00 PM.

Bẵng một thời gian, chúng ta lại quay lại với loạt bài Lập trình web với Python. Trong kỳ này, chúng ta sẽ bàn đến mô hình FastCGI (FCGI).

Cái tên FCGI khiến người ta liên tưởng đến mô hình CGI như đã trình bày trong kỳ trước. Nhưng, thật tế là FCGI là một mô hình rất khác so với CGI.

Các ứng dụng FCGI là các ứng dụng bền, tức là một tiến trình FCGI có thể phục vụ nhiều yêu cầu chứ không phải chỉ một yêu cầu như ứng dụng CGI. Do đó, các ứng dụng FCGI có thể sử dụng các biến có phạm vi ứng dụng (application-scoped variable, tương đương với các biến toàn cục, global variable), tồn tại qua nhiều yêu cầu.

Xét ví dụ một chương trình web hiển thị số lần truy cập vào trang.

  • Với mô hình CGI, khi có yêu cầu gửi đến, máy chủ web (web server, httpd) sẽ tạo một tiến trình khác, chạy chương trình CGI, chương trình này khởi tạo biến đếm với giá trị 0, tăng nó lên 1, và hiển thị số 1 rồi tiến trình kết thúc. Khi có yêu cầu thứ hai đến, máy chủ lại tạo một tiến trình khác, chạy chương trình CGI, chương trình này khởi tạo biến đếm với giá trị 0, tăng nó lên 1, và hiển thị số 1, và kết thúc tiến trình. Như vậy, vì mỗi yêu cầu được một tiến trình riêng phục vụ nên chúng ta sẽ cần phải lưu biến đếm vào một tài nguyên ngoài (ví dụ như tập tin, hoặc cơ sở dữ liệu), và các tiến trình truy cập vào cùng tài nguyên này.
  • Với mô hình FCGI, một tiến trình FCGI sẽ được chạy trước. Chương trình này được gọi là một FCGI server. Chương trình này khởi tạo biến đếm với giá trị 0 và bước vào một vòng lập vô tận để nhận yêu cầu. Trình duyệt gửi yêu cầu đến máy chủ web. Khi này máy chủ web sẽ chuyển yêu cầu này đến ứng dụng FCGI đã được chạy trước đó. Như vậy, máy chủ web đóng vai trò là một FCGI client. Ở phía FCGI server, yêu cầu được chấp nhận (accept), biến đếm được tăng lên thành 1, kết quả trả về lại cho httpd, và FCGI server quay lại vòng lập nhận yêu cầu. Máy chủ web trả lại kết quả cho trình duyệt. Khi có yêu cầu kế tiếp, máy chủ httpd lại chuyển yêu cầu đó cho cùng FCGI server. Yêu cầu này được chấp nhận, biến đếm được tăng thành 2 vì đang trong cùng một tiến trình, kết quả trả về lại cho httpd và tiếp tục như đã bàn.

Vì mô hình hoạt động của FCGI khác với CGI nên việc trao đổi giữa FCGI client và FCGI server (giữa httpd và ứng dụng FCGI) không thể sử dụng cùng một giao thức đơn giản như ứng dụng CGI nữa. Việc này đòi hỏi một giao thức riêng cho FCGI.

Mô hình hoạt động đơn giản của FCGI được miêu tả trong hình dưới.

/static/web-programming/fcgi/overview_lifecycle.png

Ngoài lợi ích về tốc độ (do không phải tạo tiến trình mới để phục vụ mỗi yêu cầu, và khả năng chia sẻ tài nguyên thông qua biến có phạm vi ứng dụng), các ứng dụng FCGI còn có thể được triển khai trên hệ thống khác với hệ thống máy chủ web, giúp cho việc phân bổ tài nguyên giữa httpd và FCGI server được hiệu quả hơn. FCGI hỗ trợ hai cách giao tiếp là thông qua stream pipe, và thông qua socket. Cách giao tiếp stream pipe tương tự như việc gửi và nhận dữ liệu qua stdin, và stdout. Cách giao tiếp này được sử dụng cho các ứng dụng FCGI triển khai trên cùng hệ thống với httpd. Cách giao tiếp socket sử dụng một kết nối TCP để đóng gói và gửi dữ liệu của env-vars, stdin, stdout, và stderr tới ứng dụng FCGI. Điều này cho phép ứng dụng FCGI được triển khai trên một hệ thống khác, và httpd sẽ liên lạc với ứng dụng này dựa vào kết nối mạng TCP. Do đó, việc tối ưu tài nguyên hệ thống có thể được thực hiện dễ dàng hơn so với ứng dụng CGI. Đối với ứng dụng FCGI, FCGI server có thể được chạy trong chế độ đa tiến trình, hoặc đa tiểu trình đều được. FCGI server có thể được chạy trên một máy 8 lõi, trong khi httpd chạy trên một máy khác đơn nhân. FCGI server phục vụ các dữ liệu động, trong khi httpd phục vụ các dữ liệu tĩnh như hình ảnh, trang web tĩnh.

Chúng ta vừa xem qua mô hình hoạt động của FCGI. Đi sâu hơn vào cấu trúc từng ứng dụng FCGI thì dúng ta có ba phần chính sau:

  • Mã khởi tạo
  • Vòng lặp nhận yêu cầu
  • Xử lý yêu cầu và trả kết quả

Trong ví dụ về ứng dụng hiển thị số lượt truy cập, mã khởi tạo là việc khởi tạo biến đếm toàn cụ với giá trị 0.

Vòng lặp nhận yêu cầu thường là một vòng lặp vô hạn, tương tự như:

while True:
    fcgi_accept()
    # xử lý yêu cầu như CGI

Trong khi yêu cầu được chấp nhận, thì dữ liệu nhập cũng được tách ra thành env-vars, stdin, stdout, và stderr. Điều này khiến cho việc xử lý yêu cầu của một ứng dụng FCGI không khác bao nhiêu so với việc xử lý của một ứng dụng CGI. Tất cả đều được thực hiện trên các biến môi trường, và các luồng chuẩn. Điều khác biệt đó là sau khi xử lý xong yêu cầu thì ứng dụng FCGI lại quay lại vòng lặp nhận yêu cầu mà không chấm dứt tiến trình như một ứng dụng CGI.

Vì không phải chấm dứt tiến trình sau mỗi yêu cầu nên các tiến trình FCGI có thể được “sử dụng lại”. Một ứng dụng FCGI có thể được khởi tạo trước, với 10 tiến trình chẳng hạn, và đặt trong một bể (pool) tiến trình sẵn sàng. Khi có yêu cầu đến, thì máy chủ web có thể ngay lập tức lấy ra một tiến trình từ bể này, và gửi thông tin đến nó. Khi kết thúc xử lý yêu cầu, máy chủ web lại đưa tiến trình này vào bể. Việc khởi tạo trước tiết kiệm được thời gian khởi tạo ban đầu, nhưng sẽ chiếm bộ nhớ, ngay cả khi chưa có yêu cầu nào được nhận.

Sau đây là mô hình chi tiết của một ứng dụng FCGI.

/static/web-programming/fcgi/detailed_lifecycle.png

Hẹn gặp các bạn vào bài tới. Chúng ta sẽ viết thử một ứng dụng FCGI đơn giản với mô-đun fcgi của Allan Saddi.