Carlmartin' Blog

In me the tiger sniffs the rose.

起因

之前逛技术博客的时候, 看了一个kubectl-debug介绍, 可以使用外部的工具, 来处理容器内部的信息, 这个能力非常有用.

因为容器制作的时候有个原则就是容器尽量的小, 导致基础镜像上连一些基础的命令都没有. 例如vi, ping这些基本的命令, 都可能要自己安装, 但是很多云环境上, 又没法正常的访问互联网, 导致严重浪费时间.

技术

实现原理说起来很简单, 就是用到容器注入的方式处理, 假设你已经启动了一个TARGET_CONTAINER容器, 它的ID为TARGET_ID, 你可以将busybox的镜像注入到TARGET_CONTAINER里面, 此时容器空间内的命令为busybox镜像所提供的, 但是网络或者进程空间全是TARGET_CONTAINER

1
2
3
export TARGET_ID=666666666
# 加入目标容器的 network, pid 以及 ipc namespace
docker run -it --network=container:$TARGET_ID --pid=container:$TARGET_ID --ipc=container:$TARGET_ID busybox

这个技术点确实很牛逼, 之前都不了解, 后面在kubernete上的实现, 就顺理成章了, 只需要通过API接口将需要的TARGET_ID查询出来, 注入镜像即可

总结

目前看这个kubectl-debug只是个人项目, 可能会有一些场景支持的并不好, 特别是各个云上的安全系统. 所以有需要可以拿过来改改代码试用一下, 如果偶尔使用的话, 直接在kubernete的节点上使用容器注入会更快和可控一点.

阅读全文 »

总览

Pipeline在Kubeflow里面是一个最重要的能力, 因为需要它来串流整个机器学习任务的组件.
因此我们首先介绍一下pipeline的定义: 它是一个工作流平台,能够编译部署机器学习的工作流, 可以定义复杂的数据DAG流程, 并提供可视化的流程展示和结果展示.

核心概念

pipelines实现了一个工作流模型。所谓工作流,或者称之为流水线(pipeline),可以将其当做一个有向无环图(DAG)。其中的每一个节点,在pipelines 的语义下被称作组件(component)。组件在图中作为一个节点,其会处理真正的逻辑,比如预处理,数据清洗,模型训练等等。每一个组件负责的功能不同,但有一个共同点,即组件都是以 Docker 镜像的方式被打包,以容器的方式被运行的。这也是与 kubeflow 社区的 Run ML on Kubernetes 这一愿景相统一的。

实验(experiment)是一个工作空间,在其中可以针对流水线尝试不同的配置。运行(run)是流水线的一次执行,用户在执行的过程中可以看到每一步的输出文件,以及日志。步(step)是组件的一次运行,步与组件的关系就像是运行与流水线的关系一样。步输出工件(step output artifacts)是在组件的一次运行结束后输出的,能被系统的前端理解并渲染可视化的文件。

Kubeflow Pipeline中概念列表:

  1. Pipeline: 定义一组操作的流水线,其中每一步都由component组成。 背后是一个Argo的模板配置
  2. Component: 一个容器操作,可以通过pipeline的sdk 定义。每一个component 可以定义定义输出(output)和产物(artifact), 输出可以通过设置下一步的环境变量,作为下一步的输入, artifact 是组件运行完成后写入一个约定格式文件,在界面上可以被渲染展示。
  3. Graph: 就是上面看到流程图, 一个pipeline可以转化为一个DAG图
  4. Experiment: 可以看做一个工作空间,管理一组运行任务
  5. Run: 真实任务, pipeline真正在K8s上实例化的产物, 会启动多个对应的Pod, 开始真正的计算
  6. Recurring Run: 定时任务, 可以由Run Trigger触发
  7. Step: Component对应实体, 就是上图之中的方框, 应该是一个Step会真实对应一个K8s的Pod

官方案例

官方的XGBoost - Training with Confusion Matrix案例:

阅读全文 »

缓存读

缓存更新

缓存并发问题

缓存系统存在根本的问题是缓存的读写和数据库读写不是原子的, 因此它必然会出现并发的问题.

缓存并发解决思路

引入全局锁

例如Redis就有锁机制, 通过redis实现全局锁(行锁), 更新的时候设置排它锁, 不允许读取操作即可.

这就和数据库之中的悲观锁是一个性质的, 这种系统最大的问题就是吞吐量限制, 每次必须查询锁的状态

引入消息队列

或者使用乐观锁的实现方式, 就是引入消息队列, 消息队列相对于全局锁的优势在于:

  1. 可以合并一部分的更新操作, 例如2次更新之间没有任何读取, 就可以将更新合并
  2. 可以和流控系统结合, 消息队列可以用于请求的流控, 通过流控系统可以实现缓存读取的分布式化

缺点就是, 系统架构越来越复杂了, 流控系统的可靠性成为系统的关键.

阅读全文 »

什么是Kubeflow

对于官网的定义:

The Kubeflow project is dedicated to making deployments of machine learning (ML) workflows on Kubernetes simple, portable and scalable. Our goal is not to recreate other services, but to provide a straightforward way to deploy best-of-breed open-source systems for ML to diverse infrastructures.

我们可以看出kubeflow是在Kubernetes之上构建Machine Learning的项目, 他本身不会创建任何AI或者Kubernetes的服务, 而是为了Machine Learning项目构建的更加简单, 更加可扩展.

为了更好的学习Kubeflow, 我们需要有以下的基础知识:

  1. 容器技术, 包含docker使用, 镜像制作, Kubernetes 任务提交等一系列的Paas能力
  2. AI技术, 包括各种AI框架, 以及分布式AI模型等
  3. Python语言, kubeflow的代码库大多以Python编写

Kubeflow有什么

Kubeflow有很多的组件, 可以在官网文档的Components模块之中找到所有能力组件, 我把这些模块整理了一下, 画出脑图, 如下:

阅读全文 »

HostPath挂载

容器启动时, 挂载/var/run/docker.sock和/usr/bin/docker,即可在容器中执行docker命令。此时docker server仍运行在host机上,docker in docker 实际操作的是宿主机docker。

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
30
31
32
33
34
kind: Deployment
apiVersion: apps/v1
metadata:
name: docker-in-docker-mount
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: docker-in-docker-mount
spec:
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: ''
- name: docker-cmd
hostPath:
path: /usr/bin/docker
type: ''
containers:
- name: container-0
image: 'ubuntu-docker-in-docker:latest'
command:
- /bin/bash
args:
- '-c'
- 'echo hello;docker image ls'
volumeMounts:
- name: docker-socket
mountPath: /var/run/docker.sock
- name: docker-cmd
mountPath: /usr/bin/docker

docker dind

docker 官方提供了docker in docker镜像: docker pull docker:18.09.7-dind, 直接使用此镜像即可在容器中在运行容器. 但是此种方式运行权限需要为特权容器, 在K8s设置securityContext.privileged为true

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
kind: Deployment
apiVersion: apps/v1
metadata:
name: dind-test10
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: dind-test10
template:
metadata:
labels:
app: dind-test10
spec:
containers:
- name: container-0
image: 'docker:18.09.7-dind'
command:
- /bin/sh
args:
- '-c'
- 'echo hello;docker image ls'
securityContext:
privileged: true
procMount: Default

两者比较

比较项 HostPath Dind
安全性 中, docker命令可以注入宿主机之中 低, 特权容器所有权限开放, 不能有用户代码存在容器之中
简便性 中, 需要额外设置HostPath 高, 配置简单, 一键使用
并发性 高, 可以用于任何容器 低, 只能基于Dind基础镜像之上构做镜像
阅读全文 »

首先, 官网上有对应的安装文档, 地址在这里官方安装指南.

但是在国内总是有一些中国特设的问题, 所以在这儿记录一下安装的流程.

安装的环境是在华为云的云容器引擎服务CCE, 其他环境可能略有不同.

此外华为云上已有一个KubeFlow安装指南

依赖安装

首先安装官方文档, 安装如下的三个依赖:

  1. kubectl
  2. ks
  3. kfctl

将这三个依赖都放入到环境之中, kubectl需要设置好环境, kubectl get pod不能有一次

1
mv ks kubectl kfctl /usr/local/bin/

我安装的是v0.5版本的kubeflow, 版本升级之后不保证成功

阅读全文 »

最近想优化一下业务代码之中的任务调度模块, 我把整体需求理了理, 准备重头开始设计一下.

请听需求:

在业务系统里面, 任务提交是一个非常常见的场景, 下面是我提炼的业务系统任务的几个特点:

  1. 任务运行时间较长, 可能会超过一个小时, 肯定会有不同的状态
  2. 任务会有不同类型, 每个类型之间会有一定关联, 但是差别也很多
  3. 一个任务可能会有多个子任务: 子任务是不可再分的
  4. 每个子任务或者任务都可能会失败, 需要进行任务重试, 重试要遵循幂等设计
  5. 子任务会连接其他系统, 中间有可能会有超时异常, 要防止任务堆积
  6. 这里假设任务提交速率不高, 可以单机处理

问题如下, 请用伪代码描述:

  1. 设计一个框架来实现该功能, 详细描述里面用到的设计模式
  2. 如果提交速率提高到100个请求/s, 需要分布式化, 请问如何设计
阅读全文 »

从Docker说起

在Docker之中有两个命令行入口定义: ENTRYPOINTCMD. 两者都是定义容器的启动命令, 两个定义方式也是相同的, 都是一个字符串数组, 类似于

1
2
ENTRYPOINT ["sh", "/opt/entrypoint.sh"]
CMD ["sh", "/opt/entrypoint.sh"]

两者的区别在于, 执行docker run后面命令行的时候, CMD的命令直接被覆盖了, 而ENTRYPOINT还依然会被执行

如果想覆盖ENTRYPOINT, 在docker run的时候需要显示指定--entrypoint

而且通常情况下, 我们会将ENTRYPOINTCMD联合使用, 类似这样:

1
2
ENTRYPOINT ["sh", "/opt/entrypoint.sh"]
CMD ["/home", "/opt"]

这种情况下, DOCKERFILE直接定义的入口脚本为sh /opt/entrypoint.sh, 但脚本的参数有CMD提供, 用户执行docker run的时候可以通过修改输入, 直接改变容器启动命令参数.

K8s的命令参数

阅读全文 »

近段时间接触了基因比对算法, 业界最常使用的是BWA算法, 我现在还不了解具体如何实现的, 这里只是准备把算法用计算机的语言描述一下.

请听题:

假设有一长字符串, 有以下特征:

  1. 字符串长度大约为30亿
  2. 所有字符由以下五种组成: ATGCN, 前面为4钟碱基, 最后一个为未知碱基
  3. 该字符串为确定字符串, 即所有位置都已经正确

另外有一短字符串, 短字符串有如下特性:

  1. 长度为100或者150左右的固定长度字符
  2. 字符串也有ATGC组成
  3. 由实验误差原因, 已知该字符串每个位置都可能出现p的概率误差, 称之为测序误差
  4. 由于生物学的缘由, 会出现字符出错, 也有出现字符丢失, 或者字符增加, 这种误差被称之为突变误差

此外, 还有一点:

  1. 短字符串比较多, 可能长字符串同一个位置会有段短字符串匹配, 也可能没一个匹配到的

  2. 短序列的起始和结束位置是不固定,

  3. 目前的高级的测序仪器, 平均所有短序列的覆盖深度为50X, 即总共的字符为30亿*50, 如果短字符长度为100的话, 就有30亿*50/100 = 15亿条.

问题:

阅读全文 »

缘起

之前一直在做Spark相关工作, 主要就是做分布式计算相关的内容, 经常会听到一些BSP或者MPP等分布式模式的术语, 每次看过文章有些了解之后, 但是经常会忘记, 因此写个文章记录这些概念.

BSP/ASP/SSP

首先要明确的是, 这三个概念主要是为了处理机器学习领域迭代计算提出来的

BSP是指迭代过程之中, 必须等待前一轮的迭代全部才能进行下一轮, 每轮之间的等待,被称之为Barrier, 所以才叫做Barrier Synchronous Parallel


ASP: Asynchronous Synchronous Parallel是另外一个极端的方式, 任何一轮迭代绝对不会等待前面的迭代结果, 这个当然能解决BSP模型里面慢节点的问题, 但是它存在的问题就是速度不一,导致最后的梯度不收敛

那么SSP: Stale Synchronous Parallel就是这两者的折中, 他有一个超参s, 表示最快的迭代和最慢的迭代之间的代差要小于等于S.

我们经常听说Spark或者MapReduce是一个BSP模型, 原因在于Spark的实际计算只有一轮迭代, 一轮迭代就需要直接出最终结果, 那么只有BSP才能正确计算完毕.

所以说, Spark是BSP的一种, 这种说明既对, 他确实有栅栏, 但也不对, 在于它主要描述分布式机器学习流程.

至于为什么机器学习那种多轮迭代为什么可以进行SSP或者ASP计算, 具体的数学原理可以查看如何理解随机梯度下降

细节的内容可以看这篇博客, 写的不错, 当然最好直接看论文

SMP/NUMA/MPP

这三个概念主要出现在计算机体系结构之中, 主要将多核CPU如何实现并行计算的.

  • SMP:对称多处理器结构(Symmetric Multi-Processor)

  • NUMA:非一致存储访问结构(Non-Uniform Memory Access)

这两个经常在课文里面见到, 大学里面也学过, 大致的体系结构如下图所示:


SMPNUMA都是单机多核, MPP我理解就应该多台机器了

MPP:和NUMA不同,MPP提供了另外一种进行系统扩展的方式,它由多个SMP服务器通过一定的节点互联网络进行连接,协同工作,完成相同的任务,从用户的角度来看是一个服务器系统。其基本特征是由多个SMP服务器(每个SMP服务器称节点)通过节点互联网络连接而成,每个节点只访问自己的本地资源(内存、存储等),是一种完全无共享(Share Nothing)结构,因而扩展能力最好,理论上其扩展无限制。

可能的示意图如下所示:

除了体系结构, 这三个概念还经常用于描述数据库的不同架构, 例如:

SMP是Shared Everthting的方式

NUMA是Shared Storage的方式

MPP是Shared Nothing的方式

按照这类分法, Spark是数据Shared Storage的方式, 因此数据放在HDFS可以共享获取.

MPP架构有如下特点:

  • Share Nothing、节点之间数据不共享,只有通过网络连接实现的协同
  • 每个节点有独立的存储和内存
  • 数据根据某种规则(如Hash)散布到各个节点
  • 计算任务也是会发布到各个节点并行执行,最后再将结果聚合到整体返回
  • 用户使用时会看做整体
  • MPP数据库(如GreePlum)往往优先考虑C一致性,然后是A可用性,最后考虑P分区容忍
  • MPP架构目前被并行数据库广泛采用,一般通过scan、sort和merge等操作符实时返回查询结果

MPP架构劣势

  • 很难高可用 -> 影响可用性和可靠性 因为数据按某种规则如HASH已经散布到了各个节点上。
  • 节点数 =任务并行数 -> 影响扩展性 一个作业提交时,每个节点都要执行相同任务。而不像MapReduce那样做了根据实际开销进行任务拆分后散发到有资源的几个节点上。这一点大大影响了MPP架构应用的可扩展性。
  • 每个客户端同时连接所有节点通信 -> 影响网络 MPP架构每个节点独立,所以客户端往往需要连接所有节点进行通信,这使得网络也成为瓶颈。
  • 分区容错性差 前面提到过MPP主要考虑CA,最次才是P。那么一旦扩展节点太多后,元数据管理十分困难。

MPP 适用场景

  • 集群规模100以内、并发小(50以下)
  • MPP架构目前被并行数据库广泛采用,一般通过scan、sort和merge等操作符实时返回查询结果

MPP的典型架构

参考博客1, 博客2, 博客3

MPP数据库/Hadoop数据库

这个博客 介绍了MPP和Spark数据库的差别, 并提出现在MPP和Batch类数据库的融合, 文章写的很流畅, 读就是了.

另外特别的要提一下Impala, 这个系统之前做Spark SQL的时候, 和它对标过: 之前团队想要使用Spark SQL替代Impala. 但效果肯定不理想, MPP数据库的时延确实比Spark好太多 了.

这篇介绍Impala的文章不错, 可以好好看一下

这个章节, 回头再理理, 需要详细写一下

Poll/Push模式

这个是Shuffle处理的概念, 经常出现在流处理系统的概念表里面, 例如Kafka/Flink.
在Spark之中, Poll是指ReduceTask主动去拉Shuffle的数据, 这种模式容错比较好处理, 数据丢失之后主要重试计算就好了.
Push模式是指将MapTask主动将数据push到ReduceTask的节点上,但是我们实际上在MapTask时候比较难以估计ReduceTask位置, 尤其在节点丢失情况下, 所以要实现push模式, 编程量会很多.

而在Kafka之中, Push和Poll区别主要在于Consumer是主动获取数据, 还是被动接收数据.

这个概念还是比较容易理解的.

总结

总体的文章有点乱, 概念越看越模糊, 后续再优化吧.

阅读全文 »
0%