setup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
curl -O https://repo.mongodb.org/apt/ubuntu/dists/bionic/mongodb-org/4.4/multiverse/binary-amd64/mongodb-org-server_4.4.30_amd64.deb

# 下载 .deb 文件
wget https://repo.mongodb.org/apt/ubuntu/dists/bionic/mongodb-org/4.4/multiverse/binary-amd64/mongodb-org-server_4.4.30_amd64.deb

https://repo.mongodb.org/apt/ubuntu/dists/bionic/mongodb-org/4.4/multiverse/binary-amd64/mongodb-org-mongos_4.4.30_amd64.deb

# 尝试安装(可能需要强制依赖)
sudo wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb

sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb

sudo dpkg -i mongodb-org-server_4.4.30_amd64.deb

# bring up mongo server

sudo mongod --dbpath /data/db --port 27017 --logpath /data/db/mongd.log --fork

# shell installation

sudo wget https://repo.mongodb.org/apt/ubuntu/dists/bionic/mongodb-org/4.4/multiverse/binary-amd64/mongodb-org-shell_4.4.30_amd64.deb

sudo dpkg -i mongodb-org-shell_4.4.30_amd64.deb


# bring up mongo shell

mongo

shell scripting

scala sdk

Problem

Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarray of A.

Since the answer may be large, return the answer modulo 10^9 + 7.

Solution

解题思路

本体的解题方法有多种,不同的解题思路具有不同的时间复杂度。

O(n^2)复杂度解法

此解法是一个简单可行的的算法,具有很小的实现难度,本文在此只略微讲述该算法的设计思路,由于该算法时间复杂度较高,不能在时间限制内跑完所有的Leetcode所有test case,不推荐使用。

本算法中引入两个索引,分别从0n-1,和in-1进行遍历,每次遍历更新当前子序列的最小值并加入最终和中,即可得出求和。还有一个细节需要注意的是,由于数列的最小值和是一个很大的数字,可能会超出int的数值范围(-2^31 ~ 2^31)),所以需要在循环体中增加对int MAX值/modulo值的比较,保证没有溢出造成结果错误。

另一个O(n^2)复杂度解法

本体也可以用动态规划的思路进行解题。动态规划采用的思想是归纳法思想,将第i规模的问题化简成第i-1规模的问题,由此递推能将问题层层迭套从而减少计算的时间复杂度。 通过公式推导,不难得出,本题长度为n的数列A的解集可以拆分为如下子解集的并集:

1
2
f(n) = N(0) U N(1) U ... U N(n-1),
其中N(i)为以A[i]为后缀的所有子序列的min值之集合。

对于N(i)的求解,可以通过如下递归关系得到:

1
2
N(i) = { A(i), min(N(i-1), A(i)) }
即包含A(i), N(i-1)中所有元素与A(i)取min值后的集合。

本算法不是最佳解法,实际的比较次数还是O(n^2)复杂度。

O(n)复杂度解法

要想减少元素的比较次数,必须将连续子数组的特性发挥到极致。Leetcode提出了一种寻找以A[i]为最小元素的子数组计数法,也就是说,找到A数组中以每个元素为最小值的子数组个数通过加权求和,就能算出最终答案。

为了找到A数组中以每个元素为最小值的子数组个数,只需要维护一个长度与A等长的数组即可。经过一次遍历,便可以将数组中各个子数组最小值计数完成。因而本算法的时间复杂度为O(n)。

程序设计

本题的算法的关键

实现技巧

微服务是可以快速构建、修改和部署到独立生产环境中的小型代码单元。可以快速进行迭代开发和交付,从而部署应该也具有如下特征:

  • 自动的——部署应该是能全部自动化的。
  • 可重复的——部署流程是可以重复的,不因开发人员或环境变化而影响
  • 完整的——部署成果应该是一个完整的虚拟机或者容器镜像(Docker),能够自包含运行
  • 不可变的——服务镜像一旦构建运行时配置不应该被修改,修改应该从代码提交开始

云原生——Docker容器技术

容器是镜像的运行时实例。容器虚拟化操作系统资源,容器引擎划分操作系统资源(比如进程树,文件系统,网络栈等),将其打包到成为容器的虚拟操作系统中,运行一个应用。
容器技术不同于Hypervisor技术,后者将物理资源划分为虚拟机的虚拟版本,前者将操作系统本身划分为容器的虚拟版本。

容器镜像构建

Dockerfile是镜像构建的描述文件,以易于阅读的格式准确描述了应用及其依赖。Dockerfile由一系列指令组成,每条指令构建镜像的一层。镜像构建的基础目录就是Dockerfile所在的目录。

Dockerfile的构建指令包括:

  • FROM:指定基础镜像
  • RUN:在容器中执行命令
  • COPY:复制文件到容器中

元数据指令包括:

  • MAINTAINER:镜像作者
  • LABEL:镜像标签
  • EXPOSE:容器对外暴露的端口
  • ENV:环境变量
  • ENTRYPOINT:容器启动时执行的命令
  • CMD:容器启动时执行的命令
  • VOLUME:容器数据卷

Docker镜像的构建是分层叠加文件系统的过程,每条指令构建一层,镜像构建完成后,可以运行容器。文件是增量叠加的,删除上层镜像中的文件目录并不能真正的删除文件本身,而是在顶层layout中将文件隐藏,所以镜像文件并不能真正的变小。

  • docker inspect命令可以查看镜像的构建过程,包括每一层构建的layer文件和指令。
  • docker build命令可以逐行解析运行dockerfile构建镜像。
  • docker history命令可以查看构建镜像的所有指令。

多段构建

多段构建有多个FROM命令,每一个FROM命令都会构建一个WORKINGDIR,以及一个独立的镜像,这为灵活运用镜像构建WORKSPACE提供了能力,甚至最终的运行时镜像可以引用完全不同的净化的base image,从而构建出与开发环境完全不同的运行时镜像。

同时也可以用 –target prod-client -f Dockerfile-final来灵活指定构建生产环境的客户端镜像。

容器网络栈虚拟化

Docker网络是基于容器网络模型的开源可插拔架构。libnetwork是CNM的实现,提供了docker的核心网络能力。Linux OS层面提供网络虚拟化的基础是VLAN,这是对eth0的拆分,每个VLAN都是一个独立的虚拟网络绑定到eth0.100等等,每个VLAN的流量都是隔离的,这是因为网桥间的隔离。Docker网络虚拟化基于VLAN,但是VLAN的隔离粒度是二层,而Docker网络虚拟化可以支持三层隔离,即每个容器可以拥有独立的IP地址,从而实现容器之间的子网隔离,也就是说在VLAN内部,即使可以将容器放在不同的子网段,保证网络间的相互通信。

VLAN

对于操作系统能L2的链路设计,是基于802.11Q扩展协议,让网卡从硬件上支持虚拟化,从而实现VLAN的隔离。VLAN不直连,并不代表两边的容器不同相互通信,如果VLAN是连向公网的,就可以通过公网通信。

VNET

虚拟子网一般是一个私网,类似于一个k8s cluster的所有容器都会在同一个VNET中,对于集群向外的通信,不要一个网关(也就是路由器)同时拥有私网IP(一般是网关IP)和公网IP(普通IP)从而可以建立路由规则,将私网向外访问的流量转发到网关,转发出去。类似于cluster的Egress IP。Ingress则是负载均衡的入口,对于外网的客户端,需要访问cluster内部的应用,必须通过Ingress负载均衡反向代理流量进入容器,从而达到通信的目的,客户端只能发现到Ingress的IP。

容器运行时

runc是开放容器计划OCI运行时规范的实现。它的任务是与底层OS交互,启动和停止容器,docker每个容器都是runc创建的。OCI包括镜像规范,运行时规范,分发规范。

containerd管理容器的生命周期,包括拉取镜像和管理runc实例。

dockerd执行更高级别的任务,如暴露docker API,管理镜像,管理卷,管理网络等。

flowchart TD;

    A[runc内核级工作] --> B[containerd容器生命周期管理]
    B --> C[Docker守护进程CLI/API/Image/Network/Storage]

云原生——K8S容器编排技术

k8s

无服务器架构——基于容器的自动化构建和部署管道

Helm–K8S容器打包技术

HelmChart

Helm是一种业界常用的容器打包技术,通过templates方式定义了一个服务所需要的资源定义。

FluxCD–容器部署技术

FluxCD是gitops repo的执行程序,以函数定义形式定义了定义每一个helm chart的部署定义,但是以目前的FluxCD集成设计模式,是更加机械的容器provision能力,而并没有提供更加灵活的容器阶段式定义。资源映射的的过程更像是资源展开的过程,从Kustomization=>HelmChart=>HelmRelease=>K8S RD的映射过程。

Ansible Tower–OS自动化部署技术

Ansible是Ansible Automation Platform的简称,提供了灵活的自动化部署过程设计,基本的可部署单元是Ansible Playbook,而不同组需要灵活管理的是自己的playbook repo。而本repo的git tag正是决定了该release的版本,从而能够解耦平台playbook和team playbook的版本发布周期。

0%