成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

以一次 Data Catalog 架構(gòu)升級(jí)為例聊業(yè)務(wù)系統(tǒng)的性能優(yōu)化

原創(chuàng) 精選
開發(fā)
本文以 Data Catalog 系統(tǒng)升級(jí)過(guò)程為例,與大家討論業(yè)務(wù)系統(tǒng)性能優(yōu)化方面的思考,也會(huì)介紹我們關(guān)于 Apache Atlas 相關(guān)的性能優(yōu)化。

?作者 | 開發(fā)套件團(tuán)隊(duì)

摘要

字節(jié)的 DataCatalog 系統(tǒng),在 2021 年進(jìn)行過(guò)大規(guī)模重構(gòu),新版本的存儲(chǔ)層基于 Apache Atlas 實(shí)現(xiàn)。遷移過(guò)程中,我們遇到了比較多的性能問(wèn)題。本文以 Data Catalog 系統(tǒng)升級(jí)過(guò)程為例,與大家討論業(yè)務(wù)系統(tǒng)性能優(yōu)化方面的思考,也會(huì)介紹我們關(guān)于 Apache Atlas 相關(guān)的性能優(yōu)化。

背景

字節(jié)跳動(dòng) Data Catalog 產(chǎn)品早期,是基于 LinkedIn Wherehows 進(jìn)行二次改造,產(chǎn)品早期只支持 Hive 一種數(shù)據(jù)源。后續(xù)為了支持業(yè)務(wù)發(fā)展,做了很多修修補(bǔ)補(bǔ)的工作,系統(tǒng)的可維護(hù)性和擴(kuò)展性變得不可忍受。比如為了支持?jǐn)?shù)據(jù)血緣能力,引入了字節(jié)內(nèi)部的圖數(shù)據(jù)庫(kù) veGraph,寫入時(shí),需要業(yè)務(wù)層處理 MySQL、ElasticSearch 和 veGraph 三種存儲(chǔ),模型也需要同時(shí)理解關(guān)系型和圖兩種。更多的背景可以參照之前的文章。

新版本保留了原有版本全量的產(chǎn)品能力,將存儲(chǔ)層替換成了 Apache Atlas。然而,當(dāng)我們把存量數(shù)據(jù)導(dǎo)入到新系統(tǒng)時(shí),許多接口的讀寫性能都有嚴(yán)重下降,服務(wù)器資源的使用也被拉伸到夸張的地步,比如:

  • 寫入一張超過(guò) 3000 列的 Hive 表元數(shù)據(jù)時(shí),會(huì)持續(xù)將服務(wù)節(jié)點(diǎn)的 CPU 占用率提升到 100%,十幾分鐘后觸發(fā)超時(shí)
  • 一張幾十列的埋點(diǎn)表,上下游很多,打開詳情展示時(shí)需要等 1 分鐘以上

為此,我們進(jìn)行了一系列的性能調(diào)優(yōu),結(jié)合 Data Catlog 產(chǎn)品的特點(diǎn),調(diào)整了 Apache Atlas 以及底層 Janusgraph 的實(shí)現(xiàn)或配置,并對(duì)優(yōu)化性能的方法論做了一些總結(jié)。

業(yè)務(wù)系統(tǒng)優(yōu)化的整體思路

在開始討論更多細(xì)節(jié)之前,先概要介紹下我們做業(yè)務(wù)類系統(tǒng)優(yōu)化的思路。本文中的業(yè)務(wù)系統(tǒng),是相對(duì)于引擎系統(tǒng)的概念,特指解決某些業(yè)務(wù)場(chǎng)景,給用戶直接暴露前端使用的 Web 類系統(tǒng)。

優(yōu)化之前,首先應(yīng)明確優(yōu)化目標(biāo)。與引擎類系統(tǒng)不同,業(yè)務(wù)類系統(tǒng)不會(huì)追求極致的性能體驗(yàn),更多是以解決實(shí)際的業(yè)務(wù)場(chǎng)景和問(wèn)題出發(fā),做針對(duì)性的調(diào)優(yōu),需要格外注意避免過(guò)早優(yōu)化與過(guò)度優(yōu)化。

準(zhǔn)確定位到瓶頸,才能事半功倍。一套業(yè)務(wù)系統(tǒng)中,可以優(yōu)化的點(diǎn)通常有很多,從業(yè)務(wù)流程梳理到底層組件的性能提升,但是對(duì)瓶頸處優(yōu)化,才是 ROI 最高的。

根據(jù)問(wèn)題類型,挑性價(jià)比最高的解決方案。解決一個(gè)問(wèn)題,通常會(huì)有很多種不同的方案,就像條條大路通羅馬,但在實(shí)際工作中,我們通常不會(huì)追求最完美的方案,而是選用性價(jià)比最高的。

優(yōu)化的效果得能快速得到驗(yàn)證。性能調(diào)優(yōu)具有一定的不確定性,當(dāng)我們做了某種優(yōu)化策略后,通常不能上線觀察效果,需要一種更敏捷的驗(yàn)證方式,才能確保及時(shí)發(fā)現(xiàn)策略的有效性,并及時(shí)做相應(yīng)的調(diào)整。

業(yè)務(wù)系統(tǒng)優(yōu)化的細(xì)節(jié)

優(yōu)化目標(biāo)的確定

在業(yè)務(wù)系統(tǒng)中做優(yōu)化時(shí),比較忌諱兩件事情:

  • 過(guò)早優(yōu)化:在一些功能、實(shí)現(xiàn)、依賴系統(tǒng)、部署環(huán)境還沒(méi)有穩(wěn)定時(shí),過(guò)早的投入優(yōu)化代碼或者設(shè)計(jì),在后續(xù)系統(tǒng)發(fā)生變更時(shí),可能會(huì)造成精力浪費(fèi)。
  • 過(guò)度優(yōu)化:與引擎類系統(tǒng)不同,業(yè)務(wù)系統(tǒng)通常不需要跑分或者與其他系統(tǒng)產(chǎn)出性能對(duì)比報(bào)表,實(shí)際工作中更多的是貼合業(yè)務(wù)場(chǎng)景做優(yōu)化。比如用戶直接訪問(wèn)前端界面的系統(tǒng),通常不需要將響應(yīng)時(shí)間優(yōu)化到 ms 以下,幾十毫秒和幾百毫秒,已經(jīng)是滿足要求的了。

優(yōu)化范圍選擇

對(duì)于一個(gè)業(yè)務(wù)類 Web 服務(wù)來(lái)說(shuō),特別是重構(gòu)階段,優(yōu)化范圍比較容易圈定,主要是找出與之前系統(tǒng)相比,明顯變慢的那部分 API,比如可以通過(guò)以下方式收集需要優(yōu)化的部分:

  • 通過(guò)前端的慢查詢捕捉工具或者后端的監(jiān)控系統(tǒng),篩選出 P90 大于 2s 的 API
  • 頁(yè)面測(cè)試過(guò)程中,研發(fā)和測(cè)試同學(xué)陸續(xù)反饋的 API
  • 數(shù)據(jù)導(dǎo)入過(guò)程中,研發(fā)發(fā)現(xiàn)的寫入慢的 API 等

優(yōu)化目標(biāo)確立

針對(duì)不同的業(yè)務(wù)功能和場(chǎng)景,定義盡可能細(xì)致的優(yōu)化目標(biāo),以 Data Catalog 系統(tǒng)為例:

定位性能瓶頸手段

系統(tǒng)復(fù)雜到一定程度時(shí),一次簡(jiǎn)單的接口調(diào)用,都可能牽扯出底層廣泛的調(diào)用,在優(yōu)化某個(gè)具體的 API 時(shí),如何準(zhǔn)確找出造成性能問(wèn)題的瓶頸,是后續(xù)其他步驟的關(guān)鍵。下面的表格是我們總結(jié)的常用瓶頸排查手段。

優(yōu)化策略

在找到某個(gè)接口的性能瓶頸后,下一步是著手處理。同一個(gè)問(wèn)題,修復(fù)的手段可能有多種,實(shí)際工作中,我們優(yōu)先考慮性價(jià)比高的,也就是實(shí)現(xiàn)簡(jiǎn)單且有明確效果。

快速驗(yàn)證

優(yōu)化的過(guò)程通常需要不斷的嘗試,所以快速驗(yàn)證特別關(guān)鍵,直接影響優(yōu)化的效率。

Data Catalog 系統(tǒng)優(yōu)化舉例

在我們升級(jí)字節(jié) Data Catalog 系統(tǒng)的過(guò)程中,廣泛使用了上文中介紹的各種技巧。本章節(jié),我們挑選一些較典型的案例,詳細(xì)介紹優(yōu)化的過(guò)程。

調(diào)節(jié) JanusGraph 配置

實(shí)踐中,我們發(fā)現(xiàn)以下兩個(gè)參數(shù)對(duì)于 JanusGraph 的查詢性能有比較大的影響:

  • query.batch = ture
  • query.batch-property-prefetch=true

其中,關(guān)于第二個(gè)配置項(xiàng)的細(xì)節(jié),可以參照我們之前發(fā)布的文章。這里重點(diǎn)講一下第一個(gè)配置。

JanusGraph 做查詢的行為,有兩種方式:

針對(duì)字節(jié)內(nèi)部的應(yīng)用場(chǎng)景,元數(shù)據(jù)間的關(guān)系較多,且元數(shù)據(jù)結(jié)構(gòu)復(fù)雜,大部分查詢都會(huì)觸發(fā)較多的節(jié)點(diǎn)訪問(wèn),我們將 query.batch 設(shè)置成 true 時(shí),整體的效果更好。

調(diào)整 Gremlin 語(yǔ)句減少計(jì)算和 IO

一個(gè)比較典型的應(yīng)用場(chǎng)景,是對(duì)通過(guò)關(guān)系拉取的其他節(jié)點(diǎn),根據(jù)某種屬性做 Count。在我們的系統(tǒng)中,有一個(gè)叫“BusinessDomain”的標(biāo)簽類型,產(chǎn)品上,需要獲取與某個(gè)此類標(biāo)簽相關(guān)聯(lián)的元數(shù)據(jù)類型,以及每種類型的數(shù)量,返回類似下面的結(jié)構(gòu)體:

{
"guid": "XXXXXX",
"typeName": "BusinessDomain",
"attributes": {
"nameCN": "直播",
"nameEN": null,
"creator": "XXXX",
"department": "XXXX",
"description": "直播業(yè)務(wù)標(biāo)簽"
},
"statistics": [
{
"typeName": "ClickhouseTable",
"count": 68
},
{
"typeName": "HiveTable",
"count": 601
}
]
}

我們的初始實(shí)現(xiàn)轉(zhuǎn)化為 Gremlin 語(yǔ)句后,如下所示,耗時(shí) 2~3s:

g.V().has('__typeName', 'BusinessDomain')
.has('__qualifiedName', eq('XXXX'))
.out('r:DataStoreBusinessDomainRelationship')
.groupCount().by('__typeName')
.profile();

優(yōu)化后的 Gremlin 如下,耗時(shí)~50ms:

g.V().has('__typeName', 'BusinessDomain')
.has('__qualifiedName', eq('XXXX'))
.out('r:DataStoreBusinessDomainRelationship')
.values('__typeName').groupCount().by()
.profile();

Atlas 中根據(jù) Guid 拉取數(shù)據(jù)計(jì)算邏輯調(diào)整

對(duì)于詳情展示等場(chǎng)景,會(huì)根據(jù) Guid 拉取與實(shí)體相關(guān)的數(shù)據(jù)。我們優(yōu)化了部分 EntityGraphRetriever 中的實(shí)現(xiàn),比如:

  • mapVertexToAtlasEntity 中,修改邊遍歷的讀數(shù)據(jù)方式,調(diào)整為以點(diǎn)以及點(diǎn)上的屬性過(guò)濾拉取,觸發(fā) multiPreFetch 優(yōu)化。
  • 支持根據(jù)邊類型拉取數(shù)據(jù),在應(yīng)用層根據(jù)不同的場(chǎng)景,指定不同的邊類型集合,做數(shù)據(jù)的裁剪。最典型的應(yīng)用是,在詳情展示頁(yè)面,去掉對(duì)血緣關(guān)系的拉取。
  • 限制關(guān)系拉取的深度,在我們的業(yè)務(wù)中,大部分關(guān)系只需要拉取一層,個(gè)別的需要一次性拉取兩層,所以我們接口實(shí)現(xiàn)上,支持傳入拉取關(guān)系的深度,默認(rèn)一層。

配合其他的修改,對(duì)于被廣泛引用的埋點(diǎn)表,讀取的耗時(shí)從~1min 下降為 1s 以內(nèi)。

對(duì)大量節(jié)點(diǎn)依次獲取信息加并行處理

在血緣相關(guān)接口中,有個(gè)場(chǎng)景是需要根據(jù)血緣關(guān)系,拉取某個(gè)元數(shù)據(jù)的上下游 N 層元數(shù)據(jù),新拉取出的元數(shù)據(jù),需要額外再查詢一次,做屬性的擴(kuò)充。

我們采用增加并行的方式優(yōu)化,簡(jiǎn)單來(lái)說(shuō):

  • 設(shè)置一個(gè) Core 線程較少,但 Max 線程數(shù)較多的線程池:需要拉取全量上下游的情況是少數(shù),大部分情況下幾個(gè) Core 線程就夠用,對(duì)于少數(shù)情況,再啟用額外的線程。
  • 在批量拉取某一層的元數(shù)據(jù)后,將每個(gè)新拉取的元數(shù)據(jù)頂點(diǎn)加入到一個(gè)線程中,在線程中單獨(dú)做屬性擴(kuò)充
  • 等待所有的線程返回

對(duì)于關(guān)系較多的元數(shù)據(jù),優(yōu)化效果可以從分鐘級(jí)到秒級(jí)。

對(duì)于寫入瓶頸的優(yōu)化

字節(jié)的數(shù)倉(cāng)中有部分大寬表,列數(shù)超過(guò) 3000。對(duì)于這類元數(shù)據(jù),初始的版本幾乎沒(méi)法成功寫入,耗時(shí)也經(jīng)常超過(guò) 15 min,CPU 的利用率會(huì)飆升到 100%。

定位寫入的瓶頸

我們將線上的一臺(tái)機(jī)器從 LoadBalance 中移除,并構(gòu)造了一個(gè)擁有超過(guò) 3000 個(gè)列的元數(shù)據(jù)寫入請(qǐng)求,使用 Arthas 的 itemer 做 Profile,得到下圖:

從上圖可知,總體 70%左右的時(shí)間,花費(fèi)在 createOrUpdate 中引用的 addProperty 函數(shù)。

耗時(shí)分析

  1. JanusGraph 在寫入一個(gè) property 的時(shí)候,會(huì)先找到跟這個(gè) property 相關(guān)的組合索引,然后從中篩選出 Coordinality 為“Single”的索引
  2. 在寫入之前,會(huì) check 這些為 Single 的索引是否已經(jīng)含有了當(dāng)前要寫入的 propertyValue
  3. 組合索引在 JanusGraph 中的存儲(chǔ)格式為:

  1. Atlas 默認(rèn)創(chuàng)建的“guid”屬性被標(biāo)記為 globalUnique,他所對(duì)應(yīng)的組合索引是__guid。
  2. 對(duì)于其他在類型定義文件中被聲明為“Unique”的屬性,比如我們業(yè)務(wù)語(yǔ)義上全局唯一的“qualifiedName”,Atlas 會(huì)理解為“perTypeUnique”,對(duì)于這個(gè) Property 本身,如果也需要建索引,會(huì)建出一個(gè) coordinity 是 set 的完全索引,為“propertyName+typeName”生成一個(gè)唯一的完全索引

  1. 在調(diào)用“addProperty”時(shí),會(huì)首先根據(jù)屬性的類型定義,查找“Unique”的索引。針對(duì)“globalUnique”的屬性,比如“guid”,返回的是“__guid”;針對(duì)“perTypeUnique”的屬性,比如“qualifiedName”,返回的是“propertyName+typeName”的組合索引。

  1. 針對(duì)唯一索引,會(huì)嘗試檢查“Unique”屬性是否已經(jīng)存在了。方法是拼接一個(gè)查詢語(yǔ)句,然后到圖里查詢

  1. 在我們的設(shè)計(jì)中,寫入表的場(chǎng)景,每一列都有被標(biāo)記為唯一的“guid”和“qualifiedName”,“guid”會(huì)作為全局唯一來(lái)查詢對(duì)應(yīng)的完全索引,“qualifiedName”會(huì)作為“perTypeUnique”的查詢“propertyName+typeName”的組合完全索引,且整個(gè)過(guò)程是順序的,因此當(dāng)寫入列很多、屬性很多、關(guān)系很多時(shí),總體上比較耗時(shí)。

優(yōu)化思路

  • 對(duì)于“guid”,其實(shí)在創(chuàng)建時(shí)已經(jīng)根據(jù)“guid”的生成規(guī)則保證了全局唯一性,幾乎不可能有沖突,所以我們可以考慮去掉寫入時(shí)對(duì)“guid”的唯一性檢查,節(jié)省了一半時(shí)間。
  • 對(duì)于“qualifiedName”,根據(jù)業(yè)務(wù)的生成規(guī)則,也是“globalUnique”的,與“perTypeUnique”的性能差別幾乎是一倍:

優(yōu)化實(shí)現(xiàn)效果

  • 去除 Atlas 中對(duì)于“guid”的唯一性的檢查。
  • 添加“Global_Unqiue”配置項(xiàng),在類型定義時(shí)使用,在初始化時(shí)對(duì)“__qualifiedName”建立全局唯一索引。
  • 配合其他優(yōu)化手段,對(duì)于超多屬性與關(guān)系的 Entity 寫入,耗時(shí)可以降低為分鐘級(jí)。

總結(jié)

  • 業(yè)務(wù)類系統(tǒng)的性能優(yōu)化,通常會(huì)以解決某個(gè)具體的業(yè)務(wù)場(chǎng)景為目標(biāo),從接口入手,逐層解決
  • 性能優(yōu)化基本遵循思路:發(fā)現(xiàn)問(wèn)題->定位問(wèn)題->解決問(wèn)題->驗(yàn)證效果->總結(jié)提升
  • 優(yōu)先考慮“巧”辦法,“土”辦法,比如加機(jī)器改參數(shù),不為了追求高大上而走彎路
責(zé)任編輯:未麗燕 來(lái)源: 字節(jié)跳動(dòng)技術(shù)團(tuán)隊(duì)
相關(guān)推薦

2015-07-17 10:04:33

MKMapView優(yōu)化

2020-08-24 07:12:17

前端CRP性能優(yōu)化

2019-03-19 14:52:00

性能優(yōu)化MySQL數(shù)據(jù)庫(kù)

2022-11-11 07:58:05

業(yè)務(wù)中臺(tái)架構(gòu)

2020-06-05 08:53:31

接口性能實(shí)踐

2017-06-12 11:09:56

計(jì)數(shù)架構(gòu)數(shù)據(jù)庫(kù)

2021-11-23 09:45:26

架構(gòu)系統(tǒng)技術(shù)

2020-08-10 11:00:02

Python優(yōu)化代碼

2021-03-12 15:08:23

服務(wù)器性能優(yōu)化

2022-06-06 21:53:08

云原生云計(jì)算

2011-09-27 10:35:44

2024-07-09 11:51:20

Windows線程池源碼

2011-02-22 09:29:23

jQueryJavaScript

2023-11-06 07:45:42

單據(jù)圖片處理

2019-03-29 08:21:51

馬蜂窩Golang并發(fā)代理

2022-03-23 15:43:26

Android客戶端架構(gòu)

2021-03-05 22:41:55

CDH集群CDH集群

2020-10-30 14:11:38

服務(wù)器SDK堆棧

2022-10-28 11:26:01

光纖終端盒光纖安裝

2021-08-26 22:26:55

性能優(yōu)化技術(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲高清免费观看 | 日本福利在线 | 91成人免费电影 | 免费欧美 | 亚洲高清视频一区 | 免费在线观看av | 精品三区 | 天天爱综合| 国产精品99久久久久久www | 免费亚洲视频 | 成人影视网 | 91在线精品视频 | 91 在线| 在线天堂免费中文字幕视频 | 国产精品av久久久久久毛片 | 一本大道久久a久久精二百 国产成人免费在线 | 成人片免费看 | 亚洲欧洲小视频 | 久久久精 | 狠狠爱视频 | 免费高清成人 | 久久久久久免费精品一区二区三区 | 日本在线黄色 | 久草久 | 日韩蜜桃视频 | 中文字幕一区二区三区乱码在线 | 四虎午夜剧场 | 四虎网站在线观看 | 精精精精xxxx免费视频 | 日日操操 | 久久国产区 | 欧美日一区| www.天堂av.com | 欧美乱操 | 欧美精品久久 | 欧美日韩亚洲国产 | 日韩精品一区二区三区视频播放 | 亚洲午夜视频 | 在线观看亚洲欧美 | 欧美日韩成人网 | 国产亚洲区 |