使用 Docker 和 Nginx 打造高性能的二维码服务

本文将演示如何使用 Docker 完整打造一个基于 Nginx 的高性能二维码服务,以及对整个服务镜像进行优化的方法。如果你的网络状况良好,完整操作和体验时间应不超过 15 分钟。

动手前的脑洞

最近有一个小需求,需要在页面中快速生成一些二维码。

说到生成二维码,方法很多,比如按照 QRCode 算法进行计算之后:

  • 使用各种服务端语言,然后调用 GD 绘图库在语言中的 API 进行绘制,并生成图片,然后配合能够提供 HTTP 服务的软件对用户提供图片访问地址。

  • 使用服务端语言,然后使用 CSS 和 HTML 生成可以识别的页面图案,然后配合能够提供 HTTP 服务的软件对用户提供图片访问地址。

  • 使用客户端脚本,使用 Canvas 生成二维码图片,或者和上一个方案一样,生成 DOM 图案。

但是只是为了一个功能,就去配置一套完整的语言环境,引入一堆三方依赖,总有一种杀鸡用牛刀的感觉,并且在资源利用效率上来说,也不是最优解。

而使用客户端进行生成,现在虽然不存在太多的兼容问题,但是需要额外引入脚本资源,图片生成效率也相对较慢。

那么有没有什么环保高效的方案呢?

自然是有的,还是选择服务端生成,但是扔掉语言运行时,直接使用 Nginx 提供服务。

使用 Nginx 进行二维码生成

这里可以使用一个现成的开源模块 ngx_http_qrcode_module 。

它通过将用户请求参数进行转换,并调用使用 C 实现的二维码快速生成库 libqrencode 的 QRcode_encodeString实现二维码快速生成,在未开启缓存的情况下,测试平均生成图片在 10ms 左右。

为了方便大家理解全部的安装配置过程,我先提供一个“啰嗦”版本的 Dockerfile

  1. FROM ubuntu:18.04

  2. 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

  3. RUN apt update && \

  4.    apt install -y unzip wget

  5. WORKDIR /data

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

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

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

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

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

  11. RUN apt install -y libgd-dev

  12. ADD ngx_http_qrcode /data/ngx_http_qrcode

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

  14. ADD nginx.conf /data

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

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

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

  18.    cd .. && rm -rf ngx_http_qrcode

将上面的文件保存完毕。接下来我们来配置 Nginx

  1. worker_processes  1;

  2. events {

  3.    worker_connections  1024;

  4. }

  5. http {

  6.    include       mime.types;

  7.    default_type  application/octet-stream;

  8.    sendfile        on;

  9.    keepalive_timeout  65;

  10.    server {

  11.        listen       80;

  12.        server_name  localhost;

  13.        location / {

  14.            set $fg_color 000000;

  15.            set $bg_color FFFFFF;

  16.            set $level 0;

  17.            set $hint 2;

  18.            set $size 300;

  19.            set $margin 80;

  20.            set $version 2;

  21.            set $case 0;

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

  23.            if ( $arg_fg_color ){

  24.                set $fg_color $arg_fg_color;

  25.            }

  26.            if ( $arg_bg_color ){

  27.                set $bg_color $arg_bg_color;

  28.            }

  29.            if ( $arg_level ){

  30.                set $level $arg_level;

  31.            }

  32.            if ( $arg_hint ){

  33.                set $hint $arg_hint;

  34.            }

  35.            if ( $arg_size ){

  36.                set $size $arg_size;

  37.            }

  38.            if ( $arg_margin ){

  39.                set $margin $arg_margin;

  40.            }

  41.            if ( $arg_ver ){

  42.                set $version $arg_ver;

  43.            }

  44.            if ( $arg_case ){

  45.                set $case $arg_case;

  46.            }

  47.            if ( $arg_txt ){

  48.                set $txt $arg_txt;

  49.            }

  50.            qrcode_fg_color $fg_color;

  51.            qrcode_bg_color $bg_color;

  52.            qrcode_level    $level;

  53.            qrcode_hint     $hint;

  54.            qrcode_size     $size;

  55.            qrcode_margin   $margin;

  56.            qrcode_version  $version;

  57.            qrcode_casesensitive $case;

  58.            qrcode_urlencode_txt $txt;

  59.            qrcode_gen;

  60.        }

  61.    }

  62. }

将上面的配置保存为 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. services:

  3.  qrcode:

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

  5.    expose:

  6.      - 80

  7.    networks:

  8.      - traefik

  9.    labels:

  10.      - "traefik.enable=true"

  11.      - "traefik.port=80"

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

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

  14. networks:

  15.  traefik:

  16.    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.  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                            

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

  8.    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. 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

  3. WORKDIR /tmp

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

  5.    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 && \

  6.    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 && \

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

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

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

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

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

  12. ADD nginx.conf /usr/local/nginx/conf/nginx.conf

  13. EXPOSE 80

  14. 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. RUN cat /etc/apk/repositories | sed -e "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/" | tee /etc/apk/repositories && \

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

  4.    cd /tmp && \

  5.    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 && \

  6.    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 && \

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

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

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

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

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

  12. ADD nginx.conf /usr/local/nginx/conf/nginx.conf

  13. EXPOSE 80

  14. 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 生成内容和图片尺寸的判断。

 

使用 Docker 和 Nginx 打造高性能的二维码服务的更多相关文章

  1. spring boot高性能实现二维码扫码登录(中)——Redis版

    前言 本打算用CountDownLatch来实现,但有个问题我没有考虑,就是当用户APP没有扫二维码的时候,线程会阻塞5分钟,这反而造成性能的下降.好吧,现在回归传统方式:前端ajax每隔1秒或2秒发 ...

  2. spring boot高性能实现二维码扫码登录(下)——订阅与发布机制版

     前言 基于之前两篇(<spring boot高性能实现二维码扫码登录(上)——单服务器版>和<spring boot高性能实现二维码扫码登录(中)——Redis版>)的基础, ...

  3. 用lua nginx module搭建一个二维码

    用lua nginx module搭建一个二维码(qr code)生成器 作者 vinoca 發布於 2014年10月31日 如果有VPS,或者开源的路由器,安装一个nginx,添加lua-nginx ...

  4. spring boot高性能实现二维码扫码登录(上)——单服务器版

    前言 目前网页的主流登录方式是通过手机扫码二维码登录.我看了网上很多关于扫码登录博客后,发现基本思路大致是:打开网页,生成uuid,然后长连接请求后端并等待登录认证相应结果,而后端每个几百毫秒会循环查 ...

  5. 【thinkphp5.1】 endroid/qrcode 二维码生成

    composer 链接: https://packagist.org/packages/endroid/qrcode 注意:PHP版本 要求 7.1+ 1. 使用 composer 安装 endroi ...

  6. 一次使用Python连接数据库生成二维码并安装为windows服务的工作任务

    最近有一个需求,在现有生产系统上的人员库中增加一个此人员关键信息的二维码,支持文字版和跳转版两种方式,与报表工具关联,可打印.以windows服务方式,定时检查,只要发现某人员没有此二维码信息,就生成 ...

  7. tornado zbar 二维码识别 ,配合nginx 反向代理,supervisord 监控

    tornado zbar 二维码识别 ,配合nginx 反向代理,supervisord 监控 1.zbar识别二维码程序,python2.6.6 #!/usr/bin/env python # co ...

  8. netcore程序部署 docker 异常 --生成图片二维码缺少libdl

    最近因业务需求需要在程序中实现二维码图片生成,于是就用到QRCoder开发库.最终在windows环境下部署运行没问题,但切换到docker(centos7.0)后发现是有问题的. 错误信息提示:Th ...

  9. 基于nginx实现二维码下载安装apk文件

    将apk文件置于nginx目录下 <!--进入nginx安装路径--> /usr/local/nginx <!--新建放apk的目录--> mkdir -p resources ...

随机推荐

  1. Maven设置http代理

    背景:有时候公司处于安全因素的考虑,需要通过代理访问因特网,这种情况需要为Maven设置htpp代理 设置步骤如下: 1 首先确认自己无法访问外网公共的中央仓库(可通过ping repo1.maven ...

  2. 【前端】之JavaScript基础知识

    JS 基础知识 JS中,简单类型的数据存储在栈中,复杂类型的数据存储在堆中,其引用存储在栈中 JS中的深拷贝和浅拷贝: 浅拷贝:将对象中的所有简单类型的属性拷贝出来,引用类型属性直接赋值null 深拷 ...

  3. python_迭代器和生成器、字节串、字节数组

    迭代器 iterator  和 生成器 generator 什么是迭代器:迭代器就是获取迭代对象中元素的工具,迭代器是由可迭代对象生成的 1.迭代器是指用iter(可迭代对象)函数返回的对象(实例) ...

  4. OpenCV图像识别初探-50行代码教机器玩2D游戏【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  5. luogu P1417 烹调方案 |dp

    题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的 ...

  6. [TimLinux] 系统配置 CentOS7配置Samba

    1. 安装软件 yum install -y samba samba-client samba-common 2. 配置用户 useradd tim passwd tim # 设置用户登录密码 smb ...

  7. ELK filebeat的安装

    安装参考官方文档: https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation.html 注意事项: Fr ...

  8. HDU2767 Proving Equivalences(加边变为强联通图)

    Proving Equivalences Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  9. [FPGA]Verilog 60s秒表计时器(最大可计时间长达9min)

    [FPGA]Verilog 60s秒表计时器 1.引述 这次的实验来自于本人本科课程数电结课时的自选题目.由于这次上传是后知后觉,学校已将小脚丫板子回收,所以在这篇文章中没法贴出代码结果的效果图了,但 ...

  10. VIP 视频开发板 上位机 测试软件 下载地址,玩转各自分辨率(V201抢先版)

    本上位机最高测试帧率 133fps 目前支持分辨率:更多分辨率支持,敬请期待或给我留言VGA:640*4801.3M:1280*10242M:1600*1200786p:1024*768 格式兼容:1 ...