新程序员003:云原生和全面数字化实践

来源:https://e.jd.com/30797971.html

目录

  • 卷首语:开源云原生和数字化新实践
  • 云原生时代的开发者
  • 专题导读:云原生时代的开发者
  • 云原生的定义及其关键技术
  • 中国云原生用户调查报告:技术应用及应用建设现状
  • 2021云原生开发者现状:K8s稳居容器榜首,Docker冲顶技术热词,微服务应用热度不减
  • Kubernetes联合创始人Brendan Burns:Kubernetes及其未来
  • 云原生与大数据、AIoT、开源的碰撞之路——专访小米崔宝秋
  • 基础设施即代码:一场变革即将到来
  • Kubernetes与云原生运行时的前世今生
  • Serverless:从云计算的默认编程范式到生产力
  • 混沌工程+韧性工程:云原生时代可靠性治理的“王炸”
  • API——现代软件基石与数字世界的连接者
  • 云原生时代,如何构建一款简单易用且安全的应用管理平台?
  • Kubernetes生产实践下的可观测性及故障定位
  • 降本增效——美团集群调度系统的云原生实践
  • 火山引擎张鑫:“原生云”时代的四个改变
  • 大规模服务治理的云原生实践
  • Dubbo在云原生时代的进化之道
  • 网易轻舟服务网格落地实践
  • 混沌工程在中国工商银行的应用实践
  • 开源云原生大潮下的消息和流系统演进
  • Network Service Mesh:让电信网络虚拟化迈向云原生时代
  • 云原生运行时的下一个五年
  • 云原生时代的异地多活架构畅想
  • 云原生时代开发者,如何“变”与“不变”?
  • 全面数字化转型
  • 程序员的数字化转型
  • 蒋涛对话英特尔中国区董事长王锐:数字化已成为推动世界革新的原动力
  • 企业数字化转型的前世今生
  • 企业数字化转型路径和实现技术
  • 数字化转型方法论:数字化转型的失败原因及成功之道
  • 数字化转型的锦囊妙计:数字化平台
  • “离·坚白,合·同异”:微软数字化转型实践的思考
  • 构建新一代数据服务与管理平台的背后思考
  • 阿里云张瑞:程序员3.0时代到来
  • 基于云原生技术突破数字化软件生产瓶颈
  • 数字化就是释放比特的能力
  • 字节跳动的“数字化原生”之路
  • 以数据治理为价值驱动的产业数字化转型
  • 企业数字化转型:因企制宜,久久为功
  • 狭义工业互联网底层体系架构及应用部署
  • 施耐德电气:开放自动化是工业控制系统的未来
  • 工业数字化:IT+OT的数与智
  • 基于数字孪生理念重新思考、架构和实现新一代工业软件
  • 超融合时序数据库:消除工业数据“孤岛”
  • 百味
  • 《神秘的程序员们》之高并发需求

前言

  我们正在进入一个开发范式转移的大时代!

  十年前,Netscape创始人、硅谷著名投资人马克·安德森(Marc Andreessen)预言“软件正在吞噬世界”;数年后,软件里90%以上的代码都是开源代码,“开源正在吞噬软件”;如今,“云原生吞噬开源”,开源项目正在向云化演进。

  近年来,容器、虚拟化、DevOps等技术快速发展,将整个开发过程、开发流程带入云端,开发范式发生巨变。同时,Kubernetes、微服务、Service Mesh等一系列新技术规范涌现,开发模式、开发工具、开发成果甚至开发商业模式都在迭代升级。

  我们已经从过去的互联网时代步入移动互联网、云计算和大数据的时代,逐步进入全新的云原生时代。在云原生的发展道路上,开源有着非常关键的作用,它推动了云原生的发展。同样,云原生也为开源带来了最好的商业化模型。PaaS、SaaS以及IaaS服务都已进化到更加原生(Native)的状态,全面云化要来了!

  未来,开发者的代码调用等各种服务都将被云化,随之而来的是服务将拥有更好的弹性,用户体验也将提升。当开源项目被云化后,其收入模型将更加清晰,用户能够得到最新、最可靠的服务。一方面,云原生等新技术顺应市场与企业的需求而生,另一方面,越来越多的企业正在借助云原生应用架构助力业务的数字化转型。

  当数字化成为当下社会的主旋律之一时,企业对技术力量的需求也将不断升级。在《新程序员·开发者黄金十年》专辑里,我们曾谈到中国正迎来开发者市场的三大红利:人人都是开发者、家家都是技术公司、十万亿开发者新生态。而今,我们已经处在了全面数字化的时代,数字化正在吞噬传统行业。

  当业务皆被数字化和数据化以后,企业的竞争力是什么?答案是:你所拥有的开发力量。

  2021年,CSDN注册用户数量增长了近700万,实名总用户数3200万。这意味着,企业对开发者的需求仍在持续上涨。在数字化转型趋势下,开发者的机遇与挑战并存。开发者不仅要掌握新一代开发范式、学习新一代的云原生技术,未来也将朝着两大方向发展:一个方向是升级为架构级工程师,去帮助开发者开发更好的程序;另一个方向则是转变为业务专家,向以低代码驱动企业的业务发展。

  一个拥有复合能力的程序员才能拥有更多的成长机会。随着技术开发范式的变化,数字化转型加速实现,开发者最需要做的仍然是不断学习、提升自我。

  在《新程序员.003》中,我们聚焦“云原生时代的开发者”与“全面数字化转型”两大主题。阿里、字节跳动、网易、快手、亚马逊等互联网大厂的云原生技术的赋能者,从技术定义、技术应用、实践案例分享等方面,以直击内核的硬核输出全面解析云原生,帮助开发者在云原生时代快速找到适合自身发展的技术范式。同时,我们也将对微软、英特尔、华为、施耐德、西门子等首批开启数字化转型的企业展开报道,通过十多位技术专家分享的鲜活案例,一窥金融、新零售、工业物联网等领域的数字化转型成果,帮助更多关注数字化转型的开发者从先驱者的经验中获得启迪。

  微软(中国)首席技术官韦青在分享他对微软数字化转型实践的思考时谈到:“真正进入数字化转型深水区的公司,会越发认识到转型的不易,也会发现很多理论性知识与现实脱节的情况。”然而,我们相信,数字化转型已是大势所趋,未来将有更多行业逐步进入全面数字化的时代。


使用 Kaniko 在Kubernetes平台上构建容器镜像

我们之前使用Jenkins构建容器镜像,做法是 Jenkins容器挂载宿主机的socket文件到容器内部,容器内部运行 docker build 就行。

但是这样有一个问题。如果宿主机的 docker daemon 重启的话,必须把Jenkins容器也重启一遍(因为原有socket文件已失效了,但是容器内部是不知道的,还用着原有的socket文件),否则就会报错。

另外由于 /var/run/docker.sock 文件是root权限,将其挂在在容器里就存在风险了,所以挂载socket文件不是一种优雅的 docker build 方式。

kaniko

Kaniko是谷歌开源的一款用来构建容器镜像的工具。Kaniko 不依赖于Docker daemon进程,它在用户空间根据 Dockerfile 的内容逐行执行命令来构建镜像,这就和宿主机上的docker解绑了,更加安全可靠。

Kaniko 以容器镜像的方式来运行的,同时需要三个参数: Dockerfile,上下文,以及远端镜像仓库的地址

  1. Kaniko会先提取基础镜像(Dockerfile FROM 之后的镜像)的文件系统
  2. 根据Dockerfile中所描述的,一条条执行命令,每一条命令执行完以后会在用户空间下面创建一个snapshot,并与存储与内存中的上一个状态进行比对,如果有变化,就将新的修改生成一个镜像层添加在基础镜像上,并且将相关的修改信息写入镜像元数据中。
  3. 等所有命令执行完,kaniko会将最终镜像推送到指定的远端镜像仓库。

demo

$ cat Dockerfile
FROM alpine:latest
    
MAINTAINER <devops008@sina.com xiaomage>
    
RUN apk add busybox-extras curl
    
CMD ["echo","Hello DevOps"]

在kubernetes cluster上面创建一个pod,yaml文件如下:

apiVersion: v1
kind: Pod
metadata:
name: kaniko
spec:
 containers:
 - name: kaniko
   image: gcr.io/kaniko-project/executor:latest
   args: ["--dockerfile=/workspace/Dockerfile",
          "--context=/workspace/",
          "--destination=dllhb/kaniko-test:v0.4"]
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
      - name: dockerfile
        mountPath: /workspace/Dockerfile
        subPath: Dockerfile
restartPolicy: Never
volumes:
      - name: dockerfile
        configMap:
          name: dockerfile
      - name: kaniko-secret
         projected:
         sources:
         - secret:
              name: regcred
              items:
                - key: .dockerconfigjson
                  path: config.json
  • args 部分

    这部分就是上面所讲的,kaniko运行时需要三个参数: Dockerfile(–dockerfile),上下文(–context),远端镜像仓库(–destination)

  • secret 部分

    推送至指定远端镜像仓库需要credential的支持,所以需要将credential以secret的方式挂载到/kaniko/.docker/这个目录下,文件名称为config.json,内容如下:

{   
    "auths": {
        "https://index.docker.io/v1/": {
            "auth": "AbcdEdfgEdggds="
       }
    }
    
}

其中auth的值为: echo"docker_registry_username:docker_registry_password"|base64

参考资料


pandoc 转换 markdown 为 pdf

一、安装

sudo apt install \
  pandoc \
  texlive-latex-base \
  texlive-fonts-recommended \
  texlive-extra-utils \
  texlive-latex-extra \
  texlive-xetex

二、背景介绍

Pandoc 可以很方便地对不同 Markup 语言的文件进行格式转换,因此被誉为格式转换的「瑞士军刀」。使用 Pandoc 把 Markdown 文件转为 PDF 文件,实际上包含两个步骤:

  • 第一步, Markdown 文件被转为 LaTeX 源文件。
  • 第二步,调用系统的 pdflatex, xelatex 或者其他 TeX 命令,将 .tex 文件转换为最终的 PDF 文件 。

Pandoc 默认使用的 pdflatex 命令无法处理 Unicode 字符,如果要把包含中文的Markdown 文件转为 PDF,在生成 PDF 的过程中会报错。我们需要使用 xelatex 来处理中文,并且需要使用 mainfont 选项指定支持中文的字体。

pandoc --pdf-engine=xelatex -V mainfont="XXX" test.md -o test.pdf

三、安装和查看本机上的中文字体

安装字体

apt-get install fontconfig xfonts-utils # 安装fc-cache
apt-get install ttf-mscorefonts-installer # 微软的TrueType 核心字库
apt-get install ttf-wqy-microhei  #文泉驿-微米黑
apt-get install ttf-wqy-zenhei  #文泉驿-正黑
apt-get install xfonts-wqy #文泉驿-点阵宋体

我是debian环境,字体位置,/usr/share/fonts

fc-list :lang=zh

image-20220310121348796

四、转换pdf常用参数

  • –latex-engine=pdflatex/lualatex/xelatex

–latex-engine用来指定转换PDF格式时LaTeX引擎,默认情况下是pdflatex,但是由于pdflatex不支持中文,因此需要将引擎设置为xelatex

  • –template=FILE

使用FILE指定的文件作为输出文档的自定义模板。可将模板文件放置任意处,只是指定FILE时需要该FILE的路径。

  • –toc, –table-of-contents

使用该参数后,会在输出文档开头自动产生文件目录,对于输出格式是man, docbook, slidy, slideous, s5, docx 或者odt的文档,该参数不起任何作用。

  • –toc-depth=NUMBER

指定文件目录中包含的章节级别,默认NUMBER=3,表示一级标题、二级标题、三级标题都会被在目录中展示。

  • -V KEY[=VAL], –variable=KEY[:VAL]

当渲染standalone模式下文档时,设置模板变量KEY的值为VAL。pandoc会自动设置默认模板中的这些变量,因此该选项这通常在使用–template选项指定自定义模板时有用,如果没有指定VAL值,那么该KEY会被赋予值true。

  • -s, –standalone

转换输出文档时会自动加上合适的header和footer(例如standalone HTML, LaTeX, RTF).该选择在转换输出pdf,epub,epub3,fb2,docx,odt格式文件时会被自动设置,因此如果转换输出上述格式文件,则不用显示指定该选项。

  • -N, –number-sections

对于转换输出LaTeX, ConTeXt, HTML, EPUB格式文档时,对文中章节进行编号。默认情况下,文章的章节是不会被编号的。对于使用了class unnumbered 的章节肯定不会被标号,即使使用了–number-sections选项。

五、命令备忘

pandoc --pdf-engine=xelatex -V mainfont='WenQuanYi Zen Hei Mono' 1.md --template pm -o 2.pdf

我用了这个模版,对中文比较友好,将 pm-template.latex 文件拷贝到 /usr/share/pandoc/data/templates后直接使用。

这个模版需要做些调整,将字体设置的地方LiHei Pro,改为我本机存在的字体WenQuanYi Zen Hei Mono

遇到个问题,中文无法换行。最后直接用这个模版解决了。

还有另一个模版Eisvogel也比较常用的。

参考资料


Nginx 缓存 DNS 解析问题

我使用了容器化的oprenresty,一般都会使用 upstream 特性转发到多个后端。因为是高可用的架构,后端偶尔也会手动重启服务。但问题在于 nginx 原生不支持动态解析 dns,需要做额外的模块编译。这篇文章记录我手动编译 openresty 容器的过程。

一、缓存问题的解决方案

1 每次更改 DNS 解析都重载 Nginx

重载 Nginx 一定会刷新缓存。

2 使用 Nginx 的 resolver

我们在使用 Nginx 过程中,有时需要根据 Url 传值动态选择 host 进行代理转发,这种模式下,一开始是不会去进行 DNS 解析的,只有请求的时候才会进行 DNS 解析,并且要设置 resolver 指定 DNS 服务器 IP。

这个时候,我们就可以使用 resolver 语法来解决 DNS 缓存的问题,比如说,我在原来的 Nginx 配置里指定 DNS IP,并设置缓存 60 秒。

server {
    listen 80;
    server_name www.test.com;

    resolver 127.0.0.1 valid=60s;
    resolver_timeout 3s;

    set $proxy_url "proxy.test.com";
    location / {
        proxy_set_header Host proxy.test.com;
        proxy_pass http://$proxy_url;
    }
}

但这种方法无法作用于 upstream 里的域名。

3 使用模块nginx-upstream-dynamic-servers

模块地址: nginx-upstream-dynamic-servers

该模块在第一次启动的时候会进行一次解析,解析完后,在 DNS 服务器设定的 TTL 过期时间内不会再次更新,过期后会再次发起解析请求

使用方法

http {
  resolver 8.8.8.8;

  upstream example {
    server example.com resolve;
  }
}

使用这种方法的时候,DNS TTL 时间需要设置短一些。

4 使用模块 ngx_upstream_jdomain

文档地址: domain_resolve

ngx_upstream_jdomain 模块是一个依赖 DNS 解析实现的 upstream 负载均衡,该模式下,允许使用域名来写 upstream 后端。该模块默认情况下,会每秒做一次 DNS 解析,使用方法如下

http {
    resolver 8.8.8.8;
    resolver_timeout 10s;

    upstream backend {
        jdomain www.baidu.com port=80 interval=5; # 每 5 秒解析一次
    }
    server {
        listen  8080;
    
        location / {
            proxy_pass http://backend;
        }
    }
}

5 使用其他版本 Nginx

  • Tengine Tengine 的 ngx_http_upstream_dynamic 模块可以提供动态的 DNS 解析
  • NGINX Plus Plus版本提供了动态解析的语法

在这里我才用了第三种方案,使用模块nginx-upstream-dynamic-servers。

二、容器化编译openresty

大致介绍一下注意点:

  1. 自定义编译参考官方文档:https://github.com/openresty/docker-openresty#building-non-rpm-based

  2. 系统我选用了alpine-3.12版本,RESTY版本1.17.8.2

  3. 在RESTY_CONFIG_OPTIONS中增加了自定义的编译命令:

        --add-module=/tmp/nginx-upstream-dynamic-servers-0.4.0 \
    
  4. 增加这个包的下载解压命令:

        && cd /tmp \
        && curl -fSL https://github.com/GUI/nginx-upstream-dynamic-servers/archive/refs/tags/v0.4.0.tar.gz -o  nginx-upstream-dynamic-servers.v0.4.0.tar.gz \
        && tar zxvf nginx-upstream-dynamic-servers.v0.4.0.tar.gz \
    
  5. 修改了一些其他组件的下载地址,有些链接失效了,例如pcre:

    curl -fSL https://ftp.exim.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz
    
  6. 注意编译最后一步要把下载的东西给清空了,节省空间

编译文件下载。编译文件夹内容如下:

image-20220304121133258

具体dockerfile如下:

# Dockerfile - alpine
# https://github.com/openresty/docker-openresty

ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.12"

FROM ${RESTY_IMAGE_BASE}:${RESTY_IMAGE_TAG}

LABEL maintainer="Evan Wies <evan@neomantra.net>"

# Docker Build Arguments
ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.12"
ARG RESTY_VERSION="1.17.8.2"
ARG RESTY_OPENSSL_VERSION="1.1.1g"
ARG RESTY_OPENSSL_PATCH_VERSION="1.1.1f"
ARG RESTY_OPENSSL_URL_BASE="https://www.openssl.org/source"
ARG RESTY_PCRE_VERSION="8.44"
ARG RESTY_VTS_VERSION="0.1.18"
ARG RESTY_J="1"
ARG RESTY_CONFIG_OPTIONS="\
    --with-compat \
    --with-file-aio \
    --with-http_addition_module \
    --with-http_auth_request_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_geoip_module=dynamic \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_image_filter_module=dynamic \
    --with-http_mp4_module \
    --with-http_random_index_module \
    --with-http_realip_module \
    --with-http_secure_link_module \
    --with-http_slice_module \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_sub_module \
    --with-http_v2_module \
    --with-http_xslt_module=dynamic \
    --with-ipv6 \
    --with-mail \
    --with-mail_ssl_module \
    --with-md5-asm \
    --with-pcre-jit \
    --with-sha1-asm \
    --with-stream \
    --with-stream_ssl_module \
    --with-threads \
    --add-module=/tmp/nginx-module-vts-0.1.18 \
    --add-module=/tmp/nginx-upstream-dynamic-servers-0.4.0 \
    "
ARG RESTY_CONFIG_OPTIONS_MORE=""
ARG RESTY_LUAJIT_OPTIONS="--with-luajit-xcflags='-DLUAJIT_NUMMODE=2 -DLUAJIT_ENABLE_LUA52COMPAT'"

ARG RESTY_ADD_PACKAGE_BUILDDEPS=""
ARG RESTY_ADD_PACKAGE_RUNDEPS=""
ARG RESTY_EVAL_PRE_CONFIGURE=""
ARG RESTY_EVAL_POST_MAKE=""

# These are not intended to be user-specified
ARG _RESTY_CONFIG_DEPS="--with-pcre \
    --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' \
    --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' \
    "

LABEL resty_image_base="${RESTY_IMAGE_BASE}"
LABEL resty_image_tag="${RESTY_IMAGE_TAG}"
LABEL resty_version="${RESTY_VERSION}"
LABEL resty_openssl_version="${RESTY_OPENSSL_VERSION}"
LABEL resty_openssl_patch_version="${RESTY_OPENSSL_PATCH_VERSION}"
LABEL resty_openssl_url_base="${RESTY_OPENSSL_URL_BASE}"
LABEL resty_pcre_version="${RESTY_PCRE_VERSION}"
LABEL resty_config_options="${RESTY_CONFIG_OPTIONS}"
LABEL resty_config_options_more="${RESTY_CONFIG_OPTIONS_MORE}"
LABEL resty_config_deps="${_RESTY_CONFIG_DEPS}"
LABEL resty_add_package_builddeps="${RESTY_ADD_PACKAGE_BUILDDEPS}"
LABEL resty_add_package_rundeps="${RESTY_ADD_PACKAGE_RUNDEPS}"
LABEL resty_eval_pre_configure="${RESTY_EVAL_PRE_CONFIGURE}"
LABEL resty_eval_post_make="${RESTY_EVAL_POST_MAKE}"

RUN apk add --no-cache --virtual .build-deps \
        build-base \
        coreutils \
        curl \
        gd-dev \
        geoip-dev \
        libxslt-dev \
        linux-headers \
        make \
        perl-dev \
        readline-dev \
        zlib-dev \
        ${RESTY_ADD_PACKAGE_BUILDDEPS} \
    && apk add --no-cache \
        gd \
        geoip \
        libgcc \
        libxslt \
        zlib \
        ${RESTY_ADD_PACKAGE_RUNDEPS} \
    && cd /tmp \
    && if [ -n "${RESTY_EVAL_PRE_CONFIGURE}" ]; then eval $(echo ${RESTY_EVAL_PRE_CONFIGURE}); fi \
    && cd /tmp \
    && curl -fSL https://github.com/GUI/nginx-upstream-dynamic-servers/archive/refs/tags/v0.4.0.tar.gz -o  nginx-upstream-dynamic-servers.v0.4.0.tar.gz \
    && tar zxvf nginx-upstream-dynamic-servers.v0.4.0.tar.gz \
    && cd /tmp \
    && curl -fSL https://github.com/vozlt/nginx-module-vts/archive/v${RESTY_VTS_VERSION}.tar.gz -o  nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz \
    && tar xzf nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz \
    && cd /tmp \
    && curl -fSL https://github.com/vozlt/nginx-module-vts/archive/v${RESTY_VTS_VERSION}.tar.gz -o  nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz \
    && tar xzf nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz \
    && curl -fSL "${RESTY_OPENSSL_URL_BASE}/openssl-${RESTY_OPENSSL_VERSION}.tar.gz" -o openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
    && tar xzf openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
    && cd openssl-${RESTY_OPENSSL_VERSION} \
    && if [ $(echo ${RESTY_OPENSSL_VERSION} | cut -c 1-5) = "1.1.1" ] ; then \
        echo 'patching OpenSSL 1.1.1 for OpenResty' \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-${RESTY_OPENSSL_PATCH_VERSION}-sess_set_get_cb_yield.patch | patch -p1 ; \
    fi \
    && if [ $(echo ${RESTY_OPENSSL_VERSION} | cut -c 1-5) = "1.1.0" ] ; then \
        echo 'patching OpenSSL 1.1.0 for OpenResty' \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/ed328977028c3ec3033bc25873ee360056e247cd/patches/openssl-1.1.0j-parallel_build_fix.patch | patch -p1 \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-${RESTY_OPENSSL_PATCH_VERSION}-sess_set_get_cb_yield.patch | patch -p1 ; \
    fi \
    && ./config \
      no-threads shared zlib -g \
      enable-ssl3 enable-ssl3-method \
      --prefix=/usr/local/openresty/openssl \
      --libdir=lib \
      -Wl,-rpath,/usr/local/openresty/openssl/lib \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install_sw \
    && cd /tmp \
    && curl -fSL https://ftp.exim.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz \
    && tar xzf pcre-${RESTY_PCRE_VERSION}.tar.gz \
    && cd /tmp/pcre-${RESTY_PCRE_VERSION} \
    && ./configure \
        --prefix=/usr/local/openresty/pcre \
        --disable-cpp \
        --enable-jit \
        --enable-utf \
        --enable-unicode-properties \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install \
    && cd /tmp \
    && curl -fSL https://openresty.org/download/openresty-${RESTY_VERSION}.tar.gz -o openresty-${RESTY_VERSION}.tar.gz \
    && tar xzf openresty-${RESTY_VERSION}.tar.gz \
    && cd /tmp/openresty-${RESTY_VERSION} \
    && eval ./configure -j${RESTY_J} ${_RESTY_CONFIG_DEPS} ${RESTY_CONFIG_OPTIONS} ${RESTY_CONFIG_OPTIONS_MORE} ${RESTY_LUAJIT_OPTIONS} \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install \
    && cd /tmp \
    && if [ -n "${RESTY_EVAL_POST_MAKE}" ]; then eval $(echo ${RESTY_EVAL_POST_MAKE}); fi \
    && rm -rf \
        nginx-module-vts-${RESTY_VTS_VERSION}.tar.gz nginx-module-vts-${RESTY_VTS_VERSION} \
        openssl-${RESTY_OPENSSL_VERSION}.tar.gz openssl-${RESTY_OPENSSL_VERSION} \
        pcre-${RESTY_PCRE_VERSION}.tar.gz pcre-${RESTY_PCRE_VERSION} \
        openresty-${RESTY_VERSION}.tar.gz openresty-${RESTY_VERSION} \
        * \
    && apk del .build-deps \
    && mkdir -p /var/run/openresty \
    && ln -sf /dev/stdout /usr/local/openresty/nginx/logs/access.log \
    && ln -sf /dev/stderr /usr/local/openresty/nginx/logs/error.log

# Add additional binaries into PATH for convenience
ENV PATH=$PATH:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin

# Copy nginx configuration files
COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY nginx.vh.default.conf /etc/nginx/conf.d/default.conf

CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]

# Use SIGQUIT instead of default SIGTERM to cleanly drain requests
# See https://github.com/openresty/docker-openresty/blob/master/README.md#tips--pitfalls
STOPSIGNAL SIGQUIT

编译命令:

docker build -t kelvinblood/openresty:v3.12.1 .

参考资料


分时与实时操作系统

转自网上的一些资讯。

裸机

没有运行操作系统的计算机称之为“裸机”,操作系统是在裸机上建立的一个最基础的工作环境,为其上运行的各种支撑软件和应用软件提供最基础的系统服务。

设有一个计算任务可分解为输入、处理、打印等三个子任务,为了使它们能并行工作,可引入缓冲技术,即输入子任务从输入设备读一批数据到输入缓冲区,处理子任务把输入缓冲区中的数据处理后放入输出缓冲区,打印子任务打印输出缓冲区中的内容,这样,输入子任务可以与打印子任务并行工作。因为处理器处理数据的速度很快,可以忽略其计算时间,这样就使完成一批数据加工的总时间近似等于较慢的设备输入或输出的时间。

批处理系统

Batch Processing

回想一下计算机历史,当操作系统开始出现的时候,当时的需求是解决人机矛盾及CPU和I/O设备之间速度不匹配的矛盾,此时出现了批处理系统。

在批处理系统中,用户将作业交给系统操作员,系统操作员将许多用户的作业组成一批作业,输入到计算机中,在系统中形成一个自动转接的连续的作业流,然后启动操作系统,系统自动、依次执行每个作业。最后由操作员将作业结果交给用户。

批处理操作系统的主要特点是:脱机、多道和成批处理

脱机是指用户提交作业之后直到获得结果之前几乎不再和计算机打交道。

多道是指按多道程序设计的调度原则,从一批后备作业中选取多道作业调入内存并组织它们运行。

成批处理是指操作员把用户提交的作业组织成一批,由操作系统负责每批作业间的自动调度。

批处理系统自动化程度比较高,系统吞吐量大,资源利用率高,系统开销小,但各作业周转时间长,不提供用户与系统的交互手段,适合大的成熟的作业。

可以看到批处理系统对机器来说资源利用率高,吞吐量大,但对人效率低的系统。问题的根源在于用户无法与系统交互获得反馈。根据操作系统所管理的资源以及所提供服务方式的不同,在此之后的操作系统可以分为两大类型:

  • 分时操作系统 Time Sharing Operating System
  • 实时操作系统 Real Time Operating System,RTOS

实时操作系统

例如:uCOS/VxWorks/RTLinux。

实时操作系统往往是专用的,在特定的应用中作为一种控制系统来使用。实时操作系统的一个主要特点在于有严格的时间限制,即每一个信息接收、分析处理和发送的过程必须在规定的时间内完成。这就要求系统的一切活动都必须在一个严格的计时程序的控制下运行。

  1. 高精度计时系统:计时精度是影响实时性的一个重要因素。在实时应用系统中,经常需要精确确定实时地操作某个设备或执行某个任务,或精确的计算一个时间函数。这些不仅依赖于一些硬件提供的时钟精度,也依赖于实时操作系统实现的高精度计时功能。
  2. 多级中断机制:一个实时应用系统通常需要处理多种外部信息或事件,但处理的紧迫程度有轻重缓急之分。有的必须立即作出反应,有的则可以延后处理。因此,需要建立多级中断嵌套处理机制,以确保对紧迫程度较高的实时事件进行及时响应和处理。
  3. 实时调度机制:实时操作系统不仅要及时响应实时事件中断,同时也要及时调度运行实时任务。但是,处理机调度并不能随心所欲的进行,因为涉及到两个进程之间的切换,只能在确保“安全切换”的时间点上进行,实时调度机制包括两个方面,一是在调度策略和算法上保证优先调度实时任务;二是建立更多“安全切换”时间点,保证及时调度实时任务。

实时操作系统是保证在一定时间限制内完成特定功能的操作系统。实时操作系统有硬实时和软实时之分,

  • 硬实时要求在规定的时间内必须完成操作,这是在操作系统设计时保证的;
  • 软实时则只要按照任务的优先级,尽可能快地完成操作即可。
  • 我们通常使用的操作系统在经过一定改变之后就可以变成实时操作系统。

例如,可以为确保生产线上的机器人能获取某个物体而设计一个操作系统。在“硬”实时操作系统中,如果不能在允许时间内完成使物体可达的计算,操作系统将因错误结束。在“软”实时操作系统中,生产线仍然能继续工作,但产品的输出会因产品不能在允许时间内到达而减慢,这使机器人有短暂的不生产现象。

分时操作系统

例如:Linux/Windows/OSX,基于时间片轮转的操作系统。

分时操作系统允许多个用户同时运行自己的程序。操作系统接收每个用户的服务命令,采用时间片轮转的方式处理用户的服务请求。对每个用户而言,都仿佛自己“占有”了整个计算机。

分时系统具有多路性、独立性、及时性和交互性,与批处理相比,系统开销大,资源利用率与系统接纳的作业有关,适合小的不成熟的作业。批处理和分时是以作业为单位进行处理的系统,是一个通用系统。

多路性是指一台计算机与若干台终端相连接,终端上的这些用户可以同时或基本同时使用计算机;

交互性是指用户的操作方式是联机方式,即用户通过终端采用人-机会话的方式直接控制程序运行,同程序进行交互;

独占性是指由于系统采用时间片轮转的办法使一台计算机同时为许多终端用户服务,因此客观效果是这些用户彼此间都感觉不到别人也在使用这台计算机,好像只有自己独占计算机一样;

及时性是指用户请求能在很短时间内获得响应。

分时系统和实时系统的比较

img

实时操作系统,它是可抢占性的内核。高优先级任务就绪而低优先级任务正在执行没有sleep的时候,高优先级任务会打断低优先级任务而立即得到执行。如图,当优先级更高的任务2就绪的时候,即便任务1正在运行中,也必须立刻交出CPU的使用权,就跟中断一样,先执行任务2,等任务2执行完或者主动挂起(sleep)让出CPU的时候,任务1才能接着运行。

img

在分时操作系统中,CPU是不可抢占的,即便高优先级的任务就绪了,也不能马上中断低优先级任务而得到执行,必须要等到低优先级任务主动挂起(sleep)或者时间片结束才能得到执行。

分布式计算、平行计算

并行计算(Parallel Computing)

  并行计算是相对于串行计算来说的。并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程。为执行并行计算,计算资源应包括一台配有多处理机(并行处理)的计算机、一个与网络相连的计算机专有编号,或者两者结合使用。并行计算的主要目的是快速解决大型且复杂的计算问题。

  并行计算可以划分成时间并行和空间并行。时间并行即流水线技术,空间并行使用多个处理器执行并发计算,当前研究的主要是空间的并行问题。以程序和算法设计人员的角度看,并行计算又可分为数据并行和任务并行。数据并行把大的任务化解成若干个相同的子任务,处理起来比任务并行简单。

  空间上的并行导致两类并行机的产生,按照Michael Flynn(费林分类法)的说法分为单指令流多数据流(SIMD)和多指令流多数据流(MIMD),而常用的串行机也称为单指令流单数据流(SISD)。MIMD类的机器又可分为常见的五类:并行向量处理机(PVP)、对称多处理机(SMP)、大规模并行处理机(MPP)、工作站机群(COW)、分布式共享存储处理机(DSM)。

分布式计算(Distributed Computing)

  分布式计算这个研究领域,主要研究分散系统(Distributed system)如何进行计算。分散系统是一组计算机,通过计算机网络相互链接与通信后形成的系统。把需要进行大量计算的工程数据分区成小块,由多台计算机分别计算,在上传运算结果后,将结果统一合并得出数据结论的科学。

  目前常见的分布式计算项目通常使用世界各地上千万志愿者计算机的闲置计算能力,通过互联网进行数据传输。如分析计算蛋白质的内部结构和相关药物的Folding@home项目,该项目结构庞大,需要惊人的计算量,由一台电脑计算是不可能完成的。即使现在有了计算能力超强的超级电脑,但是一些科研机构的经费却又十分有限。

分布式计算比起其它算法具有以下几个优点:

  1. 稀有资源可以共享。
  2. 通过分布式计算可以在多台计算机上平衡计算负载。
  3. 可以把程序放在最适合运行它的计算机上。其中,共享稀有资源和平衡负载是计算机分布式计算的核心思想之一。

并行计算与分布式计算的区别

并行计算与分布式计算都是运用并行来获得更高性能,化大任务为小任务。简单说来,如果处理单元共享内存,就称为并行计算,反之就是分布式计算。也有人认为分布式计算是并行计算的一种特例。

分布式的任务包互相之间有独立性,上一个任务包的结果未返回或者是结果处理错误,对下一个任务包的处理几乎没有什么影响。因此,分布式的实时性要求不高,而且允许存在计算错误(因为每个计算任务给好几个参与者计算,上传结果到服务器后要比较结果,然后对结果差异大的进行验证。

分布式要处理的问题一般是基于寻找模式的。所谓的寻找,就相当于穷举法!为了尝试到每一个可能存在的结果,一般从0~N( 某一数值)被一个一个的测试,直到我们找到所要求的结果。事实上,为了易于一次性探测到正确的结果,我们假设结果是以某个特殊形式开始的。在这种类型的搜索里,我们也许幸运的一开始就找到答案;也许不够走运以至于到最后才找到答案,这都很公平。

并行程序并行处理的任务包之间有很大的联系,而且并行计算的每一个任务块都是必要的,没有浪费的分割的,就是每个任务包都要处理,而且计算结果相互影响,就要求每个的计算结果要绝对正确,而且在时间上要尽量做到同步。

分布式的编写一般用的是C++(也有用JAVA的,但是都不是主流),基本不用MPI接口。并行计算用MPI或者OpenMP。

集群计算、超算

集群计算(Cluster Computing)

计算机集群将一组松散集成的计算机软件或硬件连接起来高度紧密地协作完成计算工作。在某种意义上,他们可以被看作是一台计算机。集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式。集群计算机通常用来改进单个计算机的计算速度和/或可靠性。一般情况下集群计算机比单个计算机,比如工作站或超级计算机性价比要高得多。

根据组成集群系统的计算机之间体系结构是否相同,集群可分为两种。

  • 同构
  • 异构

集群计算机按功能和结构可以分为:

  • 高可用性集群(High-availability (HA) clusters)、
  • 负载均衡集群(Loadbalancing clusters)、
  • 高性能计算集群(High-performance (HPC)clusters)、
  • 网格计算(Grid computing)。

高可用性集群,一般是指当集群中有某个节点失效的情况下,其上的任务会自动转移到其他正常的节点上。还指可以将集群中的某节点进行离线维护再上线,该过程并不影响整个集群的运行。

负载均衡集群,负载均衡集群运行时,一般通过一个或者多个前端负载均衡器,将工作负载分发到后端的一组服务器上,从而达到整个系统的高性能和高可用性。这样的计算机集群有时也被称为服务器群(Server Farm)。一般高可用性集群和负载均衡集群会使用类似的技术,或同时具有高可用性与负载均衡的特点。Linux虚拟服务器(LVS)项目在Linux操作系统上提供了最常用的负载均衡软件。

高性能计算集群,高性能计算集群采用将计算任务分配到集群的不同计算节点儿提高计算能力,因而主要应用在科学计算领域。比较流行的HPC采用Linux操作系统和其它一些免费软件来完成并行运算。这一集群配置通常被称为Beowulf集群。这类集群通常运行特定的程序以发挥HPC cluster的并行能力。这类程序一般应用特定的运行库, 比如专为科学计算设计的MPI库。HPC集群特别适合于在计算中各计算节点之间发生大量数据通讯的计算作业,比如一个节点的中间结果或影响到其它节点计算结果的情况。

网格计算,通过利用大量异构计算机的未用资源(CPU周 期和磁盘存储),将其作为嵌入在分布式电信基础设施中的一个虚拟的计算机集群,为解决大规模的计算问题提供一个模型。网格计算的焦点放在支持跨管理域计算 的能力,这使它与传统的计算机集群或传统的分布式计算相区别。网格计算的目标是解决对于任何单一的超级计算机来说仍然大得难以解决的问题,并同时保持解决 多个较小的问题的灵活性。这样,网格计算就提供了一个多用户环境。

参考资料