nginx and django

nginx (Engine X ) 是比 Apache 小巧快速的網頁伺服器,設定上相對沒有那麼強大與複雜。

Apache 是採用行程池運作比較消耗資源,而 nginx 則是 event based,不會依照 request 生成 process or thread。

下載網址:http://nginx.org/en/download.html

只是操作起來比較不熟悉,跟 apache 用 service 的方式比較不同,所以比較不親和一點…但是相對來說設定的細節都比較容易

設定檔在 /etc/nginx.conf

nginx 當初是為了 reverse porxy 所設計的,所以在 r-proxy 上理當應該比 apache 為更適當的選擇[1]


$ nginx # 啟動

$ nginx -t # 檢查設定檔格式是否正確

$ nginx -s [stop|reload|...] # 送訊號給正在執行的 nginx

可以用 fastcgi 搭配 django 運作,

可以額外 include 一個 django 的設定檔,內容如下:

server {
        listen  80;
        server_name server.com;
        location / {
            fastcgi_pass unix:/home/www/server.sock;
#           fastcgi_pass 127.0.0.1:8000;
            include     fastcgi.conf;
            access_log  /var/log/nginx_django.log;
        }
}

然後用 django 內建的 server 跑 fastcgi 模式,就能讓 django 跟 nginx 接起來囉。

$ kill `cat /home/www/server.pid`
$ python ./manage.py runfcgi method=threaded \
          socket=/home/www/server.sock pidfile=/home/www/server.pid

這邊指定用 thread 的方式跑,然後把 socket 建在該檔案位置,用在重開的時候要用,這個 socket 位置對應到上面的 nginx 設定的 socket 位置,
也可以跑在某個 port 上面去對應,只是用檔案的方式好像比較安全?!..我也不太懂=_=
另外 django 內的 fastcgi.conf 內要注意一點:

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

<strong>fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;</strong>
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

<strong>fastcgi_param  PATH_INFO          $fastcgi_script_name;</strong>

粗體的設定是 django url 在 route 會用來判斷的變數要設定對。
然後在專案內的 setting.py 的裡面加上 FORCE_SCRIPT_NAME=”/”
原因跟上面 route 路由規則有關,否則網址倒頁的時候會出問題。 參考資源:

GAE 傳檔案

由於有許多各方面的額度限制,所以要額外使用 blob service 來處理,比較不會發生逾時錯誤。

不過需要開啟付費的服務才能使用此api(開啟以後還是有一些免費額度可以使用)

http://code.google.com/appengine/docs/python/tools/webapp/blobstorehandlers.html#BlobstoreUploadHandler

那要怎麼跟 django 接在一起勒

google 食譜告訴你… http://appengine-cookbook.appspot.com/recipe/blobstore-get_uploads-helper-function-for-django-request/

example : http://blog.sserrano.com/post/479962742/blobstore-upload-with-django-form-validation-example

如果沒有信用卡可以開啟服務來測~

那可以考慮透過下面兩個方案來處理,用 java 的 sdk 來寫~都是在將檔案切割成數個檔,來突破 1MB 傳輸單頁面的限制,可以達到單檔10MB。

https://github.com/honzasterba/bigblobae

http://code.google.com/p/google-file-service/

這個經過實際測試是可以運行的。而且運作的還不錯~

Python shell history Substitution

在 linux 更新成 Python 2.7 後進入他 shell 以後發現,按上下鍵想要查尋歷史紀錄竟然只出現  ^[[A ,這些符號…感覺有點糟糕…

找了許多才發現原來是少安裝一個函式庫,不曉得是 readline 還是 ncureses ,管他的都裝…= =

ncureses 是一個提供在文字介面操作的 API 函式庫。應該跟文字介面上下左右事件監控有關。


yum install ncurses

yum install ncurses-devel
easy_install readline

ncurses 似乎還蠻有趣的,linux kernel menu config 好像就是用他寫的…
網路[3]上看到一個範例可以跑跑看…

#include <curses.h>
#include <stdlib.h>

#define ENTER 10
#define ESCAPE 27
void init_curses()
{
        initscr();
        start_color();
        init_pair(1,COLOR_WHITE,COLOR_BLUE);
        init_pair(2,COLOR_BLUE,COLOR_WHITE);
        init_pair(3,COLOR_RED,COLOR_WHITE);
        curs_set(0);
        noecho();
        keypad(stdscr,TRUE);
}
void draw_menubar(WINDOW *menubar)
{
        wbkgd(menubar,COLOR_PAIR(2));
        waddstr(menubar,"Menu1");
        wattron(menubar,COLOR_PAIR(3));
        waddstr(menubar,"(F1)");
        wattroff(menubar,COLOR_PAIR(3));
        wmove(menubar,0,20);
        waddstr(menubar,"Menu2");
        wattron(menubar,COLOR_PAIR(3));
        waddstr(menubar,"(F2)");
        wattroff(menubar,COLOR_PAIR(3));
}
WINDOW **draw_menu(int start_col)
{
        int i;
        WINDOW **items;
        items=(WINDOW **)malloc(9*sizeof(WINDOW *));

        items[0]=newwin(10,19,1,start_col);
        wbkgd(items[0],COLOR_PAIR(2));
        box(items[0],ACS_VLINE,ACS_HLINE);
        items[1]=subwin(items[0],1,17,2,start_col+1);
        items[2]=subwin(items[0],1,17,3,start_col+1);
        items[3]=subwin(items[0],1,17,4,start_col+1);
        items[4]=subwin(items[0],1,17,5,start_col+1);
        items[5]=subwin(items[0],1,17,6,start_col+1);
        items[6]=subwin(items[0],1,17,7,start_col+1);
        items[7]=subwin(items[0],1,17,8,start_col+1);
        items[8]=subwin(items[0],1,17,9,start_col+1);
        for (i=1;i<9;i++)
                wprintw(items[i],"Item%d",i);
        wbkgd(items[1],COLOR_PAIR(1));
        wrefresh(items[0]);
        return items;
}
void delete_menu(WINDOW **items,int count)
{
        int i;
        for (i=0;i<count;i++)
                delwin(items[i]);
        free(items);
}
int scroll_menu(WINDOW **items,int count,int menu_start_col)
{
        int key;
        int selected=0;
        while (1) {
                key=getch();
                if (key==KEY_DOWN || key==KEY_UP) {
                        wbkgd(items[selected+1],COLOR_PAIR(2));
                        wnoutrefresh(items[selected+1]);
                        if (key==KEY_DOWN) {
                                selected=(selected+1) % count;
                        } else {
                                selected=(selected+count-1) % count;
                        }
                        wbkgd(items[selected+1],COLOR_PAIR(1));
                        wnoutrefresh(items[selected+1]);
                        doupdate();
                } else if (key==KEY_LEFT || key==KEY_RIGHT) {
                        delete_menu(items,count+1);
                        touchwin(stdscr);
                        refresh();
                        items=draw_menu(20-menu_start_col);
                        return scroll_menu(items,8,20-menu_start_col);
                } else if (key==ESCAPE) {
                        return -1;
                } else if (key==ENTER) {
                        return selected;
                }
        }
}
int main()
{
    int key;
    WINDOW *menubar,*messagebar;

    init_curses();

    bkgd(COLOR_PAIR(1));
    menubar=subwin(stdscr,1,80,0,0);
    messagebar=subwin(stdscr,1,79,23,1);
    draw_menubar(menubar);
    move(2,1);
    printw("Press F1 or F2 to open the menus. ");
    printw("ESC quits.");
    refresh();

    do {
        int selected_item;
        WINDOW **menu_items;
        key=getch();
        werase(messagebar);
        wrefresh(messagebar);
        if (key==KEY_F(1)) {
            menu_items=draw_menu(0);
            selected_item=scroll_menu(menu_items,8,0);
            delete_menu(menu_items,9);
            if (selected_item<0)
                wprintw(messagebar,"You haven't selected any item.");
            else
                wprintw(messagebar,
                  "You have selected menu item %d.",selected_item+1);
            touchwin(stdscr);
            refresh();
        } else if (key==KEY_F(2)) {
            menu_items=draw_menu(20);
            selected_item=scroll_menu(menu_items,8,20);
            delete_menu(menu_items,9);
            if (selected_item<0)
                wprintw(messagebar,"You haven't selected any item.");
            else
                wprintw(messagebar,
                  "You have selected menu item %d.",selected_item+1);
            touchwin(stdscr);
            refresh();
        }
    } while (key!=ESCAPE);

    delwin(menubar);
    delwin(messagebar);
    endwin();
    return 0;
}

參考資源:

cassandra and django and twissandra

一個完整簡潔有力的學習專案,twissandra 用 django 與 cassandra 實作 twitter 最簡單重要的功能,有網頁介面。

此專案展示了 cassandra 資料模型的設計以及 API 的使用,又能大略學習 django 的簡單使用,安裝與運作又十分容易,

後端 API 是採用 high level api pycassa ,原先是 Thrift ,而透過 pycassa 做中介層,幫忙做一些控管讓資料存取更順暢。

資料來源

  1. twissandra https://github.com/ericflo/twissandra
  2. pycassa https://github.com/pycassa/pycassa
  3. django http://djangoproject.com