国产av一二三区|日本不卡动作网站|黄色天天久久影片|99草成人免费在线视频|AV三级片成人电影在线|成年人aV不卡免费播放|日韩无码成人一级片视频|人人看人人玩开心色AV|人妻系列在线观看|亚洲av无码一区二区三区在线播放

網(wǎng)易首頁(yè) > 網(wǎng)易號(hào) > 正文 申請(qǐng)入駐

一文看懂Netflix分布式計(jì)數(shù)器設(shè)計(jì)!

0
分享至

點(diǎn)擊下方“JavaEdge”,選擇“設(shè)為星標(biāo)”

第一時(shí)間關(guān)注技術(shù)干貨!


免責(zé)聲明~ 任何文章不要過(guò)度深思! 萬(wàn)事萬(wàn)物都經(jīng)不起審視,因?yàn)槭郎蠜](méi)有同樣的成長(zhǎng)環(huán)境,也沒(méi)有同樣的認(rèn)知水平,更「沒(méi)有適用于所有人的解決方案」; 不要急著評(píng)判文章列出的觀點(diǎn),只需代入其中,適度審視一番自己即可,能「跳脫出來(lái)從外人的角度看看現(xiàn)在的自己處在什么樣的階段」才不為俗人。 怎么想、怎么做,全在乎自己「不斷實(shí)踐中尋找適合自己的大道」

0 引言

之前博客文章介紹了Netflix的時(shí)間序列抽象,這是一個(gè)設(shè)計(jì)用來(lái)存儲(chǔ)和查詢(xún)大量時(shí)間事件數(shù)據(jù)的分布式服務(wù),具有低毫 秒級(jí)別的延遲。今天,我們很高興向大家介紹分布式計(jì)數(shù)器抽象。這個(gè)計(jì)數(shù)服務(wù)建立在時(shí)間序列抽象之上,能夠在保持類(lèi)似的低延遲性能的同時(shí),實(shí)現(xiàn)大規(guī)模的分布式計(jì)數(shù)。和我們所有的抽象一樣,我們使用我們的數(shù)據(jù)網(wǎng)關(guān)控制平面來(lái)分片、配置和全球部署這項(xiàng)服務(wù)。

分布式計(jì)數(shù)是計(jì)算機(jī)科學(xué)中的一個(gè)挑戰(zhàn)性問(wèn)題。在這篇博客文章中,我們將探討Netflix在計(jì)數(shù)需求上的多樣性,實(shí)現(xiàn)近乎實(shí)時(shí)準(zhǔn)確計(jì)數(shù)的挑戰(zhàn),以及我們選擇的方法背后的理念,包括必要的權(quán)衡。

注意:在談到分布式計(jì)數(shù)器時(shí),像“準(zhǔn)確”或“精確”這樣的術(shù)語(yǔ)應(yīng)該謹(jǐn)慎理解。在這個(gè)上下文中,它們指的是非常接近準(zhǔn)確,并且以最小的延遲呈現(xiàn)的計(jì)數(shù)。

用例和需求

在Netflix,我們的計(jì)數(shù)用例包括跟蹤數(shù)百萬(wàn)用戶(hù)交互、監(jiān)控特定功能或體驗(yàn)向用戶(hù)展示的頻率,以及在A/B測(cè)試實(shí)驗(yàn)中統(tǒng)計(jì)數(shù)據(jù)的多個(gè)方面等。

在Netflix,這些用例可以分為兩大類(lèi)別:

  1. 盡力而為:對(duì)于這一類(lèi)別的計(jì)數(shù),不需要非常準(zhǔn)確或持久。然而,這一類(lèi)別需要以低延遲近實(shí)時(shí)地訪問(wèn)當(dāng)前計(jì)數(shù),同時(shí)將基礎(chǔ)設(shè)施成本保持在最低。

  2. 最終一致性:這一類(lèi)別需要準(zhǔn)確和持久的計(jì)數(shù),并愿意接受準(zhǔn)確性的輕微延遲和稍高的基礎(chǔ)設(shè)施成本作為權(quán)衡。

這兩類(lèi)用例都有共同的需求,如高吞吐量和高可用性。下表提供了這兩類(lèi)用例不同需求的詳細(xì)概述。

為了滿足上述需求,計(jì)數(shù)器抽象被設(shè)計(jì)為高度可配置。它允許用戶(hù)在盡力而為最終一致性等不同的計(jì)數(shù)模式之間選擇,同時(shí)考慮每種選項(xiàng)的文檔化權(quán)衡。在選擇模式后,用戶(hù)可以與API交互,而無(wú)需擔(dān)心底層的存儲(chǔ)機(jī)制和計(jì)數(shù)方法。

讓我們更仔細(xì)地看看API的結(jié)構(gòu)和功能。

API

計(jì)數(shù)器被組織到用戶(hù)為他們特定用例設(shè)置的單獨(dú)命名空間中。每個(gè)命名空間都可以使用服務(wù)的控制平面配置不同的參數(shù),如計(jì)數(shù)器類(lèi)型、生存時(shí)間(TTL)和計(jì)數(shù)器基數(shù)。

計(jì)數(shù)器抽象API類(lèi)似于Java的AtomicInteger接口:

AddCount/AddAndGetCount:通過(guò)給定的增量值調(diào)整指定計(jì)數(shù)器在數(shù)據(jù)集中的計(jì)數(shù)。增量值可以是正數(shù)或負(fù)數(shù)。AddAndGetCount對(duì)應(yīng)方法在執(zhí)行添加操作后還返回計(jì)數(shù)。

{
"namespace": "my_dataset",
"counter_name": "counter123",
"delta": 2,
"idempotency_token": {
"token": "some_event_id",
"generation_time": "2024-10-05T14:48:00Z"
}
}

如果支持,冪等令牌可以用于計(jì)數(shù)器類(lèi)型??蛻?hù)端可以使用此令牌安全地重試或?qū)_他們的請(qǐng)求。分布式系統(tǒng)中的失敗是必然的,能夠安全地重試請(qǐng)求增強(qiáng)了服務(wù)的可靠性。

GetCount:檢索指定計(jì)數(shù)器在數(shù)據(jù)集中的計(jì)數(shù)值。

{
"namespace": "my_dataset",
"counter_name": "counter123"
}

ClearCount:將指定計(jì)數(shù)器在數(shù)據(jù)集中的計(jì)數(shù)有效地重置為0。

{
"namespace": "my_dataset",
"counter_name": "counter456",
"idempotency_token": {...}
}

現(xiàn)在,讓我們看看抽象中支持的不同類(lèi)型計(jì)數(shù)器。

計(jì)數(shù)器類(lèi)型

該服務(wù)主要支持兩種類(lèi)型的計(jì)數(shù)器:盡力而為最終一致性,以及第三種實(shí)驗(yàn)類(lèi)型:準(zhǔn)確。在接下來(lái)的部分中,我們將描述這些類(lèi)型的計(jì)數(shù)器的不同方法以及每種方法相關(guān)的權(quán)衡。

盡力而為區(qū)域計(jì)數(shù)器

這種類(lèi)型的計(jì)數(shù)器由EVCache提供支持,EVCache是Netflix基于廣泛流行的Memcached構(gòu)建的分布式緩存解決方案。它適用于A/B實(shí)驗(yàn)等用例,其中許多并發(fā)實(shí)驗(yàn)在短時(shí)間內(nèi)運(yùn)行,并且足夠近似的計(jì)數(shù)就足夠了。拋開(kāi)配置、資源分配和控制平面管理的復(fù)雜性不談,這個(gè)解決方案的核心非常簡(jiǎn)單:

// 計(jì)數(shù)器緩存鍵
counterCacheKey = :

// 添加操作
return delta > 0
? cache.incr(counterCacheKey, delta, TTL)
: cache.decr(counterCacheKey, Math.abs(delta), TTL);

// 獲取操作
cache.get(counterCacheKey);

// 從所有副本中清除計(jì)數(shù)
cache.delete(counterCacheKey, ReplicaPolicy.ALL);

EVCache在單個(gè)區(qū)域內(nèi)提供極低毫秒延遲或更好的極高吞吐量,支持共享集群中的多租戶(hù)設(shè)置,節(jié)省基礎(chǔ)設(shè)施成本。然而,有一些權(quán)衡:它缺乏跨區(qū)域復(fù)制增加操作的能力,并且不提供一致性保證,這可能對(duì)準(zhǔn)確計(jì)數(shù)是必要的。此外,不支持原生冪等性,使得重試或?qū)_請(qǐng)求不安全。

**編輯:關(guān)于概率數(shù)據(jù)結(jié)構(gòu)的注釋?zhuān)?/p>

像HyperLogLog(HLL)這樣的概率數(shù)據(jù)結(jié)構(gòu)對(duì)于跟蹤不同元素的近似數(shù)量(如網(wǎng)站的不同視圖或訪問(wèn)次數(shù))很有用,但并不適合于實(shí)現(xiàn)給定鍵的獨(dú)立增加和減少。Count-Min Sketch(CMS)是另一種選擇,可以用來(lái)通過(guò)給定的數(shù)量調(diào)整鍵的值。像Redis這樣的數(shù)據(jù)存儲(chǔ)支持HLL和CMS。然而,我們選擇不采取這個(gè)方向有幾個(gè)原因:

  • 我們選擇在我們已經(jīng)大規(guī)模運(yùn)營(yíng)的數(shù)據(jù)存儲(chǔ)之上構(gòu)建。

  • 概率數(shù)據(jù)結(jié)構(gòu)不支持我們的一些需求,如重置給定鍵的計(jì)數(shù)或?yàn)橛?jì)數(shù)設(shè)置TTL。需要額外的數(shù)據(jù)結(jié)構(gòu),包括更多的草圖,以支持這些需求。

  • 另一方面,EVCache解決方案非常簡(jiǎn)單,只需要最少的代碼行,并使用原生支持的元素。然而,這是以使用每個(gè)計(jì)數(shù)器鍵的少量?jī)?nèi)存為代價(jià)的。

最終一致性全球計(jì)數(shù)器

雖然一些用戶(hù)可能接受盡力而為計(jì)數(shù)器的限制,但其他用戶(hù)選擇精確計(jì)數(shù)、持久性和全球可用性。在接下來(lái)的部分中,我們將探索實(shí)現(xiàn)持久和準(zhǔn)確計(jì)數(shù)的各種策略。我們的目標(biāo)是突出全球分布式計(jì)數(shù)固有的挑戰(zhàn),并解釋我們選擇的方法背后的原因。

方法1:每個(gè)計(jì)數(shù)器存儲(chǔ)一行

讓我們從使用全球復(fù)制數(shù)據(jù)存儲(chǔ)中的表中每個(gè)計(jì)數(shù)器鍵存儲(chǔ)一行開(kāi)始。

讓我們檢查這種方法的一些缺點(diǎn):

  • 缺乏冪等性:存儲(chǔ)數(shù)據(jù)模型中沒(méi)有內(nèi)置的冪等鍵,阻止用戶(hù)安全地重試請(qǐng)求。實(shí)現(xiàn)冪等性可能需要使用外部系統(tǒng)來(lái)存儲(chǔ)這些鍵,這可能會(huì)進(jìn)一步降低性能或引起競(jìng)態(tài)條件。

  • 高爭(zhēng)用:為了可靠地更新計(jì)數(shù),每個(gè)寫(xiě)入者必須對(duì)給定的計(jì)數(shù)器執(zhí)行Compare-And-Swap操作,使用鎖或事務(wù)。根據(jù)操作的吞吐量和并發(fā)性,這可能導(dǎo)致顯著的爭(zhēng)用,嚴(yán)重影響性能。

輔助鍵:減少這種方法中的爭(zhēng)用的一種方式是使用輔助鍵,如bucket_id,它允許通過(guò)將給定的計(jì)數(shù)器分成桶來(lái)分布寫(xiě)入,同時(shí)允許讀取跨桶聚合。挑戰(zhàn)在于確定適當(dāng)?shù)耐皵?shù)。靜態(tài)數(shù)字仍可能導(dǎo)致熱鍵爭(zhēng)用,而動(dòng)態(tài)分配每個(gè)計(jì)數(shù)器的桶數(shù)涉及更復(fù)雜的問(wèn)題。

讓我們看看我們是否可以迭代我們的解決方案來(lái)克服這些缺點(diǎn)。

方法2:每個(gè)實(shí)例聚合

為了解決實(shí)時(shí)寫(xiě)入同一行的熱鍵和爭(zhēng)用問(wèn)題,我們可以實(shí)施一種策略,即每個(gè)實(shí)例在內(nèi)存中聚合計(jì)數(shù),然后定期將它們刷新到磁盤(pán)。引入足夠的抖動(dòng)到刷新過(guò)程中可以進(jìn)一步減少爭(zhēng)用。

然而,這個(gè)解決方案提出了一系列新問(wèn)題:

  • 數(shù)據(jù)丟失的脆弱性:該解決方案對(duì)實(shí)例故障、重啟或部署期間的所有內(nèi)存數(shù)據(jù)丟失都很脆弱。

  • 無(wú)法可靠地重置計(jì)數(shù):由于計(jì)數(shù)請(qǐng)求分布在多臺(tái)機(jī)器上,很難就計(jì)數(shù)器重置發(fā)生的確切時(shí)間點(diǎn)建立共識(shí)。

  • 缺乏冪等性:與之前的方法類(lèi)似,這種方法不原生保證冪等性。實(shí)現(xiàn)冪等性的一種方式是通過(guò)始終將相同的一組計(jì)數(shù)器路由到同一實(shí)例。然而,這種方法可能會(huì)引入額外的復(fù)雜性,如領(lǐng)導(dǎo)者選舉,以及在寫(xiě)入路徑上的可用性和延遲方面的潛在挑戰(zhàn)。

盡管如此,如果這些權(quán)衡是可以接受的,這種方法仍然適用。然而,讓我們看看我們是否可以采用不同的基于事件的方法來(lái)解決這些問(wèn)題。

方法3:使用持久隊(duì)列

在這種方法中,我們將計(jì)數(shù)器事件記錄到像Apache Kafka這樣的持久隊(duì)列系統(tǒng)中,以防止任何潛在的數(shù)據(jù)丟失。通過(guò)創(chuàng)建多個(gè)主題分區(qū)并將計(jì)數(shù)器鍵散列到特定分區(qū),我們確保相同的一組計(jì)數(shù)器由同一組消費(fèi)者處理。這種設(shè)置簡(jiǎn)化了冪等性檢查和重置計(jì)數(shù)。此外,通過(guò)利用額外的流處理框架,如Kafka Streams或Apache Flink,我們可以實(shí)施窗口聚合。

然而,這種方法帶來(lái)了一些挑戰(zhàn):

  • 潛在的延遲:同一個(gè)消費(fèi)者處理來(lái)自給定分區(qū)的所有計(jì)數(shù)可能導(dǎo)致備份和延遲,從而產(chǎn)生陳舊的計(jì)數(shù)。

  • 重新平衡分區(qū):這種方法需要隨著計(jì)數(shù)器基數(shù)和吞吐量的增加自動(dòng)縮放和重新平衡主題分區(qū)。

此外,所有預(yù)聚合計(jì)數(shù)的方法都很難支持我們的準(zhǔn)確計(jì)數(shù)要求中的兩個(gè):

  • 計(jì)數(shù)審計(jì):審計(jì)涉及將數(shù)據(jù)提取到離線系統(tǒng)進(jìn)行分析,以確保增量正確應(yīng)用于最終值。這個(gè)過(guò)程也可以用來(lái)跟蹤增量的來(lái)源。然而,當(dāng)計(jì)數(shù)被聚合而沒(méi)有存儲(chǔ)單個(gè)增量時(shí),審計(jì)變得不可行。

  • 可能的重新計(jì)數(shù):類(lèi)似于審計(jì),如果需要對(duì)增量進(jìn)行調(diào)整并且需要在時(shí)間窗口內(nèi)重新計(jì)數(shù)事件,預(yù)聚合計(jì)數(shù)使得這變得不可行。

除了這些需求之外,如果我們確定如何擴(kuò)展我們的隊(duì)列分區(qū)和消費(fèi)者同時(shí)保持冪等性,這種方法仍然有效。然而,讓我們探索如何調(diào)整這種方法以滿足審計(jì)和重新計(jì)數(shù)的要求。

方法4:事件日志中的單個(gè)增量

在這種方法中,我們記錄每個(gè)單獨(dú)的計(jì)數(shù)器增量及其event_timeevent_id。event_id可以包括增量來(lái)源的信息。event_time和event_id的組合也可以作為給定計(jì)數(shù)器事件的冪等鍵。

然而,在其最簡(jiǎn)單的形式中,這種方法有幾個(gè)缺點(diǎn):

  • 讀取延遲:每個(gè)讀取請(qǐng)求都需要掃描給定計(jì)數(shù)器的所有增量,可能會(huì)降低性能。

  • 重復(fù)工作:多個(gè)線程可能會(huì)重復(fù)聚合相同的一組計(jì)數(shù)器,在讀取操作中,導(dǎo)致浪費(fèi)努力和資源利用不佳。

  • 寬分區(qū):如果使用像Apache Cassandra這樣的數(shù)據(jù)存儲(chǔ),為同一計(jì)數(shù)器存儲(chǔ)許多增量可能會(huì)導(dǎo)致寬分區(qū),影響讀取性能。

  • 大數(shù)據(jù)占用:?jiǎn)为?dú)存儲(chǔ)每個(gè)增量也可能導(dǎo)致隨著時(shí)間的推移數(shù)據(jù)占用量顯著增加。如果沒(méi)有有效的數(shù)據(jù)保留策略,這種方法可能難以有效擴(kuò)展。

這些問(wèn)題的綜合影響可能導(dǎo)致基礎(chǔ)設(shè)施成本增加,可能難以證明其合理性。然而,采用事件驅(qū)動(dòng)的方法似乎是解決我們遇到的一些挑戰(zhàn)并滿足我們需求的重要一步。

我們?nèi)绾芜M(jìn)一步改進(jìn)這個(gè)解決方案?

Netflix的方法

我們結(jié)合了之前的方法,記錄每個(gè)計(jì)數(shù)活動(dòng)作為一個(gè)事件,并使用隊(duì)列和滑動(dòng)時(shí)間窗口在后臺(tái)持續(xù)聚合這些事件。此外,我們采用分桶策略以防止寬分區(qū)。在接下來(lái)的部分中,我們將探討這種方法如何解決前面提到的缺陷并滿足我們所有的需求。

注意:從這里開(kāi)始,我們將使用“匯總”和“聚合”這兩個(gè)詞交替使用。它們本質(zhì)上意味著相同的事情,即收集單個(gè)計(jì)數(shù)器的增加/減少并得出最終值。

時(shí)間序列事件存儲(chǔ)

我們選擇時(shí)間序列數(shù)據(jù)抽象作為我們的事件存儲(chǔ),計(jì)數(shù)器變化被攝取為事件記錄。在時(shí)間序列中存儲(chǔ)事件的一些好處包括:

高性能:時(shí)間序列抽象已經(jīng)解決了我們的許多需求,包括高可用性、高吞吐量、可靠和快速的性能等。

減少代碼復(fù)雜性:我們通過(guò)將大部分功能委托給現(xiàn)有服務(wù)來(lái)減少計(jì)數(shù)器抽象中的代碼復(fù)雜性。

時(shí)間序列抽象使用Cassandra作為底層事件存儲(chǔ),但它可以配置為與任何持久存儲(chǔ)一起工作。它看起來(lái)像這樣:

處理寬分區(qū):time_bucket和event_bucket列在打破寬分區(qū)、防止高吞吐量計(jì)數(shù)器事件壓倒給定分區(qū)中起著至關(guān)重要的作用。有關(guān)更多信息,請(qǐng)參考我們之前的 博客。

無(wú)過(guò)度計(jì)數(shù):event_time、event_id和event_item_key列為給定計(jì)數(shù)器的事件形成了冪等鍵,使客戶(hù)端可以安全地重試,而不會(huì)有過(guò)度計(jì)數(shù)的風(fēng)險(xiǎn)。

事件排序:時(shí)間序列以降序排列所有事件,使我們能夠利用這個(gè)屬性來(lái)處理像計(jì)數(shù)器重置這樣的事件。

事件保留:時(shí)間序列抽象包括保留策略,確保事件不會(huì)被無(wú)限期地存儲(chǔ),節(jié)省磁盤(pán)空間,降低基礎(chǔ)設(shè)施成本。一旦事件被聚合并轉(zhuǎn)移到更經(jīng)濟(jì)的存儲(chǔ)中用于審計(jì),就沒(méi)有必要將它們保留在主存儲(chǔ)中。

現(xiàn)在,讓我們看看這些事件是如何為給定的計(jì)數(shù)器聚合的。

聚合計(jì)數(shù)事件

如前所述,為每個(gè)讀取請(qǐng)求收集所有單獨(dú)的增量在讀取性能方面將是成本過(guò)高的。因此,需要后臺(tái)聚合過(guò)程不斷收斂計(jì)數(shù)并確保最優(yōu)的讀取性能。

但我們?nèi)绾卧诔掷m(xù)的寫(xiě)入操作中安全地聚合計(jì)數(shù)事件呢?

這就是最終一致計(jì)數(shù)的概念變得至關(guān)重要的地方。通過(guò)故意落后于當(dāng)前時(shí)間一個(gè)安全的范圍,我們確保聚合總是在不可變的窗口內(nèi)進(jìn)行。

讓我們看看那是什么樣子:

讓我們分解一下:

  • lastRollupTs:這表示計(jì)數(shù)器值最后一次聚合的時(shí)間。對(duì)于首次操作的計(jì)數(shù)器,此時(shí)間戳默認(rèn)為過(guò)去合理的時(shí)間。

  • 不可變窗口和滯后:聚合只能在不再接收計(jì)數(shù)器事件的不可變窗口內(nèi)安全進(jìn)行。時(shí)間序列抽象的“acceptLimit”參數(shù)在這里起著至關(guān)重要的作用,因?yàn)樗芙^了超出此限制的時(shí)間戳的傳入事件。在聚合期間,這個(gè)窗口被稍微推回以考慮時(shí)鐘偏差。

img

這確實(shí)意味著計(jì)數(shù)器值將落后于其最新更新一定范圍(通常在秒級(jí))。這種方法確實(shí)為跨區(qū)域復(fù)制問(wèn)題留有空間,可能會(huì)錯(cuò)過(guò)來(lái)自其他區(qū)域的事件。參見(jiàn)末尾的“未來(lái)工作”部分。

  • 聚合過(guò)程:匯總過(guò)程聚合聚合窗口 自上次匯總以來(lái)的所有事件,得出新值。

img

匯總存儲(chǔ)

我們將這種聚合的結(jié)果保存在持久存儲(chǔ)中。下一次聚合將簡(jiǎn)單地從這個(gè)檢查點(diǎn)繼續(xù)。

我們?yōu)槊總€(gè)數(shù)據(jù)集創(chuàng)建一個(gè)這樣的匯總表,并使用Cassandra作為我們的持久存儲(chǔ)。然而,正如你將很快在控制平面部分看到的,計(jì)數(shù)器服務(wù)可以配置為與任何持久存儲(chǔ)一起工作。

LastWriteTs:每次給定的計(jì)數(shù)器接收寫(xiě)入時(shí),我們也會(huì)在此表中記錄一個(gè)last-write-timestamp作為列更新。這是使用Cassandra的USING TIMESTAMP功能來(lái)可預(yù)測(cè)地應(yīng)用最后寫(xiě)入勝利(LWW)語(yǔ)義。這個(gè)時(shí)間戳與事件的event_time相同。在后續(xù)部分中,我們將看到這個(gè)時(shí)間戳如何被用來(lái)保持一些計(jì)數(shù)器在活躍的匯總流通中,直到它們趕上最新值。

匯總緩存

為了優(yōu)化讀取性能,這些值被緩存在每個(gè)計(jì)數(shù)器的EVCache中。我們將lastRollupCountlastRollupTs*合并為單個(gè)緩存值,以防止計(jì)數(shù)與其相應(yīng)的檢查點(diǎn)時(shí)間戳之間可能的不匹配。

但是,我們?cè)趺粗酪|發(fā)哪些計(jì)數(shù)器的匯總呢?讓我們探索我們的寫(xiě)入和讀取路徑來(lái)更好地理解這一點(diǎn)。

添加/清除計(jì)數(shù)

添加或清除計(jì)數(shù)請(qǐng)求會(huì)持久地寫(xiě)入時(shí)間序列抽象,并更新匯總存儲(chǔ)中的last-write-timestamp。如果持久性確認(rèn)失敗,客戶(hù)端可以重復(fù)他們的請(qǐng)求而不冒著過(guò)度計(jì)數(shù)的風(fēng)險(xiǎn)。一旦持久化,我們發(fā)送一個(gè)火忘請(qǐng)求來(lái)觸發(fā)請(qǐng)求計(jì)數(shù)器的匯總。

獲取計(jì)數(shù)

我們返回最后一次匯總的計(jì)數(shù)作為一個(gè)快速的點(diǎn)讀取操作,接受可能提供稍微陳舊的計(jì)數(shù)的權(quán)衡。我們還在讀取操作期間觸發(fā)匯總以推進(jìn)last-rollup-timestamp,提高后續(xù)聚合的性能。這個(gè)過(guò)程還自我補(bǔ)救了如果任何先前的匯總失敗的陳舊計(jì)數(shù)。

通過(guò)這種方法,計(jì)數(shù)不斷收斂到它們的最新值。現(xiàn)在,讓我們看看我們?nèi)绾问褂梦覀兊膮R總管道將這種方法擴(kuò)展到數(shù)百萬(wàn)計(jì)數(shù)器和數(shù)千個(gè)并發(fā)操作。

匯總管道

每個(gè)Counter-Rollup服務(wù)器運(yùn)行一個(gè)匯總管道,以高效地聚合數(shù)百萬(wàn)計(jì)數(shù)器的計(jì)數(shù)。這就是計(jì)數(shù)器抽象中的大部分復(fù)雜性所在。在接下來(lái)的部分中,我們將分享如何實(shí)現(xiàn)高效聚合的關(guān)鍵細(xì)節(jié)。

輕量級(jí)匯總事件:如我們?cè)趯?xiě)入和讀取路徑中看到的,對(duì)計(jì)數(shù)器的每個(gè)操作都會(huì)向匯總服務(wù)器發(fā)送一個(gè)輕量級(jí)事件:

rollupEvent: {
"namespace": "my_dataset",
"counter": "counter123"
}

請(qǐng)注意,此事件不包括增量。這只是向匯總服務(wù)器的一個(gè)指示,表明這個(gè)計(jì)數(shù)器已被訪問(wèn),現(xiàn)在需要被聚合。知道哪些特定的計(jì)數(shù)器需要被聚合可以防止為了聚合的目的掃描整個(gè)事件數(shù)據(jù)集。

內(nèi)存匯總隊(duì)列:給定的匯總服務(wù)器實(shí)例運(yùn)行一組內(nèi)存中隊(duì)列來(lái)接收匯總事件和并行化聚合。在這個(gè)服務(wù)的第一個(gè)版本中,我們決定使用內(nèi)存隊(duì)列來(lái)減少配置復(fù)雜性,節(jié)省基礎(chǔ)設(shè)施成本,并使隊(duì)列數(shù)量的重新平衡變得相當(dāng)直接。然而,這帶來(lái)了如果實(shí)例崩潰可能會(huì)丟失匯總事件的權(quán)衡。有關(guān)更多詳細(xì)信息,請(qǐng)參見(jiàn)“未來(lái)工作”中的“陳舊計(jì)數(shù)”部分。

最小化重復(fù)工作:我們使用快速非加密哈希,如XXHash,確保相同的一組計(jì)數(shù)器最終進(jìn)入同一個(gè)隊(duì)列。此外,我們盡量減少重復(fù)聚合工作的數(shù)量,通過(guò)有一個(gè)單獨(dú)的匯總堆棧選擇運(yùn)行更少 更大實(shí)例。

可用性和競(jìng)態(tài)條件:擁有單個(gè)匯總服務(wù)器實(shí)例可以最小化重復(fù)聚合工作,但可能會(huì)為觸發(fā)匯總帶來(lái)可用性挑戰(zhàn)。如果我們選擇水平擴(kuò)展匯總服務(wù)器,我們?cè)试S線程覆蓋匯總值,同時(shí)避免任何形式的分布式鎖定機(jī)制,以保持高可用性和性能。這種方法仍然是安全的,因?yàn)榫酆习l(fā)生在不可變的窗口內(nèi)。盡管now()*的概念可能在線程之間有所不同,導(dǎo)致匯總值有時(shí)會(huì)波動(dòng),但計(jì)數(shù)將在每個(gè)不可變的聚合窗口內(nèi)最終收斂到一個(gè)準(zhǔn)確的值。

重新平衡隊(duì)列:如果我們需要擴(kuò)展隊(duì)列的數(shù)量,一個(gè)簡(jiǎn)單的控制平面配置更新后重新部署就足以重新平衡隊(duì)列的數(shù)量。

"eventual_counter_config": {
"queue_config": {
"num_queues" : 8, // change to 16 and re-deploy
...

處理部署:在部署過(guò)程中,這些隊(duì)列會(huì)優(yōu)雅地關(guān)閉,首先排空所有現(xiàn)有事件,而新的匯總服務(wù)器實(shí)例則可能開(kāi)始使用新的隊(duì)列配置??赡軙?huì)有一個(gè)短暫的時(shí)期,舊的和新的匯總服務(wù)器都處于活動(dòng)狀態(tài),但正如前面提到的,由于聚合發(fā)生在不可變的窗口內(nèi),這種競(jìng)態(tài)條件是可控的。

最小化匯總工作:接收到同一計(jì)數(shù)器的多個(gè)事件并不意味著要多次匯總它。我們將這些匯總事件排入一個(gè)集合中,確保給定的計(jì)數(shù)器在匯總窗口期間只匯總一次。

高效聚合:每個(gè)匯總消費(fèi)者同時(shí)處理一批計(jì)數(shù)器。在每個(gè)批次中,它并行查詢(xún)底層的時(shí)間序列抽象以聚合指定時(shí)間范圍內(nèi)的事件。時(shí)間序列抽象優(yōu)化這些范圍掃描以實(shí)現(xiàn)低毫秒延遲。

動(dòng)態(tài)批處理:匯總服務(wù)器根據(jù)計(jì)數(shù)器的基數(shù)動(dòng)態(tài)調(diào)整需要掃描的時(shí)間分區(qū)數(shù)量,以防止用許多并行讀取請(qǐng)求壓倒底層存儲(chǔ)。

自適應(yīng)反壓:每個(gè)消費(fèi)者在發(fā)出下一批匯總之前等待一批完成。它根據(jù)前一批的性能調(diào)整批次之間的等待時(shí)間。這種方法在匯總期間提供反壓,以防止壓倒底層的時(shí)間序列存儲(chǔ)。

處理收斂

為了防止基數(shù)低的計(jì)數(shù)器落后太多,從而隨后掃描太多的時(shí)間分區(qū),它們被保持在不斷的匯總流通中。對(duì)于基數(shù)高的計(jì)數(shù)器,不斷地流通它們會(huì)在我們匯總隊(duì)列中消耗過(guò)多的內(nèi)存。這里就是之前提到的last-write-timestamp發(fā)揮作用的地方。匯總服務(wù)器檢查這個(gè)時(shí)間戳,以確定是否需要重新排隊(duì)給定的計(jì)數(shù)器,確保我們繼續(xù)聚合直到它完全趕上寫(xiě)入。

現(xiàn)在,讓我們看看我們?nèi)绾卫眠@種計(jì)數(shù)器類(lèi)型在近實(shí)時(shí)提供最新的當(dāng)前計(jì)數(shù)。

實(shí)驗(yàn):準(zhǔn)確全球計(jì)數(shù)器

我們正在試驗(yàn)一個(gè)稍微修改版的最終一致性計(jì)數(shù)器。同樣,對(duì)“準(zhǔn)確”這個(gè)術(shù)語(yǔ)要謹(jǐn)慎理解。這種類(lèi)型的計(jì)數(shù)器與其對(duì)應(yīng)物之間的關(guān)鍵區(qū)別在于,delta,代表自上次匯總時(shí)間戳以來(lái)的計(jì)數(shù),在實(shí)時(shí)計(jì)算。

然后,currentAccurateCount = lastRollupCount + delta

實(shí)時(shí)聚合這個(gè)delta可能會(huì)影響這個(gè)操作的性能,這取決于需要掃描多少事件和分區(qū)來(lái)檢索這個(gè)delta。同樣的批量匯總原則在這里適用,以防止并行掃描太多分區(qū)。相反,如果這個(gè)數(shù)據(jù)集中的計(jì)數(shù)器經(jīng)常被訪問(wèn),delta的時(shí)間間隔保持狹窄,使得獲取當(dāng)前計(jì)數(shù)的方法相當(dāng)有效。

現(xiàn)在,讓我們看看所有這些復(fù)雜性是如何通過(guò)擁有一個(gè)統(tǒng)一的控制平面配置來(lái)管理的。

控制平面

數(shù)據(jù)網(wǎng)關(guān)平臺(tái)控制平面管理所有抽象和命名空間的控制設(shè)置,包括計(jì)數(shù)器抽象。下面是一個(gè)支持低基數(shù)最終一致性計(jì)數(shù)器的命名空間的控制平面配置示例:

"persistence_configuration": [
{
"id": "CACHE", // 計(jì)數(shù)器緩存配置
"scope": "dal=counter",
"physical_storage": {
"type": "EVCACHE", // 緩存存儲(chǔ)類(lèi)型
"cluster": "evcache_dgw_counter_tier1" // 共享EVCache集群
}
},
{
"id": "COUNTER_ROLLUP",
"scope": "dal=counter", // 計(jì)數(shù)器抽象配置
"physical_storage": {
"type": "CASSANDRA", // 匯總存儲(chǔ)類(lèi)型
"cluster": "cass_dgw_counter_uc1", // 物理集群名稱(chēng)
"dataset": "my_dataset_1" // 命名空間/數(shù)據(jù)集
},
"counter_cardinality": "LOW", // 支持的計(jì)數(shù)器基數(shù)
"config": {
"counter_type": "EVENTUAL", // 計(jì)數(shù)器類(lèi)型
"eventual_counter_config": { // 最終一致性計(jì)數(shù)器類(lèi)型
"internal_config": {
"queue_config": { // 根據(jù)基數(shù)調(diào)整
"num_queues" : 8, // 每個(gè)實(shí)例的匯總隊(duì)列
"coalesce_ms": 10000, // 匯總的合并持續(xù)時(shí)間
"capacity_bytes": 16777216 // 每個(gè)隊(duì)列分配的內(nèi)存
},
"rollup_batch_count": 32 // 并行化因子
}
}
}
},
{
"id": "EVENT_STORAGE",
"scope": "dal=ts", // 時(shí)間序列事件存儲(chǔ)
"physical_storage": {
"type": "CASSANDRA", // 持久存儲(chǔ)類(lèi)型
"cluster": "cass_dgw_counter_uc1", // 物理集群名稱(chēng)
"dataset": "my_dataset_1", // 鍵空間名稱(chēng)
},
"config": {
"time_partition": { // 事件的時(shí)間分區(qū)
"buckets_per_id": 4, // 內(nèi)部事件桶
"seconds_per_bucket": "600", // 低基數(shù)的較小寬度
"seconds_per_slice": "86400", // 時(shí)間片表的寬度
},
"accept_limit": "5s", // 不可變性的邊界
},
"lifecycleConfigs": {
"lifecycleConfig": [
{
"type": "retention", // 事件保留
"config": {
"close_after": "518400s",
"delete_after": "604800s" // 7天計(jì)數(shù)事件保留
}
}
]
}
}
]

使用這樣的控制平面配置,我們使用容器在同一個(gè)主機(jī)上部署多個(gè)抽象層,每個(gè)容器獲取特定于其范圍的配置。

與時(shí)間序列抽象一樣,我們的自動(dòng)化使用一系列用戶(hù)輸入,關(guān)于他們的工作負(fù)載和基數(shù),以得出正確的基礎(chǔ)設(shè)施和相關(guān)的控制平面配置。你可以了解更多關(guān)于這個(gè)過(guò)程的信息,由我們的一位杰出同事Joey Lynch給出的演講:Netflix如何在云端最佳配置基礎(chǔ)設(shè)施。

性能

在撰寫(xiě)這篇博客時(shí),這項(xiàng)服務(wù)在全球不同API端點(diǎn)和數(shù)據(jù)集上處理接近75K計(jì)數(shù)請(qǐng)求/秒

同時(shí)為其所有端點(diǎn)提供個(gè)位數(shù)毫秒延遲:

雖然我們的系統(tǒng)很健壯,但我們?nèi)匀挥泄ぷ饕觯蛊涓涌煽坎⒃鰪?qiáng)其功能。其中一些工作包括:

  • 區(qū)域匯總:跨區(qū)域復(fù)制問(wèn)題可能導(dǎo)致錯(cuò)過(guò)來(lái)自其他區(qū)域的事件。另一種策略是為每個(gè)區(qū)域建立一個(gè)匯總表,然后在全局匯總表中進(jìn)行統(tǒng)計(jì)。這種設(shè)計(jì)的一個(gè)關(guān)鍵挑戰(zhàn)是有效地跨區(qū)域通信清除計(jì)數(shù)器。

  • 錯(cuò)誤檢測(cè)和陳舊計(jì)數(shù):如果匯總事件丟失或匯總失敗且沒(méi)有重試,可能會(huì)發(fā)生過(guò)度陳舊的計(jì)數(shù)。對(duì)于經(jīng)常訪問(wèn)的計(jì)數(shù)器來(lái)說(shuō),這不是問(wèn)題,因?yàn)樗鼈儽3衷趨R總流通中。這個(gè)問(wèn)題對(duì)于不經(jīng)常訪問(wèn)的計(jì)數(shù)器更為明顯。通常,這些計(jì)數(shù)器的初始讀取將觸發(fā)匯總, 自我補(bǔ)救問(wèn)題。然而,對(duì)于不能接受潛在陳舊初始讀取的用例,我們計(jì)劃實(shí)施改進(jìn)的錯(cuò)誤檢測(cè)、匯總交接和持久隊(duì)列,以實(shí)現(xiàn)彈性重試。

結(jié)論

分布式計(jì)數(shù)仍然是計(jì)算機(jī)科學(xué)中的一個(gè)挑戰(zhàn)性問(wèn)題。在這篇博客中,我們探討了多種實(shí)現(xiàn)和部署大規(guī)模計(jì)數(shù)服務(wù)的方法。盡管可能還有其他的分布式計(jì)數(shù)方法,我們的目標(biāo)是在保持高可用性的同時(shí),以低基礎(chǔ)設(shè)施成本提供極快的性能,并提供冪等保證。在此過(guò)程中,我們?yōu)榱藵M足Netflix的多樣化計(jì)數(shù)需求,做出了各種權(quán)衡。我們希望你覺(jué)得這篇博客文章有洞察力。

請(qǐng)繼續(xù)關(guān)注復(fù)合抽象的第3部分,我們將介紹我們的圖形抽象,這是一項(xiàng)新服務(wù),建立在鍵值抽象 和 時(shí)間序列抽象之上,用于處理高吞吐量、低延遲的圖形。

關(guān)注我,緊跟本系列專(zhuān)欄文章,咱們下篇再續(xù)!

★ 作者簡(jiǎn)介:魔都架構(gòu)師,多家大廠后端一線研發(fā)經(jīng)驗(yàn),在分布式系統(tǒng)設(shè)計(jì)、數(shù)據(jù)平臺(tái)架構(gòu)和AI應(yīng)用開(kāi)發(fā)等領(lǐng)域都有豐富實(shí)踐經(jīng)驗(yàn)。 各大技術(shù)社區(qū)頭部專(zhuān)家博主。具有豐富的引領(lǐng)團(tuán)隊(duì)經(jīng)驗(yàn),深厚業(yè)務(wù)架構(gòu)和解決方案的積累。 負(fù)責(zé): 中央/分銷(xiāo)預(yù)訂系統(tǒng)性能優(yōu)化 活動(dòng)&券等營(yíng)銷(xiāo)中臺(tái)建設(shè) 交易平臺(tái)及數(shù)據(jù)中臺(tái)等架構(gòu)和開(kāi)發(fā)設(shè)計(jì) 車(chē)聯(lián)網(wǎng)核心平臺(tái)-物聯(lián)網(wǎng)連接平臺(tái)、大數(shù)據(jù)平臺(tái)架構(gòu)設(shè)計(jì)及優(yōu)化 LLM Agent應(yīng)用開(kāi)發(fā) 區(qū)塊鏈應(yīng)用開(kāi)發(fā) 大數(shù)據(jù)開(kāi)發(fā)挖掘經(jīng)驗(yàn) 推薦系統(tǒng)項(xiàng)目 目前主攻市級(jí)軟件項(xiàng)目設(shè)計(jì)、構(gòu)建服務(wù)全社會(huì)的應(yīng)用系統(tǒng)。 ”

參考:

  • 編程嚴(yán)選網(wǎng)

編程嚴(yán)選網(wǎng):http://www.javaedge.cn/ 專(zhuān)注分享軟件開(kāi)發(fā)全生態(tài)相關(guān)技術(shù)文章、視頻教程資源、熱點(diǎn)資訊等,全站資源免費(fèi)學(xué)習(xí),快來(lái)看看吧~ 【編程嚴(yán)選】星球

歡迎長(zhǎng)按圖片加好友,我會(huì)第一時(shí)間和你分享軟件行業(yè)趨勢(shì)面試資源,學(xué)習(xí)方法等等。

添加好友備注【技術(shù)群交流】拉你進(jìn)技術(shù)交流群

關(guān)注公眾號(hào)后,在后臺(tái)私信:

  • 更多教程資源應(yīng)有盡有,歡迎關(guān)注并加技術(shù)交流群,慢慢獲取

  • 為避免大量資源被收藏白嫖而浪費(fèi)各自精力,以上資源領(lǐng)取分別需要收取1元門(mén)檻費(fèi)!


特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶(hù)上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關(guān)推薦
熱點(diǎn)推薦
前方敗報(bào)不停傳回俄羅斯,十天一言不發(fā)的普京,仍在安心享受假期

前方敗報(bào)不停傳回俄羅斯,十天一言不發(fā)的普京,仍在安心享受假期

博覽歷史
2026-01-10 19:32:07
天呀,杜海濤竟然現(xiàn)成這樣了,沈夢(mèng)辰對(duì)他是真愛(ài)啊

天呀,杜海濤竟然現(xiàn)成這樣了,沈夢(mèng)辰對(duì)他是真愛(ài)啊

草莓解說(shuō)體育
2026-01-07 01:43:18
第一次和女朋友同居,真是讓我大開(kāi)眼界!你們的女朋友也是這樣嗎

第一次和女朋友同居,真是讓我大開(kāi)眼界!你們的女朋友也是這樣嗎

阿凱銷(xiāo)售場(chǎng)
2026-01-01 10:07:29
高峰也沒(méi)想到,他當(dāng)年拋棄的兒子,如今開(kāi)始給那英爭(zhēng)光了

高峰也沒(méi)想到,他當(dāng)年拋棄的兒子,如今開(kāi)始給那英爭(zhēng)光了

趣文說(shuō)娛
2026-01-04 16:34:24
就在剛剛!CBA官宣第6位主帥下課!接替者是名帥,曾執(zhí)教中國(guó)男籃

就在剛剛!CBA官宣第6位主帥下課!接替者是名帥,曾執(zhí)教中國(guó)男籃

老吳說(shuō)體育
2026-01-11 20:34:42
毫無(wú)還手之力!遼寧78-108慘敗廣東,輸球責(zé)任人非這四人莫屬!

毫無(wú)還手之力!遼寧78-108慘敗廣東,輸球責(zé)任人非這四人莫屬!

田先生籃球
2026-01-12 00:15:16
出大事了,高市13天后要下臺(tái),日本突然棄美投韓,兩國(guó)秘密結(jié)盟

出大事了,高市13天后要下臺(tái),日本突然棄美投韓,兩國(guó)秘密結(jié)盟

阿器談史
2026-01-11 17:20:31
國(guó)民黨老將被逮捕,鄭麗文1個(gè)出人意料的舉動(dòng),令賴(lài)清德計(jì)謀白費(fèi)

國(guó)民黨老將被逮捕,鄭麗文1個(gè)出人意料的舉動(dòng),令賴(lài)清德計(jì)謀白費(fèi)

策略述
2026-01-10 12:57:46
許利民:有些球員吊兒郎當(dāng),毫無(wú)責(zé)任感,如果不改變這支北京毫無(wú)希望

許利民:有些球員吊兒郎當(dāng),毫無(wú)責(zé)任感,如果不改變這支北京毫無(wú)希望

懂球帝
2026-01-11 23:50:43
內(nèi)訌爆發(fā)!曝快船兩大核心矛盾激化!公開(kāi)指責(zé),表達(dá)不滿!

內(nèi)訌爆發(fā)!曝快船兩大核心矛盾激化!公開(kāi)指責(zé),表達(dá)不滿!

King迪哥侃球
2026-01-11 21:58:15
武漢商貿(mào)國(guó)有控股集團(tuán)有限公司原黨委書(shū)記、董事長(zhǎng)陳建華接受紀(jì)律審查和監(jiān)察調(diào)查

武漢商貿(mào)國(guó)有控股集團(tuán)有限公司原黨委書(shū)記、董事長(zhǎng)陳建華接受紀(jì)律審查和監(jiān)察調(diào)查

界面新聞
2026-01-11 20:50:22
賴(lài)清德想向大陸攤牌,國(guó)民黨表態(tài):直接放行!結(jié)果民進(jìn)黨立馬慫了

賴(lài)清德想向大陸攤牌,國(guó)民黨表態(tài):直接放行!結(jié)果民進(jìn)黨立馬慫了

傲傲講歷史
2026-01-11 09:53:45
離春節(jié)還剩30多天,提醒:6種年貨提前買(mǎi),先存起來(lái),不花冤枉錢(qián)

離春節(jié)還剩30多天,提醒:6種年貨提前買(mǎi),先存起來(lái),不花冤枉錢(qián)

阿龍美食記
2026-01-09 19:10:49
上海男籃功勛隊(duì)長(zhǎng),身高2米21娶1米53嬌妻,如今他換了身份回上海

上海男籃功勛隊(duì)長(zhǎng),身高2米21娶1米53嬌妻,如今他換了身份回上海

削桐作琴
2026-01-04 20:23:41
溥儀在“偽滿”的權(quán)力有多大?別被他裝孫子的一面給騙了

溥儀在“偽滿”的權(quán)力有多大?別被他裝孫子的一面給騙了

掠影后有感
2026-01-09 11:08:09
皇馬將與贊助商續(xù)約:3大金主 每年貢獻(xiàn)3億!高居世界第1

皇馬將與贊助商續(xù)約:3大金主 每年貢獻(xiàn)3億!高居世界第1

葉青足球世界
2026-01-11 16:33:40
雷軍:特斯拉確實(shí)強(qiáng),但并非不可戰(zhàn)勝!SU7是唯一擊敗Model 3的同檔純電轎車(chē)!假以時(shí)日YU7也能和Model Y一較高下

雷軍:特斯拉確實(shí)強(qiáng),但并非不可戰(zhàn)勝!SU7是唯一擊敗Model 3的同檔純電轎車(chē)!假以時(shí)日YU7也能和Model Y一較高下

每日經(jīng)濟(jì)新聞
2026-01-10 21:26:24
特朗普:美國(guó)要開(kāi)始進(jìn)行“陸地打擊”

特朗普:美國(guó)要開(kāi)始進(jìn)行“陸地打擊”

澎湃新聞
2026-01-11 00:21:24
600億抄底!美財(cái)長(zhǎng)的學(xué)生竟然收購(gòu)了中國(guó)萬(wàn)達(dá),難怪王健林會(huì)輸!

600億抄底!美財(cái)長(zhǎng)的學(xué)生竟然收購(gòu)了中國(guó)萬(wàn)達(dá),難怪王健林會(huì)輸!

蜉蝣說(shuō)
2026-01-11 17:51:23
國(guó)米打破魔咒轉(zhuǎn)運(yùn)之戰(zhàn)!齊沃率隊(duì)走向成熟,右翼或有驚喜引援!

國(guó)米打破魔咒轉(zhuǎn)運(yùn)之戰(zhàn)!齊沃率隊(duì)走向成熟,右翼或有驚喜引援!

肥強(qiáng)侃球
2026-01-11 23:34:19
2026-01-12 04:47:00
JavaEdge incentive-icons
JavaEdge
Java 技術(shù)
466文章數(shù) 457關(guān)注度
往期回顧 全部

科技要聞

“我們與美國(guó)的差距也許還在拉大”

頭條要聞

美軍突襲委內(nèi)瑞拉俄制防空系統(tǒng)失聯(lián) 俄方回應(yīng)

頭條要聞

美軍突襲委內(nèi)瑞拉俄制防空系統(tǒng)失聯(lián) 俄方回應(yīng)

體育要聞

U23國(guó)足形勢(shì):末輪不負(fù)泰國(guó)即確保晉級(jí)

娛樂(lè)要聞

留幾手為閆學(xué)晶叫屈?稱(chēng)網(wǎng)友自卑敏感

財(cái)經(jīng)要聞

外賣(mài)平臺(tái)"燒錢(qián)搶存量市場(chǎng)"迎來(lái)終局?

汽車(chē)要聞

2026款宋Pro DM-i長(zhǎng)續(xù)航補(bǔ)貼后9.98萬(wàn)起

態(tài)度原創(chuàng)

游戲
家居
本地
藝術(shù)
親子

Epic喜加二/LPL、KPL春季賽開(kāi)戰(zhàn)| 下周玩什么

家居要聞

木色留白 演繹現(xiàn)代自由

本地新聞

云游內(nèi)蒙|“包”你再來(lái)?一座在硬核里釀出詩(shī)意的城

藝術(shù)要聞

25位世界名人告訴你,音樂(lè)是人一生能擁有最棒的事!

親子要聞

最近的孩子怎么都長(zhǎng)得這么著急?你不說(shuō),誰(shuí)知道他還是個(gè)寶寶?

無(wú)障礙瀏覽 進(jìn)入關(guān)懷版