原文地址:Lua OpenResty容器化(考古歷程)html
公司有幾個「遠古時期」的項目,一直都相對較爲穩定,可是項目天天總會在一些時段,請求每分鐘QPS到達峯值800K
左右,致使機器的性能出現了一些瓶頸,每到峯值時期,總會出現一個告警,實在是使人頭疼。更糟糕的是這只是遠古時期項目中的其中一個並且都是部署在物理機器上,全部機器加起來接近100臺。node
出於穩定性(削峯)和成本的角度考慮,咱們最終決定將全部的Lua OpenResty項目上到k8s集羣。linux
經過查看線上在使用的openresty版本信息:nginx
/usr/local/openresty/nginx/sbin/nginx -V nginx version: openresty/1.13.6.2 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC) built with OpenSSL 1.1.0h 27 Mar 2018 (running with OpenSSL 1.1.0k 28 May 2019) TLS SNI support enabled configure arguments: --prefix=/usr/local/openresty/nginx ...
lua -v Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
得知在使用的是openresty/1.13.6.2
和Lua 5.1.4
:c++
docker pull openresty/openresty:1.13.6.2-2-centos
Q:能不能選擇使用更小的alpine系列的呢?git
A:由於項目依賴許多的so庫,都是glibc
編譯的,alpine的話是musl-lib
,不兼容。github
Q:爲啥不從新編譯?docker
A:一方面是風險問題,另一方面是有一些so庫不必定能找到。shell
$ tree -L 3 nginx/conf nginx/conf ├── vhosts/ │ ├── inner.prometheus.nginx.conf │ └── project.nginx.conf └── nginx.conf
binary_protocol.so
編寫好dockerfile,而後將項目打包進容器,執行:json
/usr/local/openresty/nginx/sbin/nginx nginx -t
果不其然,報錯:
/usr/local/openresty/nginx/lua/init.lua:1: module 'binary_protocol' not found: no field package.preload['binary_protocol'] no file '/usr/local/openresty/nginx/lua/binary_protocol.lua' no file '/usr/local/openresty/nginx/lua_lib/binary_protocol.lua' no file '/usr/local/openresty/nginx/luarocks/share/lua/5.1/binary_protocol.lua' no file '/usr/local/openresty/site/lualib/binary_protocol.ljbc' …… …… no file '/usr/local/openresty/nginx/luarocks/lib64/lua/5.1/binary_protocol.so' no file '/usr/local/openresty/site/lualib/binary_protocol.so' no file '/usr/local/openresty/lualib/binary_protocol.so' no file '/usr/local/openresty/site/lualib/binary_protocol.so' no file '/usr/local/openresty/lualib/binary_protocol.so' no file './binary_protocol.so' no file '/usr/local/lib/lua/5.1/binary_protocol.so' no file '/usr/local/openresty/luajit/lib/lua/5.1/binary_protocol.so' no file '/usr/local/lib/lua/5.1/loadall.so' no file '/usr/local/openresty/luajit/lib/lua/5.1/binary_protocol.so'
Q:仔細觀察,發現so動態庫是內部編譯出來提供給lua調用的,如何找到它們呢?
經過ldd、pldd命令,能夠查看so所相關的依賴
ldd binary_protocol.so linux-vdso.so.1 => (0x00007fff40bd4000) libtolua++.so => not found ## 會告訴咱們ldd缺乏這個依賴 libcrypto.so.6 => not found liblog4cplus.so.2 => not found libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f458d9ef000) libm.so.6 => /lib64/libm.so.6 (0x00007f458d6ed000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f458d4d7000) libc.so.6 => /lib64/libc.so.6 (0x00007f458d10a000) /lib64/ld-linux-x86-64.so.2 (0x00007f458df1e000)
經過這些方法,一點點跟蹤,知道找齊全部依賴庫便可。
從線上的nginx.conf
找到lua_package_path
和lua_package_cpath
中包括的luarocks
路徑,再從這個路徑中,找到manifest
文件,此文件有描述安裝了哪些luarocks庫。
RUN luarocks --tree=${WORK_DIR}/luarocks install lua-cjson \ && luarocks --tree=${WORK_DIR}/luarocks install penlight \ && luarocks --tree=${WORK_DIR}/luarocks install version \ && luarocks --tree=${WORK_DIR}/luarocks install lua-resty-http \ && luarocks --tree=${WORK_DIR}/luarocks install luaunit \ && luarocks --tree=${WORK_DIR}/luarocks install ldoc \ && luarocks --tree=${WORK_DIR}/luarocks install lua-discount \ && luarocks --tree=${WORK_DIR}/luarocks install serpent \ && luarocks --tree=${WORK_DIR}/luarocks install luacov \ && luarocks --tree=${WORK_DIR}/luarocks install cluacov \ && luarocks --tree=${WORK_DIR}/luarocks install mmdblua \ && luarocks --tree=${WORK_DIR}/luarocks install lua-resty-jit-uuid \ && luarocks --tree=${WORK_DIR}/luarocks install luasocket RUN luarocks --tree=/usr/local/openresty/nginx/luarocks install nginx-lua-prometheus
通過分析,的確佔用了很是大的內存:
經過ps命令定位到 worker 數量很是多
解決方法:
限定worker數量:worker_processes 4;
Q:爲啥會產生這麼多worker?
A:在k8s上,nginx 啓動的 worker process,並無遵循咱們給 Pod 設置的 limit,而是與 Pod 所在 node 有關。
是因爲Deployment設定的內存限額過小所致
解決方法:調大requests
資源限額
resources: limits: cpu: "2000m" memory: "1Gi" requests: cpu: "1000m" memory: "512Mi"
ps:啓動4個Worker大約消耗200Mi。
緣由是線上的nginx.conf有相關的定義
而代碼層面上沒有,加上便可:
lua_shared_dict monitor_status 150m;
在OpenResty中接入 Prometheus,https://github.com/knyar/ngin...
luarocks --tree=/usr/local/openresty/nginx/luarocks install nginx-lua-prometheus
爲nginx/conf/vhosts/project.nginx.conf
增長:
lua_shared_dict prometheus_metrics 10M; log_by_lua_block { metric_requests:inc(1, {ngx.var.server_name, ngx.var.status}) metric_latency:observe(tonumber(ngx.var.request_time), {ngx.var.server_name}) }
新增nginx/conf/vhosts/inner.prometheus.nginx.conf
server { listen 8099; location /metrics { content_by_lua_block { metric_connections:set(ngx.var.connections_reading, {"reading"}) metric_connections:set(ngx.var.connections_waiting, {"waiting"}) metric_connections:set(ngx.var.connections_writing, {"writing"}) prometheus:collect() } } }
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: ${name} namespace: ${namespace} labels: test-app: test-server spec: replicas: ${replicas} template: metadata: labels: test-app: test-server annotations: # <----------------------- 新增 prometheus.io/scrape: "true" prometheus.io/path: "/metrics" prometheus.io/port: "8099"
至此,lua的一個項目容器化完成,中途遇到的問題仍是蠻多的,上面也只記錄了幾個主要的步驟和問題。