您好,登錄后才能下訂單哦!
這篇文章主要講解了“Kubernetes的架構(gòu)怎么使用”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Kubernetes的架構(gòu)怎么使用”吧!
TensorFlow是一個(gè)使用數(shù)據(jù)流圖進(jìn)行數(shù)值計(jì)算的開(kāi)源軟件庫(kù)。圖中的節(jié)點(diǎn)代表數(shù)學(xué)運(yùn)算,而圖中的邊則代表在這些節(jié)點(diǎn)之間傳遞的多維數(shù)組(張量)。這種靈活的架構(gòu)可讓您使用一個(gè) API 將計(jì)算工作部署到桌面設(shè)備、服務(wù)器或者移動(dòng)設(shè)備中的一個(gè)或多個(gè) CPU 或 GPU。 關(guān)于TensorFlow的基礎(chǔ)概念,我就不多介紹了。
下面是一個(gè)單機(jī)式TensorFlow訓(xùn)練示意圖,通過(guò)Client提交Session,定義這個(gè)worker要用哪個(gè)cpu/gpu做什么事。
2016年4月TensorFlow發(fā)布了0.8版本宣布支持分布式計(jì)算,我們稱之為Distributed TensorFlow。這是非常重要的一個(gè)特性,因?yàn)樵贏I的世界里,訓(xùn)練的數(shù)據(jù)量和模型參數(shù)通常會(huì)非常大。比如Google Brain實(shí)驗(yàn)室今年發(fā)表的論文OUTRAGEOUSLY LARGE NEURAL NETWORKS: THE SPARSELY-GATED MIXTURE-OF-EXPERTS LAYER
中提到一個(gè)680億個(gè)Parameters的模型,如果只能單機(jī)訓(xùn)練,那耗時(shí)難于接受。通過(guò)Distributed TensorFlow,可以利用大量服務(wù)器構(gòu)建分布式TensorFlow集群來(lái)提高訓(xùn)練效率,減少訓(xùn)練時(shí)間。
通過(guò)TensorFlow Replcation機(jī)制,用戶可以將SubGraph分布到不同的服務(wù)器中進(jìn)行分布式計(jì)算。TensorFlow的副本機(jī)制又分為兩種,In-graph和Between-graph。
In-graph Replication簡(jiǎn)單來(lái)講,就是通過(guò)單個(gè)client session定義這個(gè)TensorFlow集群的所有task的工作。
與之相對(duì)地,Between-graph Replication就是每個(gè)worker都有獨(dú)立的client來(lái)定義自己的工作。
下面是抽象出來(lái)的分布式TensorFlow Framework如下:
我們先來(lái)了解里面的幾個(gè)概念:
Cluster
一個(gè)TensorFlow Cluster有一個(gè)或多個(gè)jobs組成,每個(gè)job又由一個(gè)或多個(gè)tasks構(gòu)成。Cluster的定義是通過(guò)tf.train.ClusterSpec來(lái)定義的。比如,定義一個(gè)由3個(gè)worker和2個(gè)ps的TensorFlow Cluster的ClusterSpec如下:
tf.train.ClusterSpec({ "worker": [ "worker0.example.com:2222", //主機(jī)名也可以使用IP "worker1.example.com:2222", "worker2.example.com:2222" ], "ps": [ "ps0.example.com:2222", "ps1.example.com:2222" ]})
Client
Client用來(lái)build一個(gè)TensorFlow Graph,并構(gòu)建一個(gè)tensorflow::Session用來(lái)與集群通信。一個(gè)Client可以與多個(gè)TensorFlow Server交互,一個(gè)Server能服務(wù)多個(gè)Client。
Job
一個(gè)Job由tasks list組成,Job分ps和worker兩種類型。ps即parameter server,用來(lái)存儲(chǔ)和更新variables的,而worker可以認(rèn)為是無(wú)狀態(tài)的,用來(lái)作為計(jì)算任務(wù)的。workers中,一般都會(huì)選擇一個(gè)chief worker(通常是worker0),用來(lái)做訓(xùn)練狀態(tài)的checkpoint,如果有worker故障,那么可以從最新checkpoint中restore。
Task
每個(gè)Task對(duì)應(yīng)一個(gè)TensorFlow Server,對(duì)應(yīng)一個(gè)單獨(dú)的進(jìn)程。一個(gè)Task屬于某個(gè)Job,通過(guò)一個(gè)index來(lái)標(biāo)記它在對(duì)應(yīng)Job的tasks中的位置。每個(gè)TensorFlow均實(shí)現(xiàn)了Master service和Worker service。Master service用來(lái)與集群內(nèi)的worker services進(jìn)行g(shù)rpc交互。Worker service則是用local device來(lái)計(jì)算subgraph。
關(guān)于Distributed TensorFlow的更多內(nèi)容,請(qǐng)參考官方內(nèi)容www.tensorflow.org/deplopy/distributed
分布式TensorFlow能利用數(shù)據(jù)中心所有服務(wù)器構(gòu)成的資源池,讓大量ps和worker能分布在不同的服務(wù)器進(jìn)行參數(shù)存儲(chǔ)和訓(xùn)練,這無(wú)疑是TensorFlow能否在企業(yè)落地的關(guān)鍵點(diǎn)。然而,這還不夠,它還存在一下先天不足:
訓(xùn)練時(shí)TensorFlow各個(gè)Task資源無(wú)法隔離,很有可能會(huì)導(dǎo)致任務(wù)間因資源搶占互相影響。
缺乏調(diào)度能力,需要用戶手動(dòng)配置和管理任務(wù)的計(jì)算資源。
集群規(guī)模大時(shí),訓(xùn)練任務(wù)的管理很麻煩,要跟蹤和管理每個(gè)任務(wù)的狀態(tài),需要在上層做大量開(kāi)發(fā)。
用戶要查看各個(gè)Task的訓(xùn)練日志需要找出對(duì)應(yīng)的服務(wù)器,并ssh過(guò)去,非常不方便。
TensorFlow原生支持的后端文件系統(tǒng)只支持:標(biāo)準(zhǔn)Posix文件系統(tǒng)(比如NFS)、HDFS、GCS、memory-mapped-file。大多數(shù)企業(yè)中數(shù)據(jù)都是存在大數(shù)據(jù)平臺(tái),因此以HDFS為主。然而,HDFS的Read性能并不是很好。
當(dāng)你試著去創(chuàng)建一個(gè)大規(guī)模TensorFlow集群時(shí),發(fā)現(xiàn)并不輕松;
TensorFlow的這些不足,正好是Kubernetes的強(qiáng)項(xiàng):
提供ResourceQuota, LimitRanger等多種資源管理機(jī)制,能做到任務(wù)之間很好的資源隔離。
支持任務(wù)的計(jì)算資源的配置和調(diào)度。
訓(xùn)練任務(wù)以容器方式運(yùn)行,Kubernetes提供全套的容器PLEG接口,因此任務(wù)狀態(tài)的管理很方便。
輕松對(duì)接EFK/ELK等日志方案,用戶能方便的查看任務(wù)日志。
支持Read性能更優(yōu)秀的分布式存儲(chǔ)(Glusterfs),但目前我們也還沒(méi)對(duì)接Glusterfs,有計(jì)劃但沒(méi)人力。
通過(guò)聲明式文件實(shí)現(xiàn)輕松快捷的創(chuàng)建一個(gè)大規(guī)模TensorFlow集群。
在我們的TensorFlow on Kubernetes方案中,主要用到以下的Kubernetes對(duì)象:
Kubernetes Job
我們用Kubernetes Job來(lái)部署TensorFlow Worker,Worker訓(xùn)練正常完成退出,就不會(huì)再重啟容器了。注意Job中的Pod Template restartPolicy只能為Never或者OnFailure,不能為Always,這里我們?cè)O(shè)定restartPolicy為OnFailure,worker一旦異常退出,都會(huì)自動(dòng)重啟。但是要注意,要保證worker重啟后訓(xùn)練能從checkpoint restore,不然worker重啟后又從step 0開(kāi)始,可能跑了幾天的訓(xùn)練就白費(fèi)了。如果你使用TensorFlow高級(jí)API寫(xiě)的算法,默認(rèn)都實(shí)現(xiàn)了這點(diǎn),但是如果你是使用底層core API,一定要注意自己實(shí)現(xiàn)。
kind: Job apiVersion: batch/v1 metadata: name: {{ name }}-{{ task_type }}-{{ i }} namespace: {{ name }} spec: template: metadata: labels: name: {{ name }} job: {{ task_type }} task: "{{ i }}" spec: imagePullSecrets: - name: harborsecret containers: - name: {{ name }}-{{ task_type }}-{{ i }} image: {{ image }} resources: requests: memory: "4Gi" cpu: "500m" ports: - containerPort: 2222 command: ["/bin/sh", "-c", "export CLASSPATH=.:/usr/lib/jvm/java-1.8.0/lib/tools.jar:$(/usr/lib/hadoop-2.6.1/bin/hadoop classpath --glob); wget -r -nH -np --cut-dir=1 -R 'index.html*,*gif' {{ script }}; cd ./{{ name }}; sh ./run.sh {{ ps_hosts() }} {{ worker_hosts() }} {{ task_type }} {{ i }} {{ ps_replicas }} {{ worker_replicas }}"] restartPolicy: OnFailure
Kubernetes Deployment
TensorFlow PS用Kubernetes Deployment來(lái)部署。為什么不像worker一樣,也使用Job來(lái)部署呢?其實(shí)也未嘗不可,但是考慮到PS進(jìn)程并不會(huì)等所有worker訓(xùn)練完成時(shí)自動(dòng)退出(一直掛起),所以使用Job部署沒(méi)什么意義。
kind: Deployment apiVersion: extensions/v1beta1 metadata: name: {{ name }}-{{ task_type }}-{{ i }} namespace: {{ name }} spec: replicas: 1 template: metadata: labels: name: {{ name }} job: {{ task_type }} task: "{{ i }}" spec: imagePullSecrets: - name: harborsecret containers: - name: {{ name }}-{{ task_type }}-{{ i }} image: {{ image }} resources: requests: memory: "4Gi" cpu: "500m" ports: - containerPort: 2222 command: ["/bin/sh", "-c","export CLASSPATH=.:/usr/lib/jvm/java-1.8.0/lib/tools.jar:$(/usr/lib/hadoop-2.6.1/bin/hadoop classpath --glob); wget -r -nH -np --cut-dir=1 -R 'index.html*,*gif' {{ script }}; cd ./{{ name }}; sh ./run.sh {{ ps_hosts() }} {{ worker_hosts() }} {{ task_type }} {{ i }} {{ ps_replicas }} {{ worker_replicas }}"] restartPolicy: Always
關(guān)于TensorFlow PS進(jìn)程掛起的問(wèn)題,請(qǐng)參考https://github.com/tensorflow/tensorflow/issues/4713.我們是這么解決的,開(kāi)發(fā)了一個(gè)模塊,watch每個(gè)TensorFlow集群的所有worker狀態(tài),當(dāng)所有worker對(duì)應(yīng)Job都Completed時(shí),就會(huì)自動(dòng)去刪除PS對(duì)應(yīng)的Deployment,從而kill PS進(jìn)程釋放資源。
Kubernetes Headless Service
Headless Service通常用來(lái)解決Kubernetes里面部署的應(yīng)用集群之間的內(nèi)部通信。在這里,我們也是這么用的,我們會(huì)為每個(gè)TensorFlow對(duì)應(yīng)的Job和Deployment對(duì)象都創(chuàng)建一個(gè)Headless Service作為worker和ps的通信代理。
kind: Service apiVersion: v1 metadata: name: {{ name }}-{{ task_type }}-{{ i }} namespace: {{ name }} spec: clusterIP: None selector: name: {{ name }} job: {{ task_type }} task: "{{ i }}" ports: - port: {{ port }} targetPort: 2222
用Headless Service的好處,就是在KubeDNS中,Service Name的域名解析直接對(duì)應(yīng)到PodIp,而沒(méi)有service VIP這一層,這就不依賴于kube-proxy去創(chuàng)建iptables規(guī)則了。少了kube-proxy的iptables這一層,帶來(lái)的是性能的提升。
在TensorFlow場(chǎng)景中,這是不可小覷的,因?yàn)橐粋€(gè)TensorFlow Task都會(huì)創(chuàng)建一個(gè)service,幾萬(wàn)個(gè)service是很正常的事,如果使用Normal Service,iptables規(guī)則就幾十萬(wàn)上百萬(wàn)條了,增刪一條iptabels規(guī)則耗時(shí)幾個(gè)小時(shí)甚至幾天,集群早已奔潰。關(guān)于kube-proxy iptables模式的性能測(cè)試數(shù)據(jù),請(qǐng)參考華為PaaS團(tuán)隊(duì)的相關(guān)分享。
KubeDNS Autoscaler
前面提到,每個(gè)TensorFlow Task都會(huì)創(chuàng)建一個(gè)service,都會(huì)在KubeDNS中有一條對(duì)應(yīng)的解析規(guī)則,但service數(shù)量太多的時(shí)候,我們發(fā)現(xiàn)有些worker的域名解析失敗概率很大,十幾次才能成功解析一次。這樣會(huì)影響TensorFlow集群內(nèi)各個(gè)task的session建立,可能導(dǎo)致TensorFlow集群起不來(lái)。
為了解決這個(gè)問(wèn)題,我們引入了Kubernetes的孵化項(xiàng)目kubernetes-incubator/cluster-proportional-autoscaler來(lái)對(duì)KubeDNS進(jìn)行動(dòng)態(tài)伸縮。關(guān)于這個(gè)問(wèn)題的具體的細(xì)節(jié),有興趣的同學(xué)可以查看我的博文https://my.oschina.net/jxcdwangtao/blog/1581879。
基于上面的方案,我們開(kāi)發(fā)一個(gè)TaaS平臺(tái),已經(jīng)實(shí)現(xiàn)了基本的功能,包括算法管理、訓(xùn)練集群的創(chuàng)建和管理、模型的管理、模型上線(TensorFlow Serving)、一鍵創(chuàng)建TensorBoard服務(wù)、任務(wù)資源監(jiān)控、集群資源監(jiān)控、定時(shí)訓(xùn)練管理、任務(wù)日志在線查看和批量打包下載等等,這部分內(nèi)容可以參考之前在DockOne上分享的文章http://dockone.io/article/3036。
這只是剛開(kāi)始,我正在做下面的特性:
支持基于訓(xùn)練優(yōu)先級(jí)的任務(wù)搶占式調(diào)度: 用戶在TaaS上創(chuàng)建TensorFlow訓(xùn)練項(xiàng)目時(shí),可以指定項(xiàng)目的優(yōu)先級(jí)為生產(chǎn)(Production)、迭代(Iteration)、調(diào)研(PTR),默認(rèn)為迭代。優(yōu)先級(jí)從高到低依次為**Production --> Iteration --> PTR
**。但集群資源不足時(shí),按照任務(wù)優(yōu)先級(jí)進(jìn)行搶占式調(diào)度。
提供像Yarn形式的資源分配視圖,讓用戶對(duì)自己的所有訓(xùn)練項(xiàng)目的資源占用情況變得清晰。
訓(xùn)練和預(yù)測(cè)的混合部署,提供數(shù)據(jù)中心資源利用率。
...
整個(gè)過(guò)程中,遇到了很多坑,有TensorFlow的,也有Kubernetes的,不過(guò)問(wèn)題最多的還是我們用的CNI網(wǎng)絡(luò)插件contiv netplugin,每次大問(wèn)題基本都是這個(gè)網(wǎng)絡(luò)插件造成的。Kubernetes是問(wèn)題最少的,它的穩(wěn)定性比我預(yù)期還要好。
contiv netplugin的問(wèn)題,在DevOps環(huán)境中還是穩(wěn)定的,在大規(guī)模高并發(fā)的AI場(chǎng)景,問(wèn)題就層出不窮了,產(chǎn)生大量垃圾IP和Openflow流表,直接把Node都成NotReady了,具體的不多說(shuō),因?yàn)閾?jù)我了解,現(xiàn)在用這個(gè)插件的公司已經(jīng)很少了,想了解的私下找我。
在我們的方案中,一個(gè)TensorFlow訓(xùn)練集群就對(duì)應(yīng)一個(gè)Kubernetes Namespace,項(xiàng)目初期我們并沒(méi)有對(duì)及時(shí)清理垃圾Namespace,到后來(lái)集群里上萬(wàn)Namespace的時(shí)候,整個(gè)Kubernetes集群的相關(guān)API性能非常差了,導(dǎo)致TaaS的用戶體驗(yàn)非常差。
TensorFlow grpc性能差,上千個(gè)worker的訓(xùn)練集群,概率性的出現(xiàn)這樣的報(bào)錯(cuò)grpc_chttp2_stream request on server; last grpc_chttp2_stream id=xxx, new grpc_chttp2_stream id=xxx
,這是TensorFlow底層grpc的性能問(wèn)題,低版本的grpc的Handlergrpc還是單線程的,只能嘗試通過(guò)升級(jí)TensorFlow來(lái)升級(jí)grpc了,或者編譯TensorFlow時(shí)單獨(dú)升級(jí)grpc版本。如果升級(jí)TensorFlow版本的話,你的算法可能還要做API適配。目前我們通過(guò)增加單個(gè)worker的計(jì)算負(fù)載來(lái)減少worker數(shù)量的方法,減少grpc壓力。
還有TensorFlow 自身OOM機(jī)制的問(wèn)題等等
感謝各位的閱讀,以上就是“Kubernetes的架構(gòu)怎么使用”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Kubernetes的架構(gòu)怎么使用這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。