1 概述
整個軟件的發展歷程是一部軟件復雜性對抗史,軟件的復雜性分為技術復雜性和業務復雜性,業務復雜性主要是建模和抽象設計,技術復雜性主要是三高(高性能,高并發,高可用)的應對,C端的業務一般以技術復雜性為主,業務復雜性為輔,而B端或者M端的業務通常以業務復雜性為主,技術復雜性為輔。本篇文章主要是從后端研發的視角結合自己多年的B C端系統建設實踐談下三高系統的建設方法論和實踐,希望和大家相互交流,共同進步,同時這是我參與創作者計劃的第1篇文章。
2 高性能篇
個人理解三高系統的核心在于高性能,系統的性能高,系統的處理速度快,吞吐量自然高,此時系統能夠應對高并發的流量;系統的性能高,我們系統的對外承諾的TP99, TP999就比較低,超時等影響可用率的情況自然減少,系統的可用性也會提高,所以三高系統建設的出發點可以從系統的性能如何優化進行建設,高性能篇從系統的讀寫兩個維度談下系統的性能優化方法論及實踐;
2.1 方法論
首先我們要清楚知道影響系統性能的因素有那些,通常有以下三方面的因素:計算(computation),通信(communication),存儲(storage)。計算層面:系統本身的計算邏輯復雜,Fullgc;通信層面:依賴的下游耗時比較高;存儲層面:大庫大表,慢sql,ES集群的數據節點,索引,分片,分片大小設置的不合理;針對這些問題,我們可以從讀寫兩個維度針對性能問題進行優化,下圖是我工作中解決性能問題的一些方法。
?
2.2 幾個實踐問題的探討
2.2.1 讀優化:緩存和數據庫的結合藝術
一想到高性能,我們首先想到的是使用緩存,無論是本地緩存還是分布式的緩存,通過實踐我們發現緩存確實是提高我們系統性能最有效的手段,雖然緩存能夠暫存部分數據,提高系統的性能,但是我們一般不會使用緩存持久化數據,所以一般將緩存和數據庫結合使用,提高性能的同時也保證系統的可靠性;針對緩存和數據庫的結合使用,我們一般需要識別出系統是讀多寫少的系統,還是寫多讀少的系統;
2.2.1.1 讀多寫少的系統
針對讀多寫少的系統,我們一般采用同步更新數據庫,后刪除緩存;數據庫來應對寫的流量,緩存來應對讀的流量,提高讀的性能;此種方案我們是以數據庫數據為主,緩存數據為輔,這是前司大部分團隊采用的技術方案
2.2.1.2 寫多讀少的系統
針對寫多讀少的系統,我們一般采用同步更新緩存,異步更新數據庫,通過緩存來進行抗寫的流量,異步化更新數據庫,通過緩存和異步化提高系統的性能;此種技術方案以緩存數據為主,數據庫數據為輔,這是我了解到的京東物流這邊大部分團隊的技術方案,例如我們物流平臺-統一平臺小組的訂運關系單據的存儲采用的就是這種技術方案
2.2.2 寫優化:秒殺場景下的異步化
針對于這種流量洪峰下的秒殺場景,對于接單接口的性能是很大的考驗,所以接單接口不會有很多同步交互的復雜邏輯。我們一般都是先異步將訂單接下來,返回給用戶成功,通過消息隊列來削峰處理訂單,緩存存儲相關sku的庫存,當扣減庫存成功后,再短信通知用戶支付訂單。
?
3 高并發篇
提到高并發我們想到的是高吞吐,流量洪峰;如何提高高并發我們可以從單機的性能優化,和集群的擴展來進行提高我們系統的并發能力,其實系統的高性能直接就提高了系統的高并發,上面的高性能篇主要是從單機的維度提高處理的速度來提高單機的并發處理能力,本章主要從集群的維度通過擴展:水平擴展,縱向擴展,垂直擴展三維立體來提高系統的并發能力。
3.1 方法論
3.1.1 X軸:水平擴展
水平擴展就是擴容,是我們采用最多的抗并發的措施:加機器,擴分片,每年618,雙11大促時,這是我們的常規操作,現有分組下的機器處理能力有限,我們通過擴容來應對大促的流量,擴容我們分為應用層和存儲層,應用層都是無狀態的服務,我們可以通過公司部署平臺行云快速的擴容增加機器,存儲層的擴容相對比較麻煩,新增分片后,還涉及到數據的遷移以及分片規則的調整。
3.1.2 Y軸:縱向擴展
整個軟件應用的架構經歷單體應用,SOA, 微服務,服務網格的演進。早期的架構風格所有的服務功能都融合在單體應用中,通過單體服務來抗所有的流量,后來隨著業務的復雜性和用戶的增多以及我們基于對業務的深入理解采用DDD(領域驅動設計)來指導我們按照領域劃分服務,進行微服務建設,下圖是一個電商的單體應用到按照DDD進行微服務劃分的一個演進過程。
?
?
3.1.3 Z軸:垂直擴展
當我們在應用層進行水平擴展時,每增加一臺機器都會增加數據庫的訪問鏈接,數據庫的連接數屬于寶貴資源,達到上限后,應用層再擴容就會出現連接數耗盡的異常,此時存儲層成了整個系統高并發的瓶頸,針對數據庫我們一般采用分片(分而治之)的思想:分庫分表,通過增加庫實例來增加訪問的連接數,下圖是訂單進行分庫分表的架構。
?
集群中數據庫的主從庫數量是有限制的的,達到最大限制后,一個機房的數據庫集群成了系統的瓶頸,解決方案是進行單元化建設,系統的流量和數據閉環在一個單元,這個單元分布在全國甚至全世界不同的地域,而不是集中在某個機房某個地域,北京的系統單元為北京用戶提供服務,上海的系統單元為上海用戶提供服務,就類似于京東物流的倉庫一樣,建在離用戶最近的地方,北京倉服務北京用戶,上海倉服務上海用戶。大家可以看到系統的建設和業務的發展底層的思想都是統一的,中國的頭部互聯網還都是業務驅動,所以技術要服務好業務。總之我們可以看到通過分庫分表和單元化這種垂直擴展提高并發的同時也增強了系統的可用性,下圖是我們進行單元化建設的過程。
?
3.2 幾個實踐問題的探討
3.2.1 DDD在零售物流平臺的實踐
縱向的擴展,我們采用DDD進行領域的劃分進行微服務的建設,DDD的實踐必須基于對業務的深入理解,所以作為技術人員,如果想將DDD很好的落地,必須和業務專家,產品一起頭腦風暴,技術前置去了解業務。研發可以從業務流程上去了解業務,然后基于業務流程進行領域劃分;
3.2.1.1 業務流程
正向流程:從B端商家視角來看,商家選擇服務商品比如卓配產品后,進行下單,服務商進行接單,分配快遞員,快遞員上門取件,對用戶郵寄的貨品進行稱重量方,詢價計費,然后商家支付運費,快遞員完成攬收,進入履約層面:貨品進行運輸,配送,直至C端用戶簽收完成妥投。
逆向流程:從C端用戶視角來看,用戶需要申請售后退貨,待商家審核通過后,選擇相應的商品服務進行下單,后續的流程和正向流程類似。
3.2.1.2 應用領域劃分
應用領域的劃分主要根據我們的業務流程介紹提供了那些功能;目前我們系統支撐的業務來源包括:零售的商家后臺(京麥),訂單中臺,售后,傳美,快遞鳥,中鐵,統一發貨平臺等等;
從需求側來看,我們的上游包括了京東物流,京東零售,京東工業,外部的ISV等給物流平臺下單;
從供給側來看,我們的服務商包括:京東快遞,快運,中通,圓通,韻達等來提供履約的能力;
從領域劃分角度來看,將領域劃分為:商品服務域,訂單域,支付結算域,履約域,每個領域包括了提供的功能如下圖;至于為啥這樣劃分,我的思考是這樣的,相較于C端零售側的電商交易,我們是服務于商家的B端物流側的物流交易;C端零售針對于用戶提供的是實物的商品:手機,電腦;B端物流針對于商家提供的是虛擬的商品:一種履約物流服務,將貨品從商家交付到用戶;所以無論是我們的卓配產品還是電子面單產品,我們為商戶提供了這些虛擬商品,商家選擇這些虛擬商品后,就可以下單,取消,改單,支付,服務商進行履約;
3.2.2 熱key處理
垂直的擴展,在百億補貼,大促,秒殺場景下,相關sku會成為訪問的熱點,如果將相關sku存儲到某個單一的分片則可能出現流量訪問傾斜的問題,某個分片會承擔大部分的流量出現性能變差甚至分片被打垮的情況;針對熱key的問題我們可以采用如下兩種解決方案:
本地緩存:在應用層增加本地緩存;先查本地緩存,本地緩存沒有查詢分布式緩存,分布式緩存沒有查詢數據庫;
隨機數法:針對某個key,我們可以在這個key后面增加一個隨機數,比如增加兩位的隨機,就可以將該key分散到100個分片上,避免熱點分片
總之無論是本地緩存還是key+隨機數,都是將熱key分散到不同的節點上來分散流量,提高并發的同時,也避免流量傾斜,將某個節點打垮;
4 高可用篇
保證系統的可用性是系統建設中的重中之重,如果沒有可用性,高性能和高并發也無從談起,高可用的建設通常是通過保護系統和冗余的方法來進行容錯保證系統的可用性。本篇主要從三個維度:應用層,存儲層,部署層談下可用性的建設。應用層的內容來自我的另一篇文章: http://sd.jd.com/article/33612?shareId=224276&isHideShareButton=1
4.1 方法論
4.1.1 應用層
4.1.1.1 限流
限流一般是從服務提供者provider的視角提供的針對自我保護的能力,對于流量負載超過我們系統的處理能力,限流策略可以防止我們的系統被激增的流量打垮。京東內部無論是同步交互的JSF, 還是異步交互的JMQ都提供了限流的能力,大家可以根據自己系統的情況進行設置;我們知道常見的限流算法包括:計數器算法,滑動時間窗口算法,漏斗算法,令牌桶算法,具體算法可以網上google下,下面是這些算法的優缺點對比。
算法 | 優點 | 缺點 |
流量計數器算法 | 簡單好理解 | 單位時間很難把控,不平滑 |
滑動時間窗口算法 | 時間好把控 | 1 超過窗口時間的流量就丟棄或降級 2 沒有辦法削峰填谷 |
漏桶算法 | 削峰填谷 | 1 漏桶大小的控制,太大給服務端造成壓力,太小大量請求被丟棄 2 漏桶給下游發送請求的速率固定 |
令牌桶算法 | 1 削峰填谷 2 動態控制令牌桶的大小,從而控制向下游發送請求的速率 | 1 實現相對復雜 2 只能預先設計不適配突發 |
4.1.1.2 熔斷降級
熔斷和降級是兩件事情,但是他們一般是結合在一起使用的。熔斷是防止我們的系統被下游系統拖垮,比如下游系統接口性能嚴重變差,甚至下游系統掛了;這個時候會導致大量的線程堆積,不能釋放占用的CPU,內存等資源,這種情況下不僅影響該接口的性能,還會影響其他接口的性能,嚴重的情況會將我們的系統拖垮,造成雪崩效應,通過打開熔斷器,流量不再請求到有問題的系統,可以保護我們的系統不被拖垮。降級是一種有損操作,我們作為服務提供者,需要將這種損失盡可能降到最低,無論是返回友好的提示,還是返回可接受的降級數據。降級細分的話又分為人工降級,自動降級。
人工降級:人工降級一般采用降級開關來控制,公司內部一般采用配置中心Ducc來做開關降級,開關的修改也是線上操作,這塊也需要做好監控
自動降級:自動降級是采用自動化的中間件例如Hystrix,公司的小盾龍等;如果采用自動降級的話;我們必須要對降級的條件非常的明確,比如失敗的調用次數等;
4.1.1.3 超時設置
分布式系統中的難點之一:不可靠的網絡,京東物流現有的微服務架構下,服務之間都是通過JSF網絡交互進行同步通信,我們探測下游依賴服務是否可用的最快捷的方式是設置超時時間。超時的設置可以讓系統快速失敗,進行自我保護,避免無限等待下游依賴系統,將系統的線程耗盡,系統拖垮;
超時時間如何設置也是一門學問,如何設置一個合理的超時時間也是一個逐步迭代的過程,比如下游新開發的接口,一般會基于壓測提供一個TP99的耗時,我們會基于此配置超時時間;老接口的話,會基于線上的TP99耗時來配置超時時間。
超時時間在設置的時候需要遵循漏斗原則,從上游系統到下游系統設置的超時時間要逐漸減少,如下圖所示。為什么要滿足漏斗原則,假設不滿足漏斗原則,比如服務A調取服務B的超時時間設置成500ms,而服務B調取服務C的超時時間設置成800ms,這個時候回導致服務A調取服務B大量的超時從而導致可用率降低,而此時服務B從自身角度看是可用的;
?
4.1.1.4 重試
分布式系統中性能的影響主要是通信,無論是在分布式系統中還是垮團隊溝通,communication是最昂貴的;比如我們研發都知道需求的交付有一半以上甚至更多的時間花在跨團隊的溝通上,真正寫代碼的時間是很少的;分布式系統中我們查看調用鏈路,其實我們系統本身計算的耗時是很少的,主要來自于外部系統的網絡交互,無論是下游的業務系統,還是中間件:Mysql, redis, es等等;所以在和外部系統的一次請求交互中,我們系統是希望盡最大努力得到想要的結果,但往往事與愿違,由于不可靠網絡的原因,我們在和下游系統交互時,都會配置超時重試次數,希望在可接受的SLA范圍內一次請求拿到結果,但重試不是無限的重試,我們一般都是配置重試次數的限制,偶爾抖動的重試可以提高我們系統的可用率,如果下游服務故障掛掉,重試反而會增加下游系統的負載,從而增加故障的嚴重程度。在一次請求調用中,我們要知道對外提供的API,后面是有多少個service在提供服務,如果調用鏈路比較長,服務之間rpc交互都設置了重試次數,這個時候我們需要警惕重試風暴。如下圖service D 出現問題,重試風暴會加重service D的故障嚴重程度。對于API的重試,我們還要區分該接口是讀接口還是寫接口,如果是讀接口重試一般沒什么影響,寫接口重試一定要做好接口的冪等性。
?
4.1.1.5 隔離
隔離是將故障爆炸半徑最小化的有效手段,我們通過不同層面的隔離來控制影響范圍,保證系統的高可用:
4.1.1.5.1 系統建設層面隔離
我們知道系統的分類可以分為:在線的系統,離線系統(批處理系統),近實時系統(流處理系統),如下是這些系統的定義:
在線系統:服務端等待請求的到達,接收到請求后,服務盡可能快的處理,然后返回給客戶端一個響應,響應時間通常是在線服務性能的主要衡量指標。我們生活中在手機使用的APP大部分都是在線系統;
離線系統:或稱批處理系統,接收大量的輸入數據,運行一個作業來處理數據,并產出輸出數據,作業往往需要定時,定期運行一段時間,比如從幾分鐘到幾天,所以用戶通常不會等待作業完成,吞吐量是離線系統的主要衡量指標。例如我們看到的報表數據:日訂單量,月訂單量,日活躍用戶數,月活躍用戶數都是批處理系統運算一段時間得到的;
近實時系統:或者稱流處理系統,其介于在線系統和離線系統之間,流處理系統一般會有觸發源:用戶的行為操作,數據庫的寫操作,傳感器等,觸發源作為消息會通過消息代理中間件:JMQ, KAFKA等進行傳遞,消費者消費到消息后再做其他的操作,例如構建緩存,索引,通知用戶等;
以上三種系統是需要進行隔離建設的,因為他們的衡量指標及對資源的使用情況完全不一樣的,比如我們小組會將在線系統作為一個服務單獨部署:jdl-uep-main, 離線系統和近實時系統作為一個服務單獨部署:jdl-uep-worker;
4.1.1.5.2 環境的隔離
從研發到上線階段我們會使用不同的環境,比如業界常見的環境分為:開發,測試,預發和線上環境;研發人員在開發環境進行開發和聯調,測試人員在測試環境進行測試,運營和產品在預發環境進行UAT,最終交付的產品部署到線上環境提供給用戶使用。在研發流程中,我們部署時要遵循從應用層到中間件層再到存儲層,都要在一個環境,嚴禁垮環境的調用,比如測試環境調用線上,預發環境調用線上等。
?
?
4.1.1.5.3 數據隔離
隨著業務的發展,我們對外提供的服務往往會支撐多業務,多租戶,所以這個時候我們會按照業務進行數據隔離;比如我們組產生的物流訂單數據業務方就包含京東零售,其他電商平臺,ISV等,為了避免彼此的影響我們需要在存儲層對數據進行隔離,數據的隔離可以按照不同粒度,第一種是通過租戶id字段進行區分,所有的數據存儲在一張表中,另外一個是庫粒度的區分,不同的租戶單獨分配對應的數據庫。
?
數據的隔離除了按照業務進行隔離外,還有按照環境進行隔離的,比如我們的數據庫分為測試庫,預發庫,線上庫,全鏈路壓測時,我們為了模擬線上的環境,同時避免污染線上的數據,往往會創建影子庫,影子表等。根據數據的訪問頻次進行隔離,我們將經常訪問的數據稱為熱數據,不經常訪問的數據稱為冷數據;將經常訪問的數據緩存到緩存,提高系統的性能。不經常訪問的數據持久化到數據庫或者將不使用的數據結轉歸檔到OSS,避免大庫大表。
4.1.1.5.4 核心/非核心流程隔離
我們知道應用是分級的,京東內部針對應用的重要程度會將應用分為0,1,2,3級應用。業務的流程也分為黃金流程和非黃金流程。在業務流程中,針對不同級別的應用交互,需要將核心和非核心的流程進行隔離。例如在交易業務過程中,會涉及到訂單系統,支付系統,通知系統,那這個過程中核心系統是訂單系統和支付系統,而通知相對來說重要性不是那么高,所以我們會投入更多的資源到訂單系統和支付系統,優先保證這兩個系統的穩定性,通知系統可以采用異步的方式與其他兩個系統解耦隔離,避免對其他另外兩個系統的影響。
?
4.1.1.5.5 讀寫隔離
應用層面,領域驅動設計(DDD)中最著名的CQRS(Command Query Responsibility Segregation)將寫服務和讀服務進行隔離。寫服務主要處理來自客戶端的command寫命令,而讀服務處理來自客戶端的query讀請求,這樣從應用層面進行讀寫隔離,不僅可以提高系統的可擴展性,同時也會提高系統的可維護性,應用層面我們都采用微服務架構,應用層都是無狀態服務,可以擴容加機器隨意擴展,存儲層需要持久化,擴展就比較費勁。除了應用層面的CQRS,在存儲層面,我們也會進行讀寫隔離,例如數據庫都會采用一主多從的架構,讀請求可以路由到從庫從而分擔主庫的壓力,提高系統的性能和吞吐量。所以應用層面通過讀寫隔離主要解決可擴展問題,存儲層面主要解決性能和吞吐量的問題。
?
4.1.1.5.6 線程池隔離
線程是昂貴的資源,為了提高線程的使用效率,復用線程,避免創建和銷毀的消耗,我們采用了池化技術,線程池,但是在使用線程的過程中,我們也做好線程池的隔離,避免多個API接口復用同一個線程。
?
?
4.1.1.6 兼容
我們在對老系統,老功能進行重構迭代的時候,一定要做好兼容,否則上線后會出現重大的線上問題,公司內外有大量因為沒有做好兼容性,而導致資損的情況。兼容分為:向前兼容性和向后兼容性,需要好好的區分他們,如下是他們的定義:
向前兼容性:向前兼容性指的是舊版本的軟件或硬件能夠與將來推出的新版本兼容的特性,簡而言之舊版本軟件或系統兼容新的數據和流量。
向后兼容性:向后兼容性則是指新版本的軟件或硬件能夠與之前版本的系統或組件兼容的特性,簡而言之新版本軟件或系統兼容老的數據和流量。
根據新老系統和新老數據我們可以將系統劃分為四個象限:第一象限:新系統和新數據是我們系統改造上線后的狀態,第三象限:老系統和老數據是我們系統改造上線前的狀態,第一象限和第三象限的問題我們在研發和測試階段一般都能發現排除掉,線上故障的高發期往往出現在第二和第四象限,第二象限是因為沒有做好向前兼容性,例如上線過程中,發現問題進行了代碼回滾,但是在上線過程中產生了新數據,回滾后的老系統不能處理上線過程中新產生的數據,導致線上故障。第四象限是因為沒有做好向后兼容性,上線后新系統影響了老流程。針對第二象限的問題,我們可以構造新的數據去驗證老的系統,針對第四象限的問題,我們可以通過流量的錄制回放解決,錄制線上的老流量,對新功能進行驗證。
4.1.2 存儲層
存儲層主要通過復制和分片來保證存儲層的高可用,復制主要是通過副本(主從節點,主從副本)來保證高可用,分片是將數據分散到不同的節點上來保證高可用(雞蛋不要放在同一個籃子中)。復制和分片在保證高可用的情況下,其實也提高了系統的高性能和高并發,復制和分片的思想在Mysql,Redis,ElasticSearch, kafka中都進行了采用。
4.1.2.1 復制
復制技術是一份數據的完整的拷貝,思想是通過冗余保證高可用。復制又可以分為:主從復制,多主復制,無主復制。
主從復制:客戶端將所有寫入操作發送到單個節點(主庫),該節點將數據更改事件流發送到其他副本(從庫)。讀取可以在任何副本上執行,但從庫的讀取結果可能是陳舊的。
多主復制:客戶端將每個寫入發送到幾個主庫節點之一,其中任何一個主庫都可以接受寫入。主庫將數據更改事件流發送給彼此以及任何從庫節點。
無主復制:客戶端將每個寫入發送到幾個節點,并從多個節點并行讀取,以檢測和糾正具有陳舊數據的節點。
4.1.2.2 分區
分區也稱為分片,對于非常大的數據集在單節點進行存儲時,一方面可用性比較低(雞蛋放在同一個籃子中),另一方面也會遇到存儲和性能的瓶頸,我們需要將大的數據集通過負載均衡分片到不同的節點上,每條數據(每條記錄,每行或每個文檔)屬于且僅屬于一個分區,每個分區都是自己的小型數據庫。分區我們分為鍵范圍分區,散列分區。
鍵范圍分區:其中鍵是有序的,并且分區擁有從某個最小值到某個最大值的所有鍵。排序的優勢在于可以進行有效的范圍查詢,但是如果應用程序經常訪問相鄰的鍵,則存在熱點的風險。在這種方法中,當分區變得太大時,通常將分區分成兩個子分區來動態地重新平衡分區。
散列分區:散列函數應用于每個鍵,分區擁有一定范圍的散列。這種方法破壞了鍵的排序,使得范圍查詢效率低下,但可以更均勻地分配負載。通過散列進行分區時,通常先提前創建固定數量的分區,為每個節點分配多個分區,并在添加或刪除節點時將整個分區從一個節點移動到另一個節點。也可以使用動態分區。
4.1.2.3 Redis 的復制和分片
redis cluster集群中,我們會劃分16384個槽,key 通過散列哈希算法會映射到相應的槽中,這些槽分配到不同的分片上,每個分片有主節點和從節點,主節點對外提供讀寫服務,從節點對外提供讀服務。當某個分片的主節點掛掉,其他分片的主節點會從掛掉分片的從節點選擇一個作為主節點繼續對外提供服務。整體的架構如下圖所示
?
4.1.2.4 ES索引的復制和分片
我們在創建ES索引時,會指定分片的數量和副本的數量,分片的數量確定后是不允許修改的,副本的數量允許修改,分片的數量一般和數據節點的數量保持一致,這樣能將索引的數據分配到每個數據節點上,每個數據節點都存儲索引的部分數據,Primary分片可以對外提供讀寫服務,Replica分片對外提供讀服務的同時作為備份節點保證可用性,ES索引的不同分片在不同數據節點的分布如下圖所示。
4.1.2.5 Kafka topic的復制和分區
kafka的topic為了提高可用性及高吞吐,引入了topic的分區,每個分區為了提高可用性,分區分為Leader partition 和 Follower partition,Leader partition對外提供讀寫服務,Follower partition作為災備提高可用性,整體的架構如下圖;
4.1.3 部署層
4.1.3.1 業界部署架構的演進
部署層是通過不斷突破單機器,單機房,單地域,做到機器級別,機房級別,地域級別的容災來保證系統的高可用。核心思想是通過冗余以及負載均衡進行容災保證高可用。
4.1.3.2 我們部署架構現狀
目前我們的應用都是采用多機房多分組Docker容器化部署,會根據業務方的重要程度及流量大小設置不同的別名,隔離到不同的分組中對外提供服務。
?應用容器機房為:中云信,有孚,廊坊,宿遷等;
?數據庫Mysql雙機房部署:中云信,有孚;
?緩存Redis雙機房部署:中云信,有孚;
?ES單機房部署:有孚;
審核編輯 黃宇
-
接口
+關注
關注
33文章
8689瀏覽量
151677 -
數據庫
+關注
關注
7文章
3845瀏覽量
64587 -
機房
+關注
關注
0文章
437瀏覽量
17177
發布評論請先 登錄
相關推薦
評論