bl双性厨房裸体围裙_一本大道一卡二卡三卡_2019年中文字字幕在线看不卡_中文字幕日产乱码天堂

首頁(yè) | 資訊 | 財(cái)經(jīng) | 公益 | 彩店 | 奇聞 | 速遞 | 前瞻 | 提點(diǎn) | 網(wǎng)站相關(guān) | 科技 | 熱點(diǎn) | 生活 |
面向大規(guī)模深度學(xué)習(xí)訓(xùn)練的緩存優(yōu)化實(shí)踐

發(fā)稿時(shí)間:2023-05-26 13:06:35 來源: DataFunTalk
一、項(xiàng)目背景和緩存策略

首先來分享一下相關(guān)背景。


(相關(guān)資料圖)

近年來,AI 訓(xùn)練應(yīng)用越來越廣泛。從基礎(chǔ)架構(gòu)角度來看,無論是大數(shù)據(jù)還是 AI 訓(xùn)練集群中,大多使用存儲(chǔ)與計(jì)算分離的架構(gòu)。比如很多 GPU 的陣列放到一個(gè)很大的計(jì)算集群中,另外一個(gè)集群是存儲(chǔ)。也可能是使用的一些云存儲(chǔ),像微軟的 Azure 或者是亞馬遜的 S3 等。

這樣的基礎(chǔ)架構(gòu)的特點(diǎn)是,首先,計(jì)算集群中有很多非常昂貴的 GPU,每臺(tái) GPU 往往有一定的本地存儲(chǔ),比如 SSD 這樣的幾十 TB 的存儲(chǔ)。這樣一個(gè)機(jī)器組成的陣列中,往往是用高速網(wǎng)絡(luò)去連接遠(yuǎn)端,比如 Coco、 image net、YouTube 8M 之類的非常大規(guī)模的訓(xùn)練數(shù)據(jù)是以網(wǎng)絡(luò)進(jìn)行連接的。

如上圖所示,數(shù)據(jù)有可能會(huì)成為下一個(gè) AI 訓(xùn)練的瓶頸。我們觀察到數(shù)據(jù)集越來越大,隨著 AI 應(yīng)用更加廣泛,也在積累更多的訓(xùn)練數(shù)據(jù)。同時(shí) GPU 賽道是非常卷的。比如 AMD、TPU 等廠商,花費(fèi)了大量精力去優(yōu)化硬件和軟件,使得加速器,類似 GPU、TPU這些硬件越來越快。隨著公司內(nèi)加速器的應(yīng)用非常廣泛之后,集群部署也越來越大。這里的兩個(gè)表呈現(xiàn)了關(guān)于數(shù)據(jù)集以及 GPU 速度的一些變化。之前的 K80 到 V100、 P100、 A100,速度是非常迅速的。但是,隨著速度越來越快,GPU 變得越來越昂貴。我們的數(shù)據(jù),比如 IO 速度能否跟上 GPU 的速度,是一個(gè)很大的挑戰(zhàn)。

如上圖所示,在很多大公司的應(yīng)用中,我們觀察到這樣一個(gè)現(xiàn)象:在讀取遠(yuǎn)程數(shù)據(jù)的時(shí)候,GPU 是空閑的。因?yàn)?GPU 是在等待遠(yuǎn)程數(shù)據(jù)讀取,這也就意味著 IO 成為了一個(gè)瓶頸,造成了昂貴的 GPU 被浪費(fèi)。有很多工作在進(jìn)行優(yōu)化來緩解這一瓶頸,緩存就是其中很重要的一個(gè)優(yōu)化方向。這里介紹兩種方式。

第一種,在很多應(yīng)用場(chǎng)景中,尤其是以 K8s 加 Docker 這樣的基礎(chǔ) AI 訓(xùn)練架構(gòu)中,用了很多本地磁盤。前文中提到 GPU 機(jī)器是有一定的本地存儲(chǔ)的,可以用本地磁盤去做一些緩存,把數(shù)據(jù)先緩存起來。

啟動(dòng)了一個(gè) GPU 的 Docker 之后,不是馬上啟動(dòng) GPU 的 AI 訓(xùn)練,而是先去下載數(shù)據(jù),把數(shù)據(jù)從遠(yuǎn)端下載到 Docker 內(nèi)部,也可以是掛載等方式。下載到 Docker 內(nèi)部之后再開始訓(xùn)練。這樣盡可能的把后邊的訓(xùn)練的數(shù)據(jù)讀取都變成本地的數(shù)據(jù)讀取。本地 IO 的性能目前來看是足夠支撐 GPU 的訓(xùn)練的。VLDB 2020 上面,有一篇 paper,CoorDL,是基于 DALI 進(jìn)行數(shù)據(jù)緩存。

這一方式也帶來了很多問題。首先,本地的空間是有限的,意味著緩存的數(shù)據(jù)也是有限的,當(dāng)數(shù)據(jù)集越來越大的時(shí)候,很難緩存到所有數(shù)據(jù)。另外,AI 場(chǎng)景與大數(shù)據(jù)場(chǎng)景有一個(gè)很大的區(qū)別是,AI 場(chǎng)景中的數(shù)據(jù)集是比較有限的。不像大數(shù)據(jù)場(chǎng)景中有很多的表,有各種各樣的業(yè)務(wù),每個(gè)業(yè)務(wù)的數(shù)據(jù)表的內(nèi)容差距是非常大的。在 AI 場(chǎng)景中,數(shù)據(jù)集的規(guī)模、數(shù)據(jù)集的數(shù)量遠(yuǎn)遠(yuǎn)小于大數(shù)據(jù)場(chǎng)景。所以常常會(huì)發(fā)現(xiàn),公司中提交的任務(wù)很多都是讀取同一個(gè)數(shù)據(jù)。如果每個(gè)人下載數(shù)據(jù)到自己本地,其實(shí)是不能共享的,會(huì)有非常多份數(shù)據(jù)被重復(fù)存儲(chǔ)到本地機(jī)器上。這種方式顯然存在很多問題,也不夠高效。

接下來介紹第二種方式。既然本地的存儲(chǔ)不太好,那么,是否可以使用像 Alluxio 這樣一個(gè)分布式緩存來緩解剛才的問題,分布式緩存有非常大的容量來裝載數(shù)據(jù)。另外,Alluxio 作為一個(gè)分布式緩存,很容易進(jìn)行共享。數(shù)據(jù)下載到 Alluxio 中,其他的客戶端,也可以從緩存中讀取這份數(shù)據(jù)。這樣看來,使用 Alluxio 可以很容易地解決上面提到的問題,為 AI 訓(xùn)練性能帶來很大的提升。微軟印度研究院在 FAST2020 發(fā)表的名為 Quiver 的一篇論文,就提到了這樣的解決思路。但是我們分析發(fā)現(xiàn),這樣一個(gè)看似完美的分配方案,還是比較靜態(tài)的,并不高效。同時(shí),采用什么樣的 cache 淘汰算法,也是一個(gè)很值得討論的問題。

如上圖所示,是使用 Alluxio 作為 AI 訓(xùn)練的緩存的一個(gè)應(yīng)用。使用 K8s 做整個(gè)集群任務(wù)的調(diào)度和對(duì) GPU、CPU、內(nèi)存等資源的管理。當(dāng)有用戶提交一個(gè)任務(wù)到 K8s 時(shí),K8s 首先會(huì)做一個(gè)插件,通知 Alluxio 的 master,讓它去下載這部分?jǐn)?shù)據(jù)。也就是先進(jìn)行一些熱身,把作業(yè)可能需要的任務(wù),盡量先緩存一些。當(dāng)然不一定非得緩存完,因?yàn)锳lluxio 是有多少數(shù)據(jù),就使用多少數(shù)據(jù)。剩下的,如果還沒有來得及緩存,就從遠(yuǎn)端讀取。另外,Alluxio master 得到這樣的命令之后,就可以讓調(diào)度它的 worker 去遠(yuǎn)端。可能是云存儲(chǔ),也可能是 Hadoop 集群把數(shù)據(jù)下載下來。這個(gè)時(shí)候,K8s 也會(huì)把作業(yè)調(diào)度到 GPU 集群中。比如上圖中,在這樣一個(gè)集群中,它選擇第一個(gè)節(jié)點(diǎn)和第三個(gè)節(jié)點(diǎn)啟動(dòng)訓(xùn)練任務(wù)。啟動(dòng)訓(xùn)練任務(wù)之后,需要進(jìn)行數(shù)據(jù)的讀取。在現(xiàn)在主流的像 PyTorch、Tensorflow 等框架中,也內(nèi)置了 Prefetch,也就是會(huì)進(jìn)行數(shù)據(jù)預(yù)讀取。它會(huì)讀取已經(jīng)提前緩存的 Alluxio 中的緩存數(shù)據(jù),為訓(xùn)練數(shù)據(jù) IO 提供支持。當(dāng)然,如果發(fā)現(xiàn)有一些數(shù)據(jù)是沒有讀到的,Alluxio 也可以通過遠(yuǎn)端進(jìn)行讀取。Alluxio 作為一個(gè)統(tǒng)一的接口是非常好的。同時(shí)它也可以進(jìn)行數(shù)據(jù)的跨作業(yè)間的共享。

如上圖所示,比如又有一個(gè)人提交了同樣數(shù)據(jù)的另一個(gè)作業(yè),消耗的是同一個(gè)數(shù)據(jù)集,這個(gè)時(shí)候,當(dāng)提交作業(yè)到 K8s 的時(shí)候,Alluxio 就知道已經(jīng)有這部分?jǐn)?shù)據(jù)了。如果 Alluxio 想做的更好,甚至是可以知道,數(shù)據(jù)即將會(huì)被調(diào)度到哪臺(tái)機(jī)器上。比如這個(gè)時(shí)候調(diào)度到 node 1、node 3 和 node 4 上。node 4 的數(shù)據(jù),甚至可以做一些副本進(jìn)行拷貝。這樣所有的數(shù)據(jù),即使是 Alluxio 內(nèi)部,都不用跨機(jī)器讀,都是本地的讀取。所以看起來 Alluxio 對(duì) AI 訓(xùn)練中的 IO 問題有了很大的緩解和優(yōu)化。但是如果仔細(xì)觀察,就會(huì)發(fā)現(xiàn)兩個(gè)問題。

第一個(gè)問題就是緩存的淘汰算法非常低效,因?yàn)樵?AI 場(chǎng)景中,訪問數(shù)據(jù)的模式跟以往有很大區(qū)別。第二個(gè)問題是,緩存作為一種資源,與帶寬(即遠(yuǎn)程存儲(chǔ)的讀取速度)是一個(gè)對(duì)立的關(guān)系。如果緩存大,那么從遠(yuǎn)端讀取數(shù)據(jù)的機(jī)會(huì)就小。如果緩存很小,則很多數(shù)據(jù)都得從遠(yuǎn)端讀取。如何很好地調(diào)度分配這些資源也是一個(gè)需要考慮的問題。

在討論緩存的淘汰算法之前,先來看一下 AI 訓(xùn)練中數(shù)據(jù)訪問的過程。在 AI 訓(xùn)練中,會(huì)分為很多個(gè) epoch,不斷迭代地去訓(xùn)練。每一個(gè)訓(xùn)練 epoch,都會(huì)讀取每一條數(shù)據(jù),并且僅讀一次。為了防止訓(xùn)練的過擬合,在每一次 epoch 結(jié)束之后,下一個(gè) epoch 的時(shí)候,讀取順序會(huì)變化,會(huì)進(jìn)行一個(gè) shuffle。也就是每次每個(gè) epoch 都會(huì)把所有數(shù)據(jù)都讀取一次,但是順序卻不一樣。

Alluxio 中默認(rèn)的 LRU 淘汰算法,顯然不能很好地應(yīng)用到AI訓(xùn)練場(chǎng)景中。因?yàn)?LRU 是利用緩存的本地性。本地性分為兩方面,首先是時(shí)間本地性,也就是現(xiàn)在訪問的數(shù)據(jù),馬上可能還會(huì)即將訪問。這一點(diǎn),在 AI 訓(xùn)練中并不存在。因?yàn)楝F(xiàn)在訪問的數(shù)據(jù),在下一輪的時(shí)候才會(huì)訪問,而且下一輪的時(shí)候都會(huì)訪問。沒有一個(gè)特殊的概率,一定是比其他數(shù)據(jù)更容易被訪問。另一方面是數(shù)據(jù)本地性,還有空間本地性。也就是,為什么 Alluxio 用比較大的 block 緩存數(shù)據(jù),是因?yàn)槟硹l數(shù)據(jù)讀取了,可能周圍的數(shù)據(jù)也會(huì)被讀取。比如大數(shù)據(jù)場(chǎng)景中,OLAP 的應(yīng)用,經(jīng)常會(huì)進(jìn)行表的掃描,意味著周圍的數(shù)據(jù)馬上也會(huì)被訪問。但是在 AI 訓(xùn)練場(chǎng)景中是不能應(yīng)用的。因?yàn)槊看味紩?huì) shuffle,每次讀取的順序都是不一樣的。因此 LRU 這種淘汰算法并不適用于 AI 訓(xùn)練場(chǎng)景。

不僅是 LRU,像 LFU 等主流的淘汰算法,都存在這樣一個(gè)問題。因?yàn)檎麄€(gè) AI 訓(xùn)練對(duì)數(shù)據(jù)的訪問是非常均等的。所以,可以采用最簡(jiǎn)單的緩存算法,只要緩存一部分?jǐn)?shù)據(jù)就可以,永遠(yuǎn)不用動(dòng)。在一個(gè)作業(yè)來了以后,永遠(yuǎn)都只緩存一部分?jǐn)?shù)據(jù)。永遠(yuǎn)都不要淘汰它。不需要任何的淘汰算法。這可能是目前最好的淘汰機(jī)制。

如上圖中的例子。上面是 LRU 算法,下面是均等方法。在開始只能緩存兩條數(shù)據(jù)。我們把問題簡(jiǎn)單一些,它的容量只有兩條,緩存 D 和 B 這兩條數(shù)據(jù),中間就是訪問的序列。比如命中第一個(gè)訪問的是 B,如果是 LRU,B 存在的緩存中命中了。下一條訪問的是 C,C 并不在 D 和 B,LRU 的緩存中,所以基于 LRU 策略,會(huì)把 D 替換掉,C 保留下來。也就是這個(gè)時(shí)候緩存是 C 和 B。下一個(gè)訪問的是 A,A 也不在 C 和 B 中。所以會(huì)把B 淘汰掉,換成 C 和 A。下一個(gè)就是 D,D 也不在緩存中,所以換成 D 和 A。以此類推,會(huì)發(fā)現(xiàn)所有后面的訪問,都不會(huì)再命中緩存。原因是在進(jìn)行 LRU 緩存的時(shí)候,把它替換出來,但其實(shí)在一個(gè) epoch 中已經(jīng)被訪問一次,這個(gè) epoch 中就永遠(yuǎn)不會(huì)再被訪問到了。LRU 反倒把它進(jìn)行緩存了,LRU 不但沒有幫助,反倒是變得更糟糕了。不如使用 uniform,比如下面這種方式。

下面這種 uniform 的方式,永遠(yuǎn)在緩存中緩存 D 和 B,永遠(yuǎn)不做任何的替換。在這樣情況下,你會(huì)發(fā)現(xiàn)至少有 50% 的命中率。所以可以看到,緩存的算法不用搞得很復(fù)雜,只要使用 uniform 就可以了,不要使用 LRU、LFU 這類算法。

對(duì)于第二個(gè)問題,也就是關(guān)于緩存和遠(yuǎn)程帶寬之間關(guān)系的問題?,F(xiàn)在所有主流的 AI 框架中都內(nèi)置了數(shù)據(jù)預(yù)讀,防止 GPU 等待數(shù)據(jù)。所以當(dāng) GPU 做訓(xùn)練的時(shí)候,其實(shí)是觸發(fā)了 CPU 預(yù)取下一輪可能用到的數(shù)據(jù)。這樣可以充分利用 GPU 的算力。但當(dāng)遠(yuǎn)程存儲(chǔ)的 IO 成為瓶頸的時(shí)候,就意味著 GPU 要等待 CPU 了。所以 GPU 會(huì)有很多的空閑時(shí)間,造成了資源的浪費(fèi)。希望可以有一個(gè)比較好的調(diào)度管理方式,緩解 IO 的問題。

緩存和遠(yuǎn)程 IO 對(duì)整個(gè)作業(yè)的吞吐是有很大影響的。所以除了 GPU、CPU 和內(nèi)存,緩存和網(wǎng)絡(luò)也是需要調(diào)度的。在以往大數(shù)據(jù)的發(fā)展過程中,像 Hadoop、yarn、my source、K8s 等,主要都是調(diào)度 CPU、內(nèi)存、GPU。對(duì)于網(wǎng)絡(luò),尤其對(duì)于緩存的控制都不是很好。所以,我們認(rèn)為,在 AI 場(chǎng)景中,需要很好的調(diào)度和分配它們,來達(dá)到整個(gè)集群的最優(yōu)。

二、SiloD 框架

在 EuroSys 2023 發(fā)表了這樣一篇文章,它是一個(gè)統(tǒng)一的框架,來調(diào)度計(jì)算資源和存儲(chǔ)資源。

整體架構(gòu)如上圖所示。左下角是集群中的 CPU 和 GPU 硬件計(jì)算資源,以及存儲(chǔ)資源,如 NFS、云存儲(chǔ) HDFS 等。在上層有一些 AI 的訓(xùn)練框架 TensorFlow、PyTorch 等。我們認(rèn)為需要加入一個(gè)統(tǒng)一管理和分配計(jì)算和存儲(chǔ)資源的插件,也就是我們提出的SiloD。

如上圖所示,一個(gè)作業(yè)可以達(dá)到什么樣的吞吐和性能,是由 GPU 和 IO 的最小值決定的。使用多少個(gè)遠(yuǎn)程 IO,就會(huì)使用多少遠(yuǎn)端的 networking。可以通過這樣一個(gè)公式算出訪問速度。作業(yè)速度乘以緩存未命中率,也就是(1-c/d)。其中 c 就是緩存的大小,d 就是數(shù)據(jù)集。這也就意味著數(shù)據(jù)只考慮 IO 可能成為瓶頸的時(shí)候,大概的吞吐量是等于(b/(1-c/d)),b 就是遠(yuǎn)端的帶寬。結(jié)合以上三個(gè)公式,可以推出右邊的公式,也就是一個(gè)作業(yè)最終想達(dá)到什么樣的性能,可以這樣通過公式去計(jì)算沒有 IO 瓶頸時(shí)的性能,和有 IO 瓶頸時(shí)的性能,取二者中的最小值。

得到上面的公式之后,把它微分一下,就可以得到緩存的有效性,或者叫做緩存效率。即雖然作業(yè)很多,但在分配緩存的時(shí)候不能一視同仁。每一個(gè)作業(yè),基于數(shù)據(jù)集的不同,速度的不同,緩存分配多少是很有講究的。這里舉一個(gè)例子,就以這個(gè)公式為例,如果發(fā)現(xiàn)一個(gè)作業(yè),速度非??欤?xùn)練起來非???,同時(shí)數(shù)據(jù)集很小,這時(shí)候就意味著分配更大的緩存,收益會(huì)更大。

基于以上觀察,可以使用 SiloD,進(jìn)行緩存和網(wǎng)絡(luò)的分配。而且緩存的大小,是針對(duì)每個(gè)作業(yè)的速度,以及數(shù)據(jù)集整個(gè)的大小來進(jìn)行分配的。網(wǎng)絡(luò)也是如此。所以整個(gè)架構(gòu)是這樣的:除了主流的像 K8s 等作業(yè)調(diào)度之外,還有數(shù)據(jù)管理。在圖左邊,比如緩存的管理,要統(tǒng)計(jì)或者監(jiān)控分配整個(gè)集群中緩存的大小,每個(gè)作業(yè)緩存的大小,以及每個(gè)作業(yè)使用到的遠(yuǎn)程 IO 的大小。底下的作業(yè),和 Alluxio 方式很像,都可以都使用 API 進(jìn)行數(shù)據(jù)的訓(xùn)練。每個(gè) worker 上使用緩存對(duì)于本地的 job 進(jìn)行緩存支持。當(dāng)然它也可以在一個(gè)集群中跨節(jié)點(diǎn),也可以進(jìn)行共享。

經(jīng)過初步測(cè)試和實(shí)驗(yàn),發(fā)現(xiàn)這樣一個(gè)分配方式可以使整個(gè)集群的使用率和吞吐量都得到非常明顯的提升,最高可以達(dá)到 8 倍的性能上的提升??梢院苊黠@的緩解作業(yè)等待、GPU 空閑的狀態(tài)。

對(duì)上述介紹進(jìn)行一下總結(jié):

第一,在 AI 或者深度學(xué)習(xí)訓(xùn)練場(chǎng)景中,傳統(tǒng)的 LRU、LFU 等緩存策略并不適合,不如直接使用 uniform。

第二,緩存和遠(yuǎn)程帶寬,是一對(duì)伙伴,對(duì)整體性能起到了非常大的作用。

第三,像 K8s、yarn 等主流調(diào)度框架,可以很容易繼承到 SiloD。

最后,我們?cè)?paper 中做了一些實(shí)驗(yàn),不同的調(diào)度策略,都可以帶來很明顯的吞吐量的提升。

三、分布式緩存策略以及副本管理

我們還做了一些開源的工作。分布式緩存策略以及副本管理這項(xiàng)工作,已經(jīng)提交給社區(qū),現(xiàn)在處于 PR 階段。Alluxio master 主要做 Meta 的管理和整個(gè) worker 集群的管理。真正緩存數(shù)據(jù)的是 worker。上面有很多以 block 為單位的塊兒去緩存數(shù)據(jù)。存在的一個(gè)問題是,現(xiàn)階段的緩存策略都是單個(gè) worker 的,worker 內(nèi)部的每個(gè)數(shù)據(jù)在進(jìn)行是否淘汰的計(jì)算時(shí),只需要在一個(gè) worker 上進(jìn)行計(jì)算,是本地化的。

如上圖所示的例子,如果 worker 1 上有 block A, block B 和 block C,基于 LRU 算出來 block C 是最長(zhǎng)時(shí)間沒有使用的,就會(huì)把 block C淘汰。如果看一下全局的情況,就會(huì)發(fā)現(xiàn)這樣并不好。因?yàn)?block C 在整個(gè)集群中只有一個(gè)副本。把它淘汰之后,如果下面還有人要訪問 block C,只能從遠(yuǎn)端拉取數(shù)據(jù),就會(huì)帶來性能和成本的損失。我們提出做一個(gè)全局的淘汰策略。在這種情況下,不應(yīng)該淘汰 block C,而應(yīng)該淘汰副本比較多的。在這個(gè)例子中,應(yīng)該淘汰 block A,因?yàn)樗谄渌墓?jié)點(diǎn)上仍然有兩個(gè)副本,無論是成本還是性能都要更好。

如上圖所示,我們做的工作是在每個(gè) worker 上維護(hù)副本信息。當(dāng)某一個(gè) worker,比如加了一個(gè)副本,或者減了一個(gè)副本,首先會(huì)向 master 匯報(bào),而 master 會(huì)把這個(gè)信息作為心跳返回值,返回給其它相關(guān)的 worker。其它 worker 就可以知道整個(gè)全局副本的實(shí)時(shí)變化。同時(shí),更新副本信息。所以當(dāng)進(jìn)行 worker 內(nèi)部的淘汰時(shí),可以知道每一個(gè) worker 在整個(gè)全局有多少個(gè)副本,就可以設(shè)計(jì)一些權(quán)重。比如仍然使用 LRU,但是會(huì)加上副本個(gè)數(shù)的權(quán)重,綜合考量淘汰和替換哪些數(shù)據(jù)。

經(jīng)過我們初步的測(cè)試,在很多領(lǐng)域,無論是 big data,AI training 中都可以帶來很大的提升。所以不僅僅是優(yōu)化一臺(tái)機(jī)器上一個(gè) worker 的緩存命中。我們的目標(biāo)是使得整個(gè)集群的緩存命中率都得到提升。

最后,對(duì)全文進(jìn)行一下總結(jié)。首先,在 AI 的訓(xùn)練場(chǎng)景中,uniform 緩存淘汰算法要比傳統(tǒng)的 LRU、LFU 更好。第二,緩存和遠(yuǎn)端的 networking 也是一個(gè)需要被分配和調(diào)度的資源。第三,在進(jìn)行緩存優(yōu)化時(shí),不要只局限在一個(gè)作業(yè)或者一個(gè) worker 上,應(yīng)該統(tǒng)攬整個(gè)端到端全局的參數(shù),才能使得整個(gè)集群的效率和性能有更好的提升。

標(biāo)簽:

責(zé)任編輯:mb01

網(wǎng)站首頁(yè) | 關(guān)于我們 | 免責(zé)聲明 | 聯(lián)系我們

生活晚報(bào)網(wǎng)版權(quán)所有

Copyright @ 1999-2017 gaoerwen.cn All Rights Reserved豫ICP備2022016495號(hào)-7

聯(lián)系郵箱:939 674 669@qq.com