使用 Docker 和 Nginx 打造高性能的二維碼服務

使用 Docker 和 Nginx 打造高性能的二維碼服務

本文將演示如何使用 Docker 完整打造一個基於 Nginx 的高性能二維碼服務,以及對整個服務鏡像進行優化的方法。若是你的網絡情況良好,完整操做和體驗時間應不超過 15 分鐘。javascript

動手前的腦洞

最近有一個小需求,須要在頁面中快速生成一些二維碼。java

說到生成二維碼,方法不少,好比按照 QRCode 算法進行計算以後:linux

  • 使用各類服務端語言,而後調用 GD 繪圖庫在語言中的 API 進行繪製,並生成圖片,而後配合可以提供 HTTP 服務的軟件對用戶提供圖片訪問地址。nginx

  • 使用服務端語言,而後使用 CSS 和 HTML 生成能夠識別的頁面圖案,而後配合可以提供 HTTP 服務的軟件對用戶提供圖片訪問地址。git

  • 使用客戶端腳本,使用 Canvas 生成二維碼圖片,或者和上一個方案同樣,生成 DOM 圖案。github

  • 算法

可是隻是爲了一個功能,就去配置一套完整的語言環境,引入一堆三方依賴,總有一種殺雞用牛刀的感受,而且在資源利用效率上來講,也不是最優解。docker

而使用客戶端進行生成,如今雖然不存在太多的兼容問題,可是須要額外引入腳本資源,圖片生成效率也相對較慢。ubuntu

那麼有沒有什麼環保高效的方案呢?瀏覽器

天然是有的,仍是選擇服務端生成,可是扔掉語言運行時,直接使用 Nginx 提供服務。

使用 Nginx 進行二維碼生成

這裏可使用一個現成的開源模塊 ngx_http_qrcode_module 。

它經過將用戶請求參數進行轉換,並調用使用 C 實現的二維碼快速生成庫 libqrencode 的 QRcode_encodeString實現二維碼快速生成,在未開啓緩存的狀況下,測試平均生成圖片在 10ms 左右。

爲了方便你們理解所有的安裝配置過程,我先提供一個「囉嗦」版本的 Dockerfile

  1. FROM ubuntu:18.04

  2.  

  3. RUN cat /etc/apt/sources.list | sed -e "s/archive\.ubuntu\.com/mirrors\.aliyun\.com/" | sed -e "s/security\.ubuntu\.com/mirrors\.aliyun\.com/" | tee /etc/apt/sources.list

  4. RUN apt update && \

  5.    apt install -y unzip wget

  6.  

  7. WORKDIR /data

  8.  

  9. # https://github.com/fukuchi/libqrencode

  10. RUN apt install -y autoconf automake autotools-dev libtool pkg-config libpng-dev && \

  11.    cd /data && wget https://github.com/fukuchi/libqrencode/archive/master.zip && unzip master.zip && rm -rf master.zip && \

  12.    cd libqrencode-master && ./autogen.sh && ./configure && make && make install && ldconfig && \

  13.    cd .. && rm -rf libqrencode-master

  14.  

  15. RUN apt install -y libgd-dev

  16.  

  17. ADD ngx_http_qrcode /data/ngx_http_qrcode

  18. ADD nginx-1.15.5.tar.gz /data

  19. ADD nginx.conf /data

  20.  

  21. RUN apt install -y libpcre3 libpcre3-dev && \

  22.    cd nginx-1.15.5 && ./configure --add-module=../ngx_http_qrcode/ && \

  23.    make && make install && mv /data/nginx.conf /usr/local/nginx/conf/nginx.conf && \

  24.    cd .. && rm -rf ngx_http_qrcode

將上面的文件保存完畢。接下來咱們來配置 Nginx

  1. worker_processes  1;

  2.  

  3. events {

  4.    worker_connections  1024;

  5. }

  6.  

  7.  

  8. http {

  9.    include       mime.types;

  10.    default_type  application/octet-stream;

  11.  

  12.    sendfile        on;

  13.  

  14.    keepalive_timeout  65;

  15.  

  16.    server {

  17.        listen       80;

  18.        server_name  localhost;

  19.  

  20.        location / {

  21.  

  22.            set $fg_color 000000;

  23.            set $bg_color FFFFFF;

  24.            set $level 0;

  25.            set $hint 2;

  26.            set $size 300;

  27.            set $margin 80;

  28.            set $version 2;

  29.            set $case 0;

  30.            set $txt "https://soulteary.com";

  31.  

  32.            if ( $arg_fg_color ){

  33.                set $fg_color $arg_fg_color;

  34.            }

  35.            if ( $arg_bg_color ){

  36.                set $bg_color $arg_bg_color;

  37.            }

  38.            if ( $arg_level ){

  39.                set $level $arg_level;

  40.            }

  41.            if ( $arg_hint ){

  42.                set $hint $arg_hint;

  43.            }

  44.            if ( $arg_size ){

  45.                set $size $arg_size;

  46.            }

  47.            if ( $arg_margin ){

  48.                set $margin $arg_margin;

  49.            }

  50.            if ( $arg_ver ){

  51.                set $version $arg_ver;

  52.            }

  53.            if ( $arg_case ){

  54.                set $case $arg_case;

  55.            }

  56.            if ( $arg_txt ){

  57.                set $txt $arg_txt;

  58.            }

  59.  

  60.  

  61.            qrcode_fg_color $fg_color;

  62.            qrcode_bg_color $bg_color;

  63.  

  64.            qrcode_level    $level;

  65.            qrcode_hint     $hint;

  66.            qrcode_size     $size;

  67.            qrcode_margin   $margin;

  68.            qrcode_version  $version;

  69.            qrcode_casesensitive $case;

  70.            qrcode_urlencode_txt $txt;

  71.  

  72.            qrcode_gen;

  73.        }

  74.  

  75.    }

  76. }

將上面的配置保存爲 nginx.conf,而後使用下面的命令進行鏡像構建。

  1. docker build -t docker.lab.com/qrcode.lab.com .

若是你的網絡通暢,5分鐘以內,這個鏡像就構建完畢了。接下來,咱們對它進行一下可用性驗證。

將下面的配置文件保存爲 docker-compose.yml,而後使用 docker-compose up 命令啓動,一個支持 HTTP/HTTPS,域名爲 qrcode.lab.com 的網站就準備就緒了。

這裏我使用了 Traefik 進行服務發現,感興趣的童鞋能夠參考我之前寫的文章: 使用服務發現改善開發體驗 、 更完善的 Docker + Traefik 使用方案 、使用 Traefik 的一些補充細節),一旦你開始使用並掌握了它,你會發現搭建高可擴展的 Web 服務變的更簡單了。

  1. version: '3'

  2.  

  3. services:

  4.  

  5.  qrcode:

  6.    image: docker.lab.com/qrcode.lab.com:0.0.2

  7.    expose:

  8.      - 80

  9.    networks:

  10.      - traefik

  11.    labels:

  12.      - "traefik.enable=true"

  13.      - "traefik.port=80"

  14.      - "traefik.frontend.rule=Host:qrcode.lab.com"

  15.      - "traefik.frontend.entryPoints=http,https"

  16.  

  17. networks:

  18.  traefik:

  19.    external: true

而後咱們在瀏覽器中分別訪問,來驗證二維碼服務是否就緒:

  • https://qrcode.lab.com

  • https://qrcode.lab.com/?size=150&margin=20&txt=https%3A%2F%2Fsoulteary.com

看來服務是正常運行的,本文的基礎需求到這裏就解決了,而且,爲了這個服務可以更好的被使用,咱們能夠在書籤中輸入下面的腳本代碼:

  1. javascript:(function(){document.location.href='https://qrcode.lab.com/?size=150&txt='+encodeURIComponent(document.location.href);})()

當你點擊書籤的時候,會將當前頁面自動轉換爲一個能夠掃描的二維碼。

經過整合語句優化容器鏡像

雖然上面的內容已經知足了咱們的基礎需求,可是做爲一個有追求的開發者,咱們不光是要追求執行效率,還要追求儲存效率。

雖然 Nginx 的運行資源佔用很少。

  1. top - 09:50:29 up 21 days, 19 min,  0 users,  load average: 0.03, 0.05, 0.05

  2. Tasks:   4 total,   1 running,   3 sleeping,   0 stopped,   0 zombie

  3. %Cpu(s):  0.3 us,  0.3 sy,  0.0 ni, 99.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

  4. KiB Mem :  6101684 total,   332268 free,  3649484 used,  2119932 buff/cache

  5. KiB Swap:   998396 total,   936632 free,    61764 used.  2122020 avail Mem

  6.  

  7.  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                            

  8.    8 nobody    20   0   72352   4792   3124 S   0.7  0.1   0:00.02 nginx                                                                                                              

  9.    1 root      20   0   70800   4996   4240 S   0.0  0.1   0:00.01 nginx

可是使用 docker images 命令查看鏡像詳情,咱們能夠看到這個鏡像仍是挺大的,有 400+MB

  1. REPOSITORY                            TAG                   IMAGE ID            CREATED              SIZE

  2. docker.lab.com/qrcode.lab.com         0.0.1                 d98376b43ae9        About a minute ago   454MB

這裏咱們修改一下上面的鏡像 Dockerfile,嘗試從新進行鏡像構建。

  1. FROM ubuntu:18.04

  2.  

  3. RUN cat /etc/apt/sources.list | sed -e "s/archive\.ubuntu\.com/mirrors\.aliyun\.com/" | sed -e "s/security\.ubuntu\.com/mirrors\.aliyun\.com/" | tee /etc/apt/sources.list

  4.  

  5. WORKDIR /tmp

  6.  

  7. RUN apt update && apt install -y unzip wget autoconf automake autotools-dev libtool pkg-config libpng-dev libgd-dev libpcre3 libpcre3-dev && \

  8.    wget https://nginx.org/download/nginx-1.15.5.tar.gz && tar -zxvf nginx-1.15.5.tar.gz && rm -rf nginx-1.15.5.tar.gz && \

  9.    wget https://github.com/dcshi/ngx_http_qrcode_module/archive/master.zip && unzip master.zip && mv ngx_http_qrcode_module-master ngx_http_qrcode_module && rm -rf master.zip && \

  10.    wget https://github.com/fukuchi/libqrencode/archive/master.zip && unzip master.zip && mv libqrencode-master libqrencode && \

  11.    cd libqrencode && ./autogen.sh && ./configure && make && make install && ldconfig && \

  12.    cd /tmp/nginx-1.15.5 && ./configure --add-module=../ngx_http_qrcode_module/ && make && make install && \

  13.    apt remove -y unzip wget autoconf automake autotools-dev libtool pkg-config && \

  14.    rm -rf /tmp/* && rm -rf /var/cache/

  15.  

  16. ADD nginx.conf /usr/local/nginx/conf/nginx.conf

  17.  

  18. EXPOSE 80

  19.  

  20. ENTRYPOINT [ "/usr/local/nginx/sbin/nginx", "-g", "daemon off;" ]

再次構建完畢,咱們會發現鏡像只是減小了 35MB,相比較 400MB 多的總體體積,優化部分杯水車薪。

  1. REPOSITORY                            TAG                   IMAGE ID            CREATED             SIZE

  2. docker.lab.com/qrcode.lab.com         0.0.1                 a24ffc73121a        1 minutes ago      420MB

那麼優化就到此爲止了麼?顯然不是。

經過優化基礎鏡像來優化容器鏡像

這裏咱們選擇使用體積更小的 Linux 鏡像, Alpine來進行一樣功能的二維碼服務的容器鏡像。

由於 Alpine 和 Ubuntu 不是一個社區進行維護,因此軟件包不少名稱是不一樣的,這裏我直接提供我已經查找修改完畢的鏡像文件。

若是你也有相似的需求,須要將不一樣系統的軟件進行遷移安裝,能夠在 https://pkgs.alpinelinux.org/packages 查找你所須要的軟件包的名稱。

  1. FROM alpine:3.8

  2.  

  3. RUN cat /etc/apk/repositories | sed -e "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/" | tee /etc/apk/repositories && \

  4.    apk --update add openssl-dev pcre-dev zlib-dev wget build-base autoconf automake libtool libpng-dev libgd pcre pcre-dev pkgconfig gd-dev && \

  5.    cd /tmp && \

  6.    wget https://nginx.org/download/nginx-1.15.5.tar.gz && tar -zxvf nginx-1.15.5.tar.gz && rm -rf nginx-1.15.5.tar.gz && \

  7.    wget https://github.com/dcshi/ngx_http_qrcode_module/archive/master.zip && unzip master.zip && mv ngx_http_qrcode_module-master ngx_http_qrcode_module && rm -rf master.zip && \

  8.    wget https://github.com/fukuchi/libqrencode/archive/master.zip && unzip master.zip && mv libqrencode-master libqrencode && \

  9.    cd libqrencode && ./autogen.sh && ./configure && make && make install && ldconfig || true && \

  10.    cd /tmp/nginx-1.15.5 && ./configure --add-module=../ngx_http_qrcode_module/ && make && make install && \

  11.    apk del build-base autoconf automake pkgconfig && \

  12.    rm -rf /tmp/* && rm -rf /var/cache/apk/*

  13.  

  14. ADD nginx.conf /usr/local/nginx/conf/nginx.conf

  15.  

  16. EXPOSE 80

  17.  

  18. ENTRYPOINT [ "/usr/local/nginx/sbin/nginx", "-g", "daemon off;" ]

當鏡像打包完畢,咱們再次查看鏡像體積,能夠看到體積有了明顯的優化效果。

  1. REPOSITORY                            TAG                   IMAGE ID            CREATED             SIZE

  2. docker.lab.com/qrcode.lab.com         0.0.2                 d236b96c8950        1 minutes ago   79.1MB

最後

還記得本文標題中的關鍵詞「高性能」嘛,雖然說我我的測試單實例的響應時間都在 10ms 左右,可是若是你真的考慮使用它作對外服務的話,可使用下面的命令,根據本身狀況對節點進行動態擴容,成倍提升服務響應能力。

  1. docker-compose scale qrcode=4

或者使用

  1. docker-compose up --scale qrcode=2 -d

若是你也是 Traefik 用戶,你將會看到你的實例被成功進行掛載以及流量負載均衡。

另外,爲了不被惡意利用,還須要考慮使用 Nginx / iptable 的 req_limit 等模塊限制訪問頻率,以及適當修改 ngx_http_qrcode_module 生成內容和圖片尺寸的判斷。

相關文章
相關標籤/搜索