Moosefs Master 高可用实现

我自己设计了一套简陋的k8s persistentvolumeclaims方案,后端采用Moosefs做为分布式数据存储,原理是基于kubernetes events机制,当接收到create pvc的消息时,后台control应用会在moosefs上创建对应的pv,并绑定相应的pvc,为了方便应用在各个节点间移动,我将moosefs文件系统挂载到了每一个worker节点下,这里就产生了一个问题:如何保证moosefs master高可用!moosefs官方有两个版本一个是opensource,另外一个是Pro,Pro版本自带HA功能,而opensource只有备份master的功能,当出现故障时只能通过手动恢复master。为了满足高可用的需求,我申请了Pro版本为期一个月的使用权限,购买永久授权官方价格是1425EUR/10TBi,其中包括了一年的维护费570EUR,这个价格对于我个人使用Raspberry Pi来说实在过于昂贵,并且我测试了mfsmaster pro的性能,发现和opensource版本相比没有显著的提升,考虑到mfsmaster是单线程应用,我决定以后自己维护一套mfs源码,增加它在kubernetes上的功能。这样经过调研,我发现了mfs master高可用的方案(上图所示)。 MFS Opensource Master HA 总共分为三部分: mfsmaster DRBD Keepalived mfsmaster:存储mfs的元数据。 DRBD:实现网络层块设备的实时复制,类似RAID 1。 Keepalived:监控两台mfsmaster的健康状况。 当mfsmaster A出现异常时,keepalived会将VIP迁移到mfsmaster B上,并将A由原先的master变成backup,同时卸载mfs metadata的DRBD USB磁盘,将B由原先的backup变成master,同时挂载mfs metadata的DRBD USB磁盘,启动mfsmaster,这样就完成了故障节点的恢复。 在使用moosefs之前,我测试过openebs,longhorn,beegfs,glusterfs这些分布式文件系统,对比了它们之间的性能和易用性,最终还是选择了moosefs,因为mfs的扩展实在是太方便了,并且客户端是通过fuse访问文件系统,像macos,freebsd,netbsd都可以使用,在ARM64平台上的读写性能也是优于其他几个分布式文件系统的。当然最后的缺点是官方好像停止维护mfs v3版本了(github一直没有更新),v4版本仍然处于闭源状态。

November 23, 2022

记录sparkpool的时光

2018年我以Devops的职位加入了sparkpool团队之后,扩宽了我对数字加密货币的认知,在这接近四年的工作中,我在sparkpool学习了数字金融与传统金融体系的相关知识,什么是健全的货币体系,加密货币与传统货币的区别,可以这么说,在sparkpool我学到了大量的金融知识,同时也在工作之余自学了前沿科技的相关技术,比如深度学习和量化交易,虽然自己还没有做出一套完整的相关产品,但我一直在朝着这个方向努力。非常庆幸自己能够加入sparkpool大家庭,在此感谢sparkpool的两位创始人。最后的最后,聚是一团火,散是满天星。

May 11, 2022

TIDB 架构

Reference TIDB architecture 为什么使用 TIDB 机器采用的架构是ARM64。 尝试使用分布式数据库架构。 解决高可用问题,当一台Raspberry Pi数据库节点宕机时,不会影响数据的写入。 对比了vitess和TIDB,TIDB更加兼容ARM64,容易上手实验。 为后面的金融交易系统作准备。 架构 组件及功能 TIDB Server TIDB Server 是一个无状态应用,它本身并不存储数据,前面可以放置负载均衡,外部应用请求到TIDB Cluster中的节点,TIDB server将分析和计算应用请求的SQL,并将请求转发给底层的数据存储TiKV。 PD Server 整个TiDB集群的元信息管理模块,存储每个TiKV节点的数据分布情况,以及集群的整体拓扑情况,根据TiKV节点实时上报的数据分布状态,PD server向TiKV节点发布数据调度命令。 Storage Server TiKV 负责数据存储,是一个提供事务的key-Value分布式存储引擎,存储的基本单位是Region,每个Region存储一个Key Range的数据,每个TiKV节点会负责多个Region,TiDB的SQL对SQL做完解析后,会将SQL的执行计划转化为对TiKV API的实际调用,所有的SQL数据全部存储在TiKV中。 TiFLASH Server 特殊的存储节点,数据存储是以列式的方式进行存储,主要功能式为分析型的场景加速。

January 4, 2022

Volcano高性能引擎

简介 volcano是一个用于高性能工作负载场景下基于kubernets的容器批量引擎。 应用场景: 机器学习以及深度学习 生物以及基因计算 大数据应用 概念 Queue 容纳一组podgroup的队列 apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: distcc spec: weight: 1 reclaimable: false capability: cpu: 50 字段: weight -> 该queue在集群资源划分中所占有的比例,该queue占用的资源比例为: (weight / total-weight) * total-resource,资源软约束。 capability -> queue内所有podgroup使用资源之和的上限,资源硬约束。 reclaimable -> 当该queue在资源使用超过该queue限制时,是否允许其他queue回收该queue使用的超额资源。 使用场景 Total Cluster CPUS = 4cores --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test1 spec: weight: 1 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test2 spec: weight: 3 # 创建p1 p2 podgroup分别属于test1,test2,分别向p1 p2中投入job1 job2,资源申请分别为1C和3C,两个job均能正常工作 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test1 spec: weight: 1 # 首先创建test1 queue,创建podgroup p1,在p1中创建job1 job2,资源分配分别为1C和3C,job均能正常工作。 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test2 spec: weight: 3 # 创建test2 queue, 在该queue中创建podgroup p2,在p2中创建job3资源申请为3C,由于test2 queue weight=3,从而job2将被驱逐,test1 3C资源将归还给test2。 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test1 spec: capability: cpu: 2 # 创建test1 queue,容量设置为2,也就是资源上限使用为2C,创建p1 podgroup,在p1中创建job1 job2资源申请分别为1C和3C,那么job1正常运行,job2处于pending状态 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test1 spec: weight: 1 reclaimable: false --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test2 spec: weight: 1 # 创建 test1 queue,reclaimable为False,也就是该queue不归还多占用的资源,分别在test1 test2 queue 中创建p1 p2,在p1中创建job1,资源申请为3C,由于权重比例为1:1,此时 test1 多占用1C,在p2中创建job2,资源申请为2C,此时由于test1不归还多占用的资源,job2将处于pending状态。 PodGroup podgroup是一组强关联pod的集合,用于批处理工作负载场景。 ...

June 2, 2021

History of Kubernets

Kubernets Wiki 最近看了Large-scale cluster management at Google with Borg,Borg是谷歌公司自己内部开发的一套集群管理系统,后来开源社区也就慢慢开始孵化和推出了Kubernets集群管理系统,k8s和Borg有着很深的渊源关系。 先从Kubernets入手,我们来看下K8s的组件: Kubelet 在每一台节点上都会运行Kubelet,管理节点上的容器。 kube-apiServer 验证和配置关于Pods,Services,ReplicationControllers等数据,其他kube都需要通过调用api来获取所需的数据。 kube-Controller-Manager 用于控制系统的状态,通过API接口来同步系统数据,比如将系统从A状态同步更新到B状态。 kube-proxy 运行在每一台的节点上,主要作用充当网络代理,能够简单的处理TCP UDP 转发和轮询。 kube-scheduler 用来调度Pods,当有新的Pods需要创建时,调度器会给每一台工作节点打分,然后将Pods分配到满足要求的节点上。 然后再看关于Borg系统的描述,每一个集群都称之为一个Cell,每一个Cell都运行在一个独立的数据中心里。 Borg 架构 Borg 设计准则主要是以下三点: 隐藏对系统底层资源的管理以及容错处理,方便开发者将注意力集中在开发上,而不过多注意底层细节。 系统中运行的应用都是高可用的,某台节点的宕机,不会引起服务的不可用。 必须非常高效的在数万台节点上完成对应用的扩展。 Borg的用户基本上是google内部开发人员和SRE,正是因为google注重对SRE的发展,才慢慢在google内部形成了上述三点的认知体系,提到google SRE不得不提GOOGLE SRE How Google Runs Production Systems这本书,我只看过中文版,看完英文版之后会写一篇博客专门详细讨论这本书里的内容。 集群设计架构 Borg系统有一套自己的配置文件语法体系BCL,然后通过borgcfg加载到基于Paxos的分布式数据库存储中,在k8s中我们是通过编写Yaml状态配置文件,然后使用kubectl将状态配置通过kube-api接口提交到后端分布式ETCD存储中,在边缘设施的k8s场景中,像k3s,microk8s会默认使用基于SQL的数据库引擎Dqlite,dqlite也采用了Raft一致性存储协议,这样就可以做到边缘设备上的k8s高可用。 在Borg系统中,SRE工程师大部分通过Borgctl命令行工具对系统进行访问和修改。 Borg的核心组成部分有Scheduler,BorgMaster,Paxos Datastore,LinkShard,Borglet。 BorgMaster: master分为两部分,第一部分是对外处理请求,比如RPC调用获取集群状态,任务分配信息,获取borglet的状态,第二部分是用于处理集群内部的任务调度模块,master 支持高可用,所有的数据都是通过基于Paxos的数据库进行存储,当前master leader宕机之后,master 副本中会选举出新的master节点继续对外提供服务。最引人注目的是,master节点的数据存储使用了CheckPoint技术,每隔一段时间,系统都会自动保存当前的状态到checkpoint中,这样在集群发生问题的时候,我们就能将集群回退到前一个正常的checkpoint的状态,并且在线下使用这些point来做debug。 BorgScheduler: 当任务通过master提交之后,master会将数据存储到paxos中,并且将任务放到待处理队列中,Scheduler会根据这些任务的优先级进行先后处理,Scheduler拿到任务之后,计算哪些机器是符合要求的,根据一定的打分算法给这些机器打分,再根据分数将任务分配到对应的节点上。 Borglet: 运行在每一台节点上,用于管理任务的生命周期,比如停止运行重启,维护操作系统的内核配置,borgmaster会定期去拉取let上的状态信息,如果let没有应答那么master就认为这个对应节点已经下线或者宕机。 Jobs&&Tasks: Borgs运行的对象以Jobs Tasks来进行管理,一个Job可以由多个Tasks组成。以下是任务的生命周期。 当任务被提交到Borg Master时,如果任务被master接受则会进入Pending状态,等待Scheduler进行调度,调度完成之后,组成job’s Tasks就开始运行,如果超出系统的资源限制,Tasks就会被Evicted,然后进入Pending状态,继续等待被调度到新的节点上,当Tasks运行结束,任务的状态会被更新为Dead,有点像进程的生命周期,整个主干过程就是 Create -> Pending -> Scheduling -> Runing -> Dead。 然后我们看下k8s整个架构以及任务的调度是如何完成的,可以与Borg对比,发现两者的优缺点。 ...

September 7, 2020

Mathematica Json 解析

今天在工作过程中遇到需要解析JSON文件,得到其中的一个关键字,准备用Mathematica练练手,文件如下,需要解析"pubkey"这个字段。 { "apiVersion": "v1", "data": { "voting-keystore.json": "{\"version\": 4, \"pubkey\": \"a94300da6d73a11d8ba72c99dd385b7a9d5043c9ee83ffd4190d89b7677e68d384fbceb556d2a0652e81250ad4b8477d\", \"uuid\": \"09e5c322-bf6b-401a-b90d-1aef6d57996a\", \"crypto\": {\"checksum\": {\"message\": \"704e947d244bc8020ef6d6f0844c4aea08af18ecf345bb98ab999df6441377d7\", \"function\": \"sha256\", \"params\": {}}, \"kdf\": {\"message\": \"\", \"function\": \"scrypt\", \"params\": {\"p\": 1, \"n\": 32768, \"salt\": \"b891518a06f1d3f67a6d485bba8627f5320497f98c08cb52e4391e50071ac97d\", \"dklen\": 32, \"r\": 8}}, \"cipher\": {\"message\": \"bcd85ce03e82e645e13501f717d907c03a23ee1f8dc6bd045c53001719ddc7a5\", \"function\": \"aes-128-ctr\", \"params\": {\"iv\": \"7f05ffce95bcd0157e520c6b949b90b1\"}}}, \"path\": \"\"}" }, "kind": "ConfigMap", "metadata": { "creationTimestamp": "2020-07-25T11:35:24Z", "managedFields": [ { "apiVersion": "v1", "fieldsType": "FieldsV1", "fieldsV1": { "f:data": { ".": {}, "f:voting-keystore.json": {} } }, "manager": "Swagger-Codegen", "operation": "Update", "time": "2020-07-25T11:35:24Z" } ], "name": "lighthouse-validator-a94300da6d73", "namespace": "eth", "resourceVersion": "1200502", "selfLink": "/api/v1/namespaces/eth/configmaps/lighthouse-validator-a94300da6d73", "uid": "05b37640-be81-4944-9c9f-868431b6107f" } } 使用wolfram语言一行搞定: ...

July 27, 2020

Node-RED@Home

目标 继续接前一篇的NFS文件系统,目前的需求是需要能够控制集群中运行的应用,比如现在需要运行并行跨节点程序A,那么需要先调度停止正在运行的程序B,这就需要构建一个消息传递系统,能够基于消息驱动来完成操作任务。 前景和基本架构设计 Swift被设定为Tensorflow下一代的机器学习语言,参见Swift for Tensorflow,目前尝试着用Swift来编写应用。 使用MQTT协议来发送和接收需要处理的数据。 利用TinyML技术收集家用设备电器上传感器产生的数据,从而使得家电更加智能。 目前的设想是使用RabbitMQ做为消息中间件,Swift编写服务端应用推送消息,客户端需要一个UI应用接受和处理对应的消息事件,以下就是介绍一款基于消息驱动的可视化编程工具。 发现 Node-Red Node-Red是由IBM开发的基于流程的可视化编程工具。 个人觉得它的优点就是开发物联网应用原型速度快,支持Arduino,Raspberry Pi等设备,简单易用,基于事件驱动,原生开发语言为nodejs,支持可扩展插件。 运行在K3s上 node-red.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: node-red namespace: science labels: app: node-red spec: replicas: 1 selector: matchLabels: app: node-red template: metadata: labels: app: node-red spec: containers: - name: node-red image: $image imagePullPolicy: Always ports: - containerPort: 1880 volumeMounts: - mountPath: /data name: data-volume volumes: - name: data-volume persistentVolumeClaim: claimName: node-red-pvc --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: node-red-pvc namespace: science annotations: volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" spec: accessModes: - ReadWriteOnce resources: requests: storage: 6Gi --- apiVersion: v1 kind: Service metadata: name: node-red namespace: science spec: selector: app: node-red ports: - protocol: TCP port: 1880 targetPort: 1880 --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: node-red-ingress namespace: science spec: rules: - host: foo.bar.host http: paths: - backend: serviceName: node-red servicePort: 1880 Run RabbitMQ On K3s rabbitmq-conf-rabbitmq-env-configmap.yaml ...

June 29, 2020

Raspberry Pi K3s NFS FS

NFS on Raspberry Pi 目前正学习如何在树莓派4集群上结合gromacs+mpich的分子动力学模拟,所以需要搭建一款分布式存储系统,又由于树莓派性能的限制,搭建OpenEBS会比较浪费计算资源,最后就采用轻量级的NFS来完成文件系统的共享和存储。 NFS on K3s aarch64 基础依赖 NFS Server: sudo apt install nfs-kernel-server 添加共享文件目录到/etc/exports: /mnt/data/nfs 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check) # 外部使用 /mnt/data/kubedata 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check) # k3s 使用 启动 NFS Server: sudo systemctl restart nfs-kernel-server NFS Client: sudo apt install nfs-common sudo mount 192.168.1.145:/mnt/data/nfs ./nfs 添加到/etc/fstab: 192.168.1.145:/mnt/data/nfs /home/chenfeng/nfs nfs auto,nofail,noatime,nolock 0 0 K3s NFS Volume 需要使用Kubernets提供的NFS Client Provisioner k3s是跑在Ubuntu 20.04 aarch64 系统上的,而官方提供的NFS Client Provisioner是基于ARM v7的,所以需要重新编译Provisioner。 以下的操作全部在Raspberry pi 4上完成的。 以下为PATH: diff -ur ./Makefile /tmp/nfs-client/Makefile --- ./Makefile 2020-06-28 07:47:43.883181030 +0000 +++ /tmp/nfs-client/Makefile 2020-06-28 10:06:00.588586966 +0000 @@ -28,17 +28,16 @@ container: build image build_arm image_arm build: - CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o docker/x86_64/nfs-client-provisioner ./cmd/nfs-client-provisioner + go build -a -ldflags '-extldflags "-static"' -o docker/x86_64/nfs-client-provisioner ./cmd/nfs-client-provisioner build_arm: - CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -a -ldflags '-extldflags "-static"' -o docker/arm/nfs-client-provisioner ./cmd/nfs-client-provisioner + go build -a -ldflags '-extldflags "-static"' -o docker/arm/nfs-client-provisioner ./cmd/nfs-client-provisioner image: docker build -t $(MUTABLE_IMAGE) docker/x86_64 docker tag $(MUTABLE_IMAGE) $(IMAGE) image_arm: - docker run --rm --privileged multiarch/qemu-user-static:register --reset docker build -t $(MUTABLE_IMAGE_ARM) docker/arm docker tag $(MUTABLE_IMAGE_ARM) $(IMAGE_ARM) Only in /tmp/nfs-client/deploy: .deployment-arm.yaml.swp diff -ur ./deploy/deployment-arm.yaml /tmp/nfs-client/deploy/deployment-arm.yaml --- ./deploy/deployment-arm.yaml 2020-06-28 09:24:48.499572298 +0000 +++ /tmp/nfs-client/deploy/deployment-arm.yaml 2020-06-28 10:06:11.876117004 +0000 @@ -4,7 +4,8 @@ name: nfs-client-provisioner labels: app: nfs-client-provisioner - namespace: nfs + # replace with namespace where provisioner is deployed + namespace: default spec: replicas: 1 strategy: @@ -20,7 +21,7 @@ serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner - image: 192.168.1.114:5000/nfs-client-provisioner-arm + image: quay.io/external_storage/nfs-client-provisioner-arm:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes @@ -28,11 +29,11 @@ - name: PROVISIONER_NAME value: fuseim.pri/ifs - name: NFS_SERVER - value: 192.168.1.145 + value: 10.10.10.60 - name: NFS_PATH - value: /mnt/data/kubedata + value: /ifs/kubernetes volumes: - name: nfs-client-root nfs: - server: 192.168.1.145 - path: /mnt/data/kubedata + server: 10.10.10.60 + path: /ifs/kubernetes diff -ur ./deploy/test-pod.yaml /tmp/nfs-client/deploy/test-pod.yaml --- ./deploy/test-pod.yaml 2020-06-28 09:36:06.872994438 +0000 +++ /tmp/nfs-client/deploy/test-pod.yaml 2020-06-28 10:06:11.920115180 +0000 @@ -5,7 +5,7 @@ spec: containers: - name: test-pod - image: 192.168.1.114:5000/ubuntu:20.04 + image: gcr.io/google_containers/busybox:1.24 command: - "/bin/sh" args: diff -ur ./docker/arm/Dockerfile /tmp/nfs-client/docker/arm/Dockerfile --- ./docker/arm/Dockerfile 2020-06-28 07:47:43.759177680 +0000 +++ /tmp/nfs-client/docker/arm/Dockerfile 2020-06-28 10:06:00.628585293 +0000 @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM hypriot/rpi-alpine:3.6 -RUN apk update --no-cache && apk add ca-certificates +FROM ubuntu:20.04 COPY nfs-client-provisioner /nfs-client-provisioner ENTRYPOINT ["/nfs-client-provisioner"] nfs-client/cmd/nfs-client-provisioner为Provisioner源码目录。 ...

June 28, 2020

关于建立个人知识库的思考

建立个人知识库的思考

June 9, 2020