【系統設計】指標監控和告警系統

在本文中,我們將探討如何設計一個可擴展的指標監控和告警系統。一個好的監控和告警系統,對基礎設施的可觀察性,高可用性,可靠性方面發揮著關鍵作用。

下圖顯示了市面上一些流行的指標監控和告警服務。

bb4f4037423fe26d6482c4a193f971e6.png

接下來,我們會設計一個類似的服務,可以供大公司內部使用。

設計要求

從一個小明去面試的故事開始。

31e4827650533fe866d41f1062af0aba.png

面試官:如果讓你設計一個指標監控和告警系統,你會怎么做?

小明:好的,這個系統是為公司內部使用的,還是設計像 Datadog 這種 SaaS 服務?

面試官:很好的問題,目前這個系統只是公司內部使用。

小明:我們想收集哪些指標信息?

面試官:包括操作系統的指標信息,中間件的指標,以及運行的應用服務的 qps 這些指標。

小明:我們用這個系統監控的基礎設施的規模是多大的?

面試官:1億日活躍用戶,1000個服務器池,每個池 100 臺機器。

小明:指標數據要保存多長時間呢?

面試官:我們想保留一年。

小明:好吧,為了較長時間的存儲,可以降低指標數據的分辨率嗎?

面試官:很好的問題,對于最新的數據,會保存 7 天,7天之后可以降低到1分鐘的分辨率,而到 30 天之后,可以按照 1 小時的分辨率做進一步的匯總。

小明:支持的告警渠道有哪些?

面試官:郵件,電 釘釘,企業微信,Http Endpoint。

小明:我們需要收集日志嗎?還有是否需要支持分布式系統的鏈路追蹤?

面試官:目前專注于指標,其他的暫時不考慮。

小明:好的,大概都了解了。

總結一下,被監控的基礎設施是大規模的,以及需要支持各種維度的指標。另外,整體的系統也有較高的要求,要考慮到可擴展性,低延遲,可靠性和靈活性。

基礎知識

一個指標監控和告警系統通常包含五個組件,如下圖所示

9b763ab81d7b17895872366dc7711fc3.png
  1. 1. 數據收集:從不同的數據源收集指標數據。

  2. 2. 數據傳輸:把指標數據發送到指標監控系統。

  3. 3. 數據存儲:存儲指標數據。

  4. 4. 告警:分析接收到的數據,檢測到異常時可以發出告警通知。

  5. 5. 可視化:可視化頁面,以圖形,圖表的形式呈現數據。

數據模式

指標數據通常會保存為一個時間序列,其中包含一組值及其相關的時間戳。

序列本身可以通過名稱進行唯一標識,也可以通過一組標簽進行標識。

讓我們看兩個例子。

示例1:生產服務器 i631 在 20:00 的 CPU 負載是多少?

ab45a258f507d7fa706bf75f424e5afe.png

上圖標記的數據點可以用下面的格式表示

99d69353443d4a6a774c2fa0d34c6b4d.png

在上面的示例中,時間序列由指標名稱,標簽(host:i631,env:prod),時間戳以及對應的值構成。

示例2:過去 10 分鐘內上海地區所有 Web 服務器的平均 CPU 負載是多少?

從概念上來講,我們會查詢出和下面類似的內容

CPU.load?host=webserver01,region=shanghai?1613707265?50CPU.load?host=webserver01,region=shanghai?1613707270?62CPU.load?host=webserver02,region=shanghai?1613707275?43

我們可以通過上面每行末尾的值計算平均 CPU 負載,上面的數據格式也稱為行協議。是市面上很多監控軟件比較常用的輸入格式,Prometheus 和 OpenTSDB 就是兩個例子。

每個時間序列都包含以下內容:

  • ??指標名稱,字符串類型的 metric name 。

  • ??一個鍵值對的數組,表示指標的標簽,List<key,value>

  • ??一個包含時間戳和對應值的的數組,List <value, timestamp>

數據存儲

數據存儲是設計的核心部分,不建議構建自己的存儲系統,也不建議使用常規的存儲系統(比如 MySQL)來完成這項工作。

理論下,常規數據庫可以支持時間序列數據, 但是需要數據庫專家級別的調優后,才能滿足數據量比較大的場景需求。

具體點說,關系型數據庫沒有對時間序列數據進行優化,有以下幾點原因

  • ??在滾動時間窗口中計算平均值,需要編寫復雜且難以閱讀的 SQL。

  • ??為了支持標簽(tag/label)數據,我們需要給每個標簽加一個索引。

  • ??相比之下,關系型數據庫在持續的高并發寫入操作時表現不佳。

那 NoSQL 怎么樣呢?理論上,市面上的少數 NoSQL 數據庫可以有效地處理時間序列數據。比如 Cassandra 和 Bigtable 都可以。但是,想要滿足高效存儲和查詢數據的需求,以及構建可擴展的系統,需要深入了解每個 NoSQL 的內部工作原理。

相比之下,專門對時間序列數據優化的時序數據庫,更適合這種場景。

OpenTSDB 是一個分布式時序數據庫,但由于它基于 Hadoop 和 HBase,運行 Hadoop/HBase 集群也會帶來復雜性。Twitter 使用了 MetricsDB 時序數據庫存儲指標數據,而亞馬遜提供了 Timestream 時序數據庫服務。

根據 DB-engines 的報告,兩個最流行的時序數據庫是 InfluxDB 和 Prometheus ,它們可以存儲大量時序數據,并支持快速地對這些數據進行實時分析。

如下圖所示,8 核 CPU 和 32 GB RAM 的 InfluxDB 每秒可以處理超過 250,000 次寫入。

2ddefcd193f14bc0b5439bcdb73bc342.png

高層次設計

a5d00a87a0743f8cfda4e58ac31f06fa.png
  • ? Metrics Source 指標來源,應用服務,數據庫,消息隊列等。

  • ? Metrics Collector 指標收集器。

  • ? Time series DB 時序數據庫,存儲指標數據。

  • ? Query Service 查詢服務,向外提供指標查詢接口。

  • ? Alerting System 告警系統,檢測到異常時,發送告警通知。

  • ? Visualization System 可視化,以圖表的形式展示指標。

深入設計

7a0000ca02d33ba87c9bb33ee278b029.png

現在,讓我們聚焦于數據收集流程。主要有推和拉兩種方式。

拉模式

5e8645b9483dbb98324fad1906587ee2.png

上圖顯示了使用了拉模式的數據收集,單獨設置了數據收集器,定期從運行的應用中拉取指標數據。

這里有一個問題,數據收集器如何知道每個數據源的地址? 一個比較好的方案是引入服務注冊發現組件,比如 etcd,ZooKeeper,如下

0ac3be8c8f222f77e846e57578895008.png

下圖展示了我們現在的數據拉取流程。

585f3a93d43a73cb5eb13690fd5a4439.png
  1. 1. 指標收集器從服務發現組件中獲取元數據,包括拉取間隔,IP 地址,超時,重試參數等。

  2. 2. 指標收集器通過設定的 HTTP 端點獲取指標數據。

在數據量比較大的場景下,單個指標收集器是獨木難支的,我們必須使用一組指標收集器。但是多個收集器和多個數據源之間應該如何協調,才能正常工作不發生沖突呢?

一致性哈希很適合這種場景,我們可以把數據源映射到哈希環上,如下

d83a9b4c5166fb08fbabfb9d46b9933b.png

這樣可以保證每個指標收集器都有對應的數據源,相互工作且不會發生沖突。

推模式

如下圖所示,在推模式中,各種指標數據源(Web 應用,數據庫,消息隊列)直接發送到指標收集器。

a1723433c7f60f68d16ce10ed1bab3f2.png

在推模式中,需要在每個被監控的服務器上安裝收集器代理,它可以收集服務器的指標數據,然后定期的發送給指標收集器。

推和拉兩種模式哪種更好?沒有固定的答案,這兩個方案都是可行的,甚至在一些復雜場景中,需要同時支持推和拉。

擴展數據傳輸

edee94416a7e8b1b53835fdb708659ce.png

現在,讓我們主要關注指標收集器和時序數據庫。不管使用推還是拉模式,在需要接收大量數據的場景下,指標收集器通常是一個服務集群。

但是,當時序數據庫不可用時,就會存在數據丟失的風險,所以,我們引入了 Kafka 消息隊列組件, 如下圖

394b05f39561161c0b852dddfb852b12.png

指標收集器把指標數據發送到 Kafka 消息隊列,然后消費者或者流處理服務進行數據處理,比如 Apache Storm、Flink 和 Spark, 最后再推送到時序數據庫。

指標計算

指標在多個地方都可以聚合計算,看看它們都有什么不一樣。

  • ??客戶端代理:客戶端安裝的收集代理只支持簡單的聚合邏輯。

  • ??傳輸管道:在數據寫入時序數據庫之前,我們可以用 Flink 流處理服務進行聚合計算,然后只寫入匯總后的數據,這樣寫入量會大大減少。但是由于我們沒有存儲原始數據,所以丟失了數據精度。

  • ??查詢端:我們可以在查詢端對原始數據進行實時聚合查詢,但是這樣方式查詢效率不太高。

時序數據庫查詢語言

大多數流行的指標監控系統,比如 Prometheus 和 InfluxDB 都不使用 SQL,而是有自己的查詢語言。一個主要原因是很難通過 SQL 來查詢時序數據, 并且難以閱讀,比如下面的SQL 你能看出來在查詢什么數據嗎?

select?id,temp,avg(temp)?over?(partition?by?group_nr?order?by?time_read)?as?rolling_avg
from?(select?id,temp,time_read,interval_group,id?-?row_number()?over?(partition?by?interval_group?order?by?time_read)?as?group_nrfrom?(select?id,time_read,"epoch"::timestamp?+?"900?seconds"::interval?*?(extract(epoch?from?time_read)::int4?/?900)?as?interval_group,tempfrom?readings)?t1
)?t2
order?by?time_read;

相比之下, InfluxDB 使用的針對于時序數據的 Flux 查詢語言會更簡單更好理解,如下

from(db:"telegraf")|>?range(start:-1h)|>?filter(fn:?(r)?=>?r._measurement?==?"foo")|>?exponentialMovingAverage(size:-10s)

數據編碼和壓縮

數據編碼和壓縮可以很大程度上減小數據的大小,特別是在時序數據庫中,下面是一個簡單的例子。

f701fd073cf9c6abd99bca40ab156640.png

因為一般數據收集的時間間隔是固定的,所以我們可以把一個基礎值和增量一起存儲,比如 1610087371, 10, 10, 9, 11 這樣,可以占用更少的空間。

下采樣

下采樣是把高分辨率的數據轉換為低分辨率的過程,這樣可以減少磁盤使用。由于我們的數據保留期是1年,我們可以對舊數據進行下采樣,這是一個例子:

  • ? 7天數據,不進行采樣。

  • ??30天數據,下采樣到1分鐘的分辨率

  • ? 1年數據,下采樣到1小時的分辨率。

我們看另外一個具體的例子,它把 10 秒分辨率的數據聚合為 30 秒分辨率。

原始數據

9d47fd102c5a27e5a74cca72432d6412.png

下采樣之后

686932ed252f9bbecf92e1d3ad8d8a4e.png

告警服務

讓我們看看告警服務的設計圖,以及工作流程。

1baa4b38dd4c054548b234bb1890e499.png
  1. 1. 加載 YAML 格式的告警配置文件到緩存。

  2. -?name:?instance_down
    ??rules:
    ??#?服務不可用時間超過?5?分鐘觸發告警.
    ??-?alert:?instance_down
    ????expr:?up?==?0
    ????for:?5m
    ????labels:
    ??????severity:?page

  3. 2. 警報管理器從緩存中讀取配置。

  4. 3. 根據告警規則,按照設定的時間和條件查詢指標,如果超過閾值,則觸發告警。

  5. 4. Alert Store 保存著所有告警的狀態(掛起,觸發,已解決)。

  6. 5. 符合條件的告警會添加到 Kafka 中。

  7. 6. 消費隊列,根據告警規則,發送警報信息到不同的通知渠道。

可視化

可視化建立在數據層之上,指標數據可以在指標儀表板上顯示,告警信息可以在告警儀表板上顯示。下圖顯示了一些指標,服務器的請求數量、內存/CPU 利用率、頁面加載時間、流量和登錄信息。

e6a1512518056543c1b616be48b62d2d.png

Grafana 可以是一個非常好的可視化系統,我們可以直接拿來使用。

總結

在本文中,我們介紹了指標監控和告警系統的設計。在高層次上,我們討論了數據收集、時序數據庫、告警和可視化,下圖是我們最終的設計:

79bddc191232bf2a1ded78e00ded0471.png

Reference

[0] System Design Interview Volume 2: https://www.amazon.com/System-Design-Interview-Insiders-Guide/dp/1736049119

[1] Datadog: https://www.datadoghq.com/

[2] Splunk: https://www.splunk.com/

[3] Elastic stack: https://www.elastic.co/elastic-stack

[4] Dapper, a Large-Scale Distributed Systems Tracing Infrastructure: https://research.google/pubs/pub36356/

[5] Distributed Systems Tracing with Zipkin: https://blog.twitter.com/engineering/en_us/a/2012/distributed-systems-tracing-with-zipkin.html

[6] Prometheus: https://prometheus.io/docs/introduction/overview/

[7] OpenTSDB - A Distributed, Scalable Monitoring System: http://opentsdb.net/

[8] Data model: : https://prometheus.io/docs/concepts/data_model/

[9] Schema design for time-series data | Cloud Bigtable Documentation https://cloud.google.com/bigtable/docs/schema-design-time-series

[10] MetricsDB: TimeSeries Database for storing metrics at Twitter: https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/metricsdb.html

[11] Amazon Timestream: https://aws.amazon.com/timestream/

[12] DB-Engines Ranking of time-series DBMS: https://db-engines.com/en/ranking/time+series+dbms

[13] InfluxDB: https://www.influxdata.com/

[14] etcd:?https://etcd.io

[15] Service Discovery with Zookeeper https://cloud.spring.io/spring-cloud-zookeeper/1.2.x/multi/multi_spring-cloud-zookeeper-discovery.html

[16] Amazon CloudWatch: https://aws.amazon.com/cloudwatch/

[17] Graphite: https://graphiteapp.org/

[18] Push vs Pull: http://bit.ly/3aJEPxE

[19] Pull doesn’t scale - or does it?: https://prometheus.io/blog/2016/07/23/pull-does-not-scale-or-does-it/

[20] Monitoring Architecture: https://developer.lightbend.com/guides/monitoring-at-scale/monitoring-architecture/architecture.html

[21] Push vs Pull in Monitoring Systems: https://giedrius.blog/2019/05/11/push-vs-pull-in-monitoring-systems/

[22] Pushgateway: https://github.com/prometheus/pushgateway

[23] Building Applications with Serverless Architectures https://aws.amazon.com/lambda/serverless-architectures-learn-more/

[24] Gorilla: A Fast, Scalable, In-Memory Time Series Database: http://www.vldb.org/pvldb/vol8/p1816-teller.pdf

[25] Why We’re Building Flux, a New Data Scripting and Query Language: https://www.influxdata.com/blog/why-were-building-flux-a-new-data-scripting-and-query-language/

[26] InfluxDB storage engine: https://docs.influxdata.com/influxdb/v2.0/reference/internals/storage-engine/

[27] YAML: https://en.wikipedia.org/wiki/YAML

[28] Grafana Demo: https://play.grafana.org/

END

做了一個 .NET 的學習網站,內容涵蓋了分布式系統,數據結構與算法,設計模式,操作系統,計算機網絡等,以及工作推薦和面試經驗分享,歡迎來撩。

回復 dotnet 獲取網站地址。

回復 面試題 獲取 .NET 面試題。

回復 程序員副業?獲取適合程序員的副業指南。

3b0249e834fc3d11fa794c43c38e9430.gif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285181.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285181.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285181.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言試題154之兩個字符串連接程序

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:兩個字符串連接程序 2 、溫馨…

[轉]Android studio 快速解決Gradle's dependency cache may be corrupt 和 Gradle配置 gradle

用了好久的AS了&#xff0c;官方版本更新&#xff0c;各種配置工具 也跟著更新。更新后導入工程時&#xff08;使用Android工程編譯或者導入新的工程沒有對應的gradle版本&#xff09;一些電腦出現一下問題。 Error:Failed to open zip file. Gradles dependency cache may …

mybatis源碼學習

2019獨角獸企業重金招聘Python工程師標準>>> 學習主線&#xff1a; 目的&#xff1a;mybatis的作用orm框架&#xff0c;用了該框架就不用自己調用jdbc了。 用法&#xff1a;。。。。。 邏輯&#xff1a;。。。。。 源代碼&#xff1a;。。。。。 1、猜想mybatis對數…

自己封裝一個彈框插件

彈出層提示信息&#xff0c;這是移動前端開發中最常見的需求&#xff0c;你可能會想到一些流行的彈框插件&#xff0c;比如 經典的artDialog 炫酷的Sweetalert等等.. 但是慢慢地你其實會發現通常情況下需求定制化要求較高&#xff0c;一般的彈框插件可能只滿足大部分要求&#…

C語言中include““與include<>的區別(自定義頭文件、預設頭文件)

文章目錄 新建控制臺應用程序自定義頭文件編輯頭文件工程內引用頭文件,調用函數標準庫頭文件,調用函數新建控制臺應用程序 Win32 Application和Win32 Console Application 都是工作在32位Windows環境的程序。其中: (1)Win32 Application就是普通的常見的窗口應用程序,當…

.NET MAUI 性能提升

點擊藍字關注我們作者&#xff1a;Jonathan Peppers翻譯&#xff1a;Yijing Sun校稿&#xff1a;Amy Peng排版&#xff1a;Rani Sun精彩預告*本文干貨滿滿&#xff0c;預計閱讀時間32分鐘&#xff0c;建議收藏保存。.NET多平臺應用程序UI (MAUI)將android、iOS、macOS和Windows…

類與類之間的關系

橫向關系依賴 關聯 聚合 組合 判斷方法&#xff1a; 生命周期有關系&#xff1a;組合&#xff0c;聚合  聚合&#xff1a;包含多個相同的類  組合&#xff1a;定義的時候就要有  依賴&#xff1a;只要使用就必須要有  關聯&#xff1a;可有可無 縱向關系繼承 基類( 父類…

C語言試題155之有五個學生,每個學生有 3 門課的成績,從鍵盤輸入以上數據(包括學生號,姓名,三門課成績),計算出 平均成績,況原有的數據和計算出的平均分數存放在磁盤文件“stud“中

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:有五個學生,每個學生有 3 門…

仿照支付寶賬單界面--listview分組顯示 用來做!發!財樹充值交易明細

QQ圖片20150430155638.png (151.65 KB, 下載次數: 32) 下載鏈接: http://pan.baidu.com/s/1kVMY1SV 密碼: i8ta

系統中常用的目錄

Linux系統中常用的目錄 目錄 /bin 存放二進制可執行文件(ls,cat,mkdir等)&#xff0c;常用命令一般都在這里。 /etc 存放系統管理和配置文件 /home 存放所有用戶文件的根目錄&#xff0c;是用戶主目錄的基點&#xff0c;比如用戶user的主目錄就是/home/user&#xff0…

C語言試題156之有兩個磁盤文件 A 和 B,各存放一行字母,要求把這兩個文件中的信息合并(按字母順序排列), 輸出到一個新文件 C 中。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:有兩個磁盤文件 A 和 B,各存…

【ArcGIS微課1000例】0002:創建漁網(Create fishnet)

本文講解ArcGIS軟件中漁網(fishnet)工具的原理,方法及使用技巧。 文章目錄 微課目標工具介紹實現過程微課目標 如下圖所示,影像為無人機航測生產的DOM,現在需要在ArcGIS平臺中進行DLG數據采集(數字化),由于測區較大,需要創建500*500的漁網,并對影像進行裁剪下發給多…

基于http協議的api接口對于客戶端的身份認證方式以及安全措施[轉]

基于http協議的api接口對于客戶端的身份認證方式以及安全措施 由于http是無狀態的&#xff0c;所以正常情況下在瀏覽器瀏覽網頁&#xff0c;服務器都是通過訪問者的cookie(cookie中存儲的jsessionid)來辨別客戶端的身份的&#xff0c;當客戶端進行登錄服務器也會將登錄信息存放…

使用 Scrutor 快速實現“裝飾者模式”

裝飾者模式介紹裝飾器模式&#xff08;Decorator Pattern&#xff09;是在不改變原類和使用繼承的情況下&#xff0c;動態地給一個對象添加一些額外的職責。它是通過創建一個包裝對象&#xff0c;也就是裝飾來包裹真實的對象。可以在如下使用場景中使用裝飾器模式&#xff1a;在…

各個 Android Gradle 插件版本所需的 Gradle 版本

下表列出了各個 Android Gradle 插件版本所需的 Gradle 版本。 要獲得最佳性能&#xff0c;您應該使用 Gradle 和插件這兩者的最新版本。 插件版本所需的 Gradle 版本1.0.0 - 1.1.32.2.1 - 2.31.2.0 - 1.3.12.2.1 - 2.91.5.02.2.1 - 2.132.0.0 - 2.1.22.10 - 2.132.1.3 - 2.2…

JS時間戳和時間互轉

https://www.cnblogs.com/nield-bky/p/6040853.html http://blog.csdn.net/csdn565973850/article/details/73838583 時間轉時間戳&#xff1a; javascript獲得時間戳的方法有四種&#xff0c;都是通過實例化時間對象 new Date() 來進一步獲取當前的時間戳1.var timestamp1 Da…

C語言試題157之從鍵盤輸入一個字符串,將小寫字母全部轉換成大寫字母,然后輸出到一個磁盤文件“test”中保存。 輸入的字符串以!結束

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:從鍵盤輸入一個字符串,將小…

【ArcGIS微課1000例】0001:添加XY數據(Add XY data)生成shp

用過CASS的人都知道&#xff0c;野外數字測圖得到的點數據&#xff08;平面坐標&#xff09;可以直接在CASS中展點&#xff0c;進一步繪制地形圖。那么&#xff0c;帶有坐標的數據能不能在ArcGIS中實現點圖層的生成呢&#xff1f;答案是必須的&#xff01; 本文以氣象臺站Excel…

算法導論--廣度優先搜索和深度優先搜索

廣度優先搜索 在給定圖G(V,E)和一個特定的源頂點s的情況下&#xff0c;廣度優先搜索系統地探索G中的邊&#xff0c;以期“發現”可從s 到達的所有頂點&#xff0c;并計算s 到所有這些可達頂點之間的距離&#xff08;即最少的邊數&#xff09;。該搜索算法同時還能生成一棵根為s…

動手學 docker

背景動手學 docker最近&#xff0c;終于完成了 動手學 docker 系列的編寫。動手學 docker 是 動手學系列 的首個系列。如果反饋的效果不錯&#xff0c;后續還將推出 動手學 devops動手學 kubernetes動手學 istio 等系列。動手學系列 的構思來源于 李沐 老師的 動手學深度學習 。…