ClickHouse + Graphite: ինչպես է էապես նվազեցվում դիսկի տարածքի սպառումը

ClickHouse + Graphite: ինչպես է էապես նվազեցվում դիսկի տարածքի սպառումը

Բարի գալուստ, habr։

Եթե որևէ մեկը շահագործում է համակարգը graphite-web և բախվել է պահեստի կատարողականի խնդրի whisper (IO, օգտագործվող սկավառակի տարածություն), ապա հավանականությունը, որ ClickHouse-ը դիտարկվել է որպես փոխարինում, պետք է մոտենա մեկին: Այս հայտարարությունը ենթադրում է, որ որպես չստացված մետրիկների ընդունող արդեն օգտագործվում է երրորդ կողմի իրականացում, օրինակ carbonwriter կամ go-carbon.

ClickHouse-ն լավ լուծում է ներդրված խնդիրներին: Օրինակ, whisper-ից 2TiB տվյալների տեղափոխելուց հետո դրանք տեղավորվեցին 300GiB-ում: Հիմնականում չեմ կանգ առնելու համեմատության վրա, այս թեմայով հոդվածներ բավական են: Բացի այդ, մինչև վերջերս մեր ClickHouse պահեստի հետ ամեն ինչ գերազանց չէր:

Օգտվողական տարածքի խնդիրներ

Առաջին հայացքից, ամեն ինչ պետք է լավ աշխատի: Հետևելով փաստաթղթավորումը, ստեղծում ենք մետրիկների պահելու սխեմայի համար կոնֆիգ (հետագայում retention), ապա կազմում ենք աղյուսակ ըստ graphite-web-ի ընտրած նախադրյալների առաջարկի: carbon-clickhouse+graphite-clickhouse կամ graphouse, կախված նրանից, թե ինչ թեքնոլոռում է օգտագործվում: Եվ… սկսվում է դանդաղ գործողության պայթյուն:

Ուղին հասկանալու համար, թե որ վերջին, պետք է իմանալ, թե ինչպես են կատարում տվյալների ներարկումները և դրանց հետագա անելու ընթացքը *MergeTree ClickHouse (գրաֆիկները վերցված են նախահանձումից Ալեքսեյ Զատելիեփինի):

  • Ներարկվում է տեղեկատվության բլոկ: Մեր դեպքում, սա նմուշավորվեց մետրիկաները:
    ClickHouse + Graphite: ինչպես է էապես նվազեցվում դիսկի տարածքի սպառումը
  • Յուրաքանչյուր այդպիսի բլոկ, նախքան սկավառակի վրա գրառումը, դասավորվում է ըստ նշված բանալիի ORDER BY, որը նշված էր աղյուսակի ստեղծման ժամանակ:
  • Դասավորումից հետո, մանրամաս (part) տվյալները գրանցվում են սկավառակի վրա:
    ClickHouse + Graphite: ինչպես է էապես նվազեցվում դիսկի տարածքի սպառումը
  • Սերվերը հետևում է, որ նման հասցեների քանակը ավել չլինի, և սկսում է ֆոնային մենքերը (merge, հետագայում մերժները:
    ClickHouse + Graphite: ինչպես է էապես նվազեցվում դիսկի տարածքի սպառումը
    ClickHouse + Graphite: ինչպես է էապես նվազեցվում դիսկի տարածքի սպառումը
  • Սերվերը դադարեցնում է մերժների ինքնակառավարման համակարգը, ինչպես միայն տվյալները ակտիվ չեն տեղափոխվում տուջում (partition), բայց գործընթացը կարելի է ձեռքով սկսել OPTIMIZE.
  • Եթե բաժնում մնացել է միայն մեկ մանրամաս, ապա սրանով պարզ այլ կարգով չի հնարավոր OPTIMIZE ... FINAL

Այժմ, ներդրվում են առաջին մետրիկաները: Եվ նրանք զբաղեցնում են որոշ տարածություն: Հետագա դրսևորումները, տարբեր շատ ֆակտորներից կախված, կարող են մի փոքր փոխվել:

  • Բաժնավորման բանալին կարող է լինել ինչպես շատ փոքր (օր), այնպես էլ շատ մեծ (մի քանի ամիս):
  • Այս պահերթում պահպանման կոնֆիգը կարող է ներառել մի քանի նշանակալի արտասահմանյան շ阭ողքներին ակտիվ բաժնում (որտեղ մետրիկաներ են գրանցվում), կամ չի կարող էն:
  • Եթե տվյալները շատ են, ապա հենց առաջին բաժինները, որոնք կարող են արդեն լինել մեծ (ոչ օպտիմալ բաժնավորման բանալի ընտրելու դեպքում), չեն կարող միասին գրվել նոր փոքր բաժինների հետ:

Եվ վերջում միշտ ավարտվում է նույն ձևը: Մետրիկաների զբաղեցրած տարածությունը ClickHouse-ում միայն աճում է, եթե:

  • ոչ օգտագործել OPTIMIZE ... FINAL մենակ կամ
  • не փոխանցել տվյալները բոլոր հատ تقسیمումներին մշտապես, որպեսզի շուտ թե ուշ տեղադրվի ֆոնը միաձուլումը

Երկրորդ եղանակը թվում է իրականացման համար ամենահեշտը, ուստի դա սխալ է և առաջին հերթին փորձարկվել է:
Ես գրել եմ բավականին պարզ սցենար Python-ով, որը ուղարկում էր կեղծ մետրիկներ ամեն օր անցյալ 4 տարիների համար և ամեն ժամ запускался кроном:
Ինչպես կա ամբողջ աշխատանքը ClickHouse DBMS-ի վրա հիմնված է այն փաստի վրա, որ այս համակարգը շուտ թե ուշ կատարի ամբողջ ֆոնային աշխատանքը, բայց երբ, այդ պատճառով ես չկարողացա սպասել, երբ հին մեծ կտորները սկսեն միաձուլվել նոր փոքրերի հետ: واضح է, որ անհրաժեշտ է որոնել ավտոմատացման միջոցով պարտադրում գործողությունների:

ClickHouse + Graphite: ինչպես է էապես նվազեցվում դիսկի տարածքի սպառումը

Տվյալները ClickHouse-ի համակարգային աղյուսակներում

Մի ծառայում ենք աղյուսակի կառուցվածքին system.parts. Սա ամբողջական տեղեկատվություն է յուրաքանչյուր կտորի մասին, բոլոր աղյուսակների համար ClickHouse սերվերում: Այն պարունակում է, այդ թվում, հետևյալ սյուները:

  • իմ անունը БД (database);
  • իմ անունը աղյուսակում (սեղան);
  • հատվածի անունը և ID (partition & partition_id);
  • երբ կտորը ստեղծվել է (modification_time);
  • ցածր և բարձր ամսաթիվը կտորի մեջ (հատվածները իրականացվում են ըստ օրերի) (min_date & max_date);

Արժեք ունի նաև աղյուսակը system.graphite_retentions, հետևյալ հետաքրքիր ոլորտներով:

  • իմ անունը БД (Tables.database);
  • իմ անունը աղյուսակում (Tables.table);
  • մետրիկի տարիքը, երբ պետք է կիրառվի հաջորդ ագրեգացումը (age);

Այսինքն:

  1. Մենք ունենք կտորների աղյուսակ և ագրեգացման կանոնների աղյուսակ:
  2. Միանում ենք նրանց հատման և ստանում ենք բոլոր աղյուսակները *GraphiteMergeTree.
  3. Որոնում ենք բոլոր հատակարգեր, որտեղ:
    • ավելի քան մեկ կտոր
    • կամ հասել է հաջորդ ագրեգացման կանոնի կիրառելուն, և modification_time հին է այս պահին:

Իմացում

Այս հարցումն

SELECT
    concat(p.database, '.', p.table) AS table,
    p.partition_id AS partition_id,
    p.partition AS partition,
    -- Ամենաերիտասարդ "կանոն", որը կարող է կիրառվել
    -- հատթացի համար, բայց ոչ ապագայում, նայեք (*)
    max(g.age) AS age,
    -- Հատադարձներում կտորների քանակը
    countDistinct(p.name) AS parts,
    -- Առաջին ամենաերիտասարդ մտրիկը հաշվվում է օրվա 00:00:00-ն
    toDateTime(max(p.max_date + 1)) AS max_time,
    -- Երբ հատաթիվը պետք է օպտիմիզացվի
    max_time + age AS rollup_time,
    -- Երբ հատվածի ամենահին կտորը թարմացվել է
    min(p.modification_time) AS modified_at
FROM system.parts AS p
INNER JOIN
(
    -- Ամեն տեսակ կանոններ բոլոր աղյուսակների համար *GraphiteMergeTree
    SELECT
        Tables.database AS database,
        Tables.table AS table,
        age
    FROM system.graphite_retentions
    ARRAY JOIN Tables
    GROUP BY
        database,
        table,
        age
) AS g ON
    (p.table = g.table)
    AND (p.database = g.database)
WHERE
    -- Միայն ակտիվ կտորներ
    p.active
    -- (*) Եվ միայն այդ շարքերը, որտեղ ագրեգացման կանոնները արդեն պետք է կիրառվեն
    AND ((toDateTime(p.max_date + 1) + g.age) < now())
GROUP BY
    table,
    partition
HAVING
    -- Միայն հատկացումները, որոնք փոքր են օպտիմացման պահին
    (modified_at  1)
ORDER BY
    table ASC,
    partition ASC,
    age ASC

Անվտանգությունը վերադարձնում է այն բոլոր *GraphiteMergeTree տարվող հատվածները, որոնց միավորում պետք է հանգեցնի սկավառակի տեղատեղի ազատող։ Այժմ մնում է միայն վերհսկել դրանք բոլորով մեկ հարցմամբ OPTIMIZE ... FINAL. Գնահատված բաղադրիչը իրագործման ավարտական տարբերակում նույնպես հաշվի է առնվել այն, որ ակտիվ գրառում ունեցող հատվածները հպվել չի կարելի։

Սա հենց այն է, ինչ անում է նախագիծը graphite-ch-optimizer. Երեկվա գործընկերները Yandex.Market-ում փորձարկեցին այն պրոդուկտիվ միջավայրում, արդյունքը կարելի է տեսնել ստորև։

ClickHouse + Graphite: ինչպես է էապես նվազեցվում դիսկի տարածքի սպառումը

Եթե ծրագրային ապահովումը գործարկվի ClickHouse-ի հետ սերվերում, ապա այն պարզապես կսկսի աշխատել դեկանային ռեժիմում։ Մեկ ժամում մի հարցում կկատարվի, ստուգելով, թե արդյոք երեք օրից մեծ նոր հատվածներ չեն հայտնվել, որոնք կարելի է բարելավել։

Առաջիկա ծրագրերը՝ ապահովել, ամենաքիչը, deb փաթեթներով, իսկ հնարավորության դեպքում՝ նաև rpm-ները։

Վերջում

Ավելի քան 9 ամիս առաջ ես իմ ընկերությունում InnoGames վտանգել եմ շատ ժամանակ, գործող կազմակերպությունների և graphite-web միջավայրի խաչմերցումով։ Սա հիշվող փորձ էր, որի արդյունքում հնարավոր դարձավ արագ գործադրել whisper-ից ClickHouse-ը որպես մետրիկայի պահեստարան։ Espero որ այս հոդվածը՝ մի տեսակի օժանդակություն է, թե ինչ բարելավումներ մենք տարել ենք այս հատվածի տարբեր մասերում, և ինչ անելու ենք ապագայում։

Հարցի մշակմանը մի քանի լիտր գարեջուր և կառավարման օրեր են ծախսվել միասին հետ v0devil, որի համար ուզում եմ հայտնել նրա շնորհակալությունը։ Այդպիսով, նույնպես իր գնահատման համար այս հոդվածի։

Գործունեության էջը github-ում

Ընտանիք: habr.com

Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով 🔥 Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով | ProHoster