10 строк кода Clojure для создания простого балансировщика с динамическим ограничителем пропускной способности на основе ролей в Nginx
Благодаря быстрым и надежным функциям Nginx становится все более популярным, особенно среди веб-сайтов с высоким трафиком. Clojure , как диалект Lisp на JVM, обладает множеством замечательных функций, таких как «Код — это данные», «Функциональное программирование», «Простота и красота» и т. Д. Теперь Nginx-Clojure является мостом между ними. С Nginx-Clojure мы можем сделать некоторые сложные задачи очень простыми. В этой статье будет приведен пример использования кода Clojure для создания простого балансировщика с динамическим ограничителем пропускной способности на основе ролей в Nginx.
Предположим, что наш веб-сайт имеет две роли пользователей, одна из которых — VIP, а другая — General Free User. Мы хотим ограничить скорость загрузки VIP-пользователей до 500 К / с и ограничить скорость загрузки бесплатных пользователей до 100 К / с. Кажется, что это непростая задача для чисто Java / Clojure решения, но позже мы увидим, что для выполнения этой задачи требуется всего 10 строк кода Clojure.
1. Настройка Nginx-Clojure
Мы можем скачать скомпилированные двоичные файлы
Nginx-Clojure Release v0.3.0 или скомпилировать исходный код после прочтения
руководства по установке с помощью Source .
Задание пути JVM и пути к классам в
http { block в nginx.conf
jvm_path "/usr/lib/jvm/java-7-oracle/jre/lib/amd64/server/libjvm.so"; #jvm_options can be repeated once per option. #for win32, class path seperator is ";" jvm_options "-Djava.class.path=jars/nginx-clojure-0.2.2.jar:jars/clojure-1.5.1.jar:myclasspath";
Вот типичные примеры jvm_path для типичной ОС
Операционные системы | типичный путь jvm_path |
win32 | C: / Program Files / Java / jdk1.7.0_25 / jre / bin / server / jvm.dll |
macosx (Java 6) |
/Library/Java/JavaVirtualMachines/1.6.0_65-b14-462.jdk/Contents/Libraries/libserver.dylib |
macosx (Java 7) |
/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/server/libjvm.dylib |
Ubuntu (64 бит) |
/usr/lib/jvm/java-7-oracle/jre/lib/amd64/server/libjvm.so |
сентос (64 бит) |
/usr/java/jdk1.6.0_45/jre/lib/amd64/server/libjvm.so |
сентос (32 бита) |
/usr/java/jdk1.7.0_51/jre/lib/i386/server/libjvm.so |
upstream mycluster { server 192.168.2.100:9090; server 192.168.2.101:9090; server 192.168.2.102:9090; }
2. Write a Nginx Rewrite Handler by using Clojure
; 7 lines (ns my-simple-limiter (:use [nginx.clojure.core])) (defn speed-limiter [req] (if (= "VIP" (compute-user-role req)) (set-ngx-var! req "limit_rate" "500k") (set-ngx-var! req "limit_rate" "100k")) phrase-done)
3. Configurations about Location /download
server { block
server { listen 8080; server_name localhost; location /download { rewrite_handler_code ' ; 3 lines (do (require \'[my-simple-limiter :as msl]) msl/speed-limiter)'; proxy_pass http://mycluster; }
4. The whole content about nginx.conf
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; jvm_path "/usr/lib/jvm/java-7-oracle/jre/lib/amd64/server/libjvm.so"; #Suppose this Clojure source path is myclasspath. jvm_options "-Djava.class.path=jars/nginx-clojure-0.2.2.jar:jars/clojure-1.5.1.jar:myclasspath"; #jvm heap memory jvm_options "-Xms1024m"; jvm_options "-Xmx1024m"; upstream mycluster { server 192.168.2.100:9090; server 192.168.2.101:9090; server 192.168.2.102:9090; } server { listen 8080; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location /download { rewrite_handler_code ' (do (require \'[my-simple-limiter :as msl]) msl/speed-limiter)'; proxy_pass http://mycluster; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
5. More Thinking about compute-user-role
- Encrypted cookie Store
- Local Memroy Store
- Remote Session Store
If our Nginx worker number is more than one, we can not use simple local memory store to store user sessions, we should consider Shared Map among Nginx Workers or the other two choices.
If we use remote session store such as Redis, Memcached etc. we should Chose Coroutine based Socket Or Asynchronous Socket Or Thread Pool for slow I/O operations.