Upgrade to Pro — share decks privately, control downloads, hide ads and more …

대용량 데이터베이스 동기화를 위한 최적의 CDC 시스템 구축기

kakao
November 01, 2024

대용량 데이터베이스 동기화를 위한 최적의 CDC 시스템 구축기

#Data #CDC #Debezium #Flink #Iceberg #Spark

카카오 내 다양한 서비스의 데이터를 한 곳으로 응집하기 위한 대규모 CDC 파이프라인을 구축한 사례를 소개합니다. Flink와 Kafka Connect를 통해 수십억 건의 데이터를 MySQL과 Iceberg 까지 연동하는 과정에서 맞닥뜨린 어려움과 해결 방안을 공유합니다.

발표자 : dawn.choi, louis.sml

카카오 전사 데이터 조직의 데이터 엔지니어 던입니다. 카카오의 방대하고 다양한 데이터를 효율적으로 처리하는 대규모 CDC 파이프라인을 개발하고 있습니다.

flink와 kafka를 활용하여 다양한 시도를 하고 있는 루이스 이승민입니다. 요즘은 flink로 iceberg에 데이터를 적재하는 것에 집중하고 있어요.

kakao

November 01, 2024
Tweet

More Decks by kakao

Other Decks in Programming

Transcript

  1.  о੢؀઺੸ੋ౟ے੥࣌۽Ӓӝ߈$%$য়೑ࣗझ  ੌ߈੸ਵ۽஠೐஠ழ֏౟ӝ߈ਵ۽ز੘  .Z42- 1PTUHSF42- .POHP%#١׮নೠ%#.4૑ਗ  पदрਵ۽য়೐ࣇӝ۾

    ੤োزद݃૑݄ਵ۽੍਷য়೐ࣇद੼ীࢲࠂҳоמ  ૐ࠙झշࢫ *ODSFNFOUBM4OBQTIPU ӝמ૑ਗ %FCF[JVN
  2. झշࢫ %.- 4PVSDF     झշࢫ 5BSHFU 

         ߄੉ցܻ۽Ӓ ܻబ࣌ઓ੤
  3. ౟ے੥࣌۽Ӓ   ࣻ૘ 5BSHFU     

       ߈৔ 4PVSDF         ߄੉ցܻ۽Ӓ ౠ੿ష೗ী 
 য়೐ࣇ (5*%T ੷੢
  4. 4PVSDF ౟ے੥࣌۽Ӓ */4&35*/50DVTUPNFST7"-6&4  t5POZ4UBSLu { "schema": { "type": "struct",

    "fields": [ ... ], "optional": false, "name": "mysql-server-1.inventory.customers.Envelope" }, "payload": { "op": "c", "ts_ms": 1465491411815, "before": null, "after": { ... }, "source": { "db": "inventory", "table": "customers", ... } } } $IBOHF&WFOU
  5. ౟ے੥࣌۽Ӓ 5BSHFU ,BGLB { "schema": { "type": "struct", "fields": [

    ... ], "optional": false, "name": "mysql-server-1.inventory.customers.Envelope" }, "payload": { "op": "c", "ts_ms": 1465491411815, "before": null, "after": { ... }, "source": { "db": "inventory", "table": "customers", ... } } } $IBOHF&WFOU
  6. %FCF[JVN౵੉೐ۄੋ ,BGLB 1PTUHSF42- .Z42- ,BGLB$POOFDU 
 4PVSDF$POOFDUPS %FCF[JVN 
 .Z42-

    %FCF[JVN 
 1PTUHSF42- &4$POOFDUPS +%#$ 
 $POOFDUPS &MBTUJD4FBSDI 8BSFIPVTF ,BGLB$POOFDU 
 4JOL$POOFDUPS
  7. ୓௼ನੋ౟੷੢ 4PVSDF     5BSHFU   

               ߄੉ցܻ۽Ӓ ࣻ૘ ߈৔ )%'4 ୓௼ನੋ౟ী 
 য়೐ࣇ (5*%T ੷੢
  8. 'MJOL$%$بੑਵ۽঳਷੉੼  झշࢫࢿמ؀಩ೱ࢚  %FCF[JVN݅ਵ۽חࠛоמ೮؍ӝ؀ࢿמب׳  ߄੉ցܻ۽Ӓद੘য়೐ࣇ૒੽૑੿оמ  TDBOTUBSUVQNPEF২࣌ਵ۽FBSMJFTU TQFDJ

    fi D UJNFTUBNQ١द੘ਤ஖ਬোೞѱ૑੿  ੢গ୊ܻബਯࢿೱ࢚  ੢গद୓௼ನੋ౟ഝਊೞৈ੗زਵ۽੉੹࢚కࠂҳ  ੤दب੹ۚҳ୓੸ਵ۽ࢸ੿ fi YFE - EFMBZ FYQPOFOUJBM - EFMBZ
  9. ઱ਃࢸ੿  ݵ١ࢿ  VQTFSUݽ٘ࢎਊೞৈэ਷1,ܳо૓ۨ௏٘ী؀೧ݵ١ࢿࠁ੢  ؘ੉ఠ઺ࠂ੸੤ߑ૑  ߽۳୊ܻ 

    UBTLTNBY২࣌ࢎਊೞৈ߽۳ࢗੑ  ҃೷੸ਵ۽஠೐஠ష೗౵౭࣌ѐࣻ੄ীࢲ੿ب۽ࢸ੿ೞৈࢎਊ  ߥ௼ੋࢲ౟  SFXSJUF#BUDI*OTFSUT CBUDITJ[F২࣌ࢎਊೞৈୡ׼୊ܻਯೱ࢚  ఋѶؘ੉ఠ߬੉झীऺ੉ח۽Ӓࢎ੉ૉ؀಩хࣗ
  10. ੿೤ࢿѨࢎ 4PVSDF     5BSHFU   

      زӝചػప੉࠶рী੿೤ࢿਸ઱ӝ੸ਵ۽Ѩࢎೞݴزӝചҗ੿ীࢲ 
 ߊࢤоמೠؘ੉ఠࠛੌ஖ఐ૑
  11. 4PVSDF     5BSHFU    

     ߓ஖୊ܻী੸೤ೠझ౵௼ࢎਊਵ۽؀ӏݽؘ੉ఠܳੌҚ۽ࡅܰѱ୊ܻ  ࢎղҊࢿמೞن௿۞झఠ੗ਗഝਊ  ؘ੉ఠ೐ۨ੐ਸాೠѨࢎ۽૒ੌਗച ੿೤ࢿѨࢎ
  12.  ؘ੉ఠ࠺Үߑߨ  ੹୓ۨ௏٘࠺Ү  ੌױਤ߸ച࠙ۨ௏٘݅࠺Ү ೒݂௼оݒੌ੄߸ച࠙1,ܻझ౟ܳೞنী੷੢  Ѿҗഛੋߑߨ 

    ੌױਤ੿೤ࢿѾҗؘܳ੉ఠ߬੉झী੷੢  ݒੌয়੹ঌܿਸా೧ഛੋ ੿೤ࢿѨࢎ 🟢 [VALIDATION] যઁ, য়ט ప੉࠶ ࣻ: 300 / 300 Ѩࢎ ؘ੉ఠ ੌ੗: 2024-09-30 🟢 success(੿ഛبо 100% ~ 99% ࢎ੉ੋ ҃਋) ప੉࠶ ࣻ: 299ѐ 🟡 warning(੿ഛبо 99% ~ 95% ࢎ੉ੋ ҃਋) ప੉࠶ ࣻ: 1ѐ - service_name - database_name.table_name 98.928% (2801980/2832336)
  13.  %%-੉߮౟ઁ৻ࢸ੿JODMVEFTDIFNBDIBOHFTGBMTFࢎਊ  %%-੉റ੉߮౟ٜب੹࣠غযࢶউغӝীࠛ୽࠙  %%-੉߮౟ߊࢤद೒݂௼੟઺ױ  ஠೐஠ীFYBDUMZ - PODF۽੹࣠

    -> ஠೐஠۽ழ޿ө૑ࣻ೯غযঠ஠೐஠۽੹࣠غӝী੟઺ױࠛо 
 ੟ਸ઺ױೞݶ%%-૒੹੄੉߮౟ٜ੉஠೐஠۽੹࣠ؽਸࠁ੢ࠛо ੉गҊ۰೧ࠄࢎ೦
  14. ੉गߊࢤঌܿ  ؘ੉ఠ߬੉झ߂ప੉࠶੿ࠁ  (5*%T (MPCBM5SBOTBDUJPO*EFOUJ fi FST  ੤োزदࢎਊ

     ߊࢤೠ%%-੉߮౟ Host: source-database-slv.domain DB & Table: source_database.source_table GTIDs: 03725867-eb09-11ed-8566-b4055d39b0bc:1-1129608071 Query: ALTER TABLE `source_database`.`source_table` ADD COLUMN `added_column` TINYINT NULL
  15. ੉गழझథ4.5ҳഅ { "schema": {...}, "payload": { "source": { "db": "source_database",

    // ਗୌ ؘ੉ఠ߬੉झݺ "table": "source_table" // ਗୌ ప੉࠶ݺ }, "op": "r", … } }  ஠೐஠ݫद૑чನݘ਷٣࠺૑਑੄DIBOHFFWFOUನݘ  DIBOHFFWFOUী੓חؘ੉ఠ߬੉झ৬ప੉࠶ݺਸࢎਊ 
  16. ੉गழझథ4.5ҳഅ public abstract class RenameTopic<R extends ConnectRecord<R>> implements Transformation<R> {

    @Override public R apply(R record) { final String[] parts = record.valueSchema().toString().split("\\."); final String db = parts[1]; // ؘ੉ఠ߬੉झݺ ୶୹ final String table = parts[2]; // ప੉࠶ݺ ୶୹ // ࢜۽਍ ష೗ݺ ࢤࢿ ߂ ࢎਊ final String newTopic = String.format(..., db, table, shardId); return record.newRecord(newTopic, ...); } }  ݫद૑੄ؘ੉ఠ߬੉झ৬ప੉࠶ݺਸࢎਊೞৈష೗੉ܴਸ߸҃  ష೗੉ܴ߸҃੉ਬ  ஠೐஠ழ֏౟ীࢲప੉࠶ݺਸࢸ੿ೞ૑ঋਵݶష೗ݺਸప੉࠶ݺਵ۽ೞৈ੸੤  ݫद૑ܳࠁҊఋѶప੉࠶ࢶఖ 
  17.  ਗੋLBGLB - DPOOFDUۄ੉࠳۞ܻҙ۲  ஠೐஠ݫद૑ܳKTPOё୓۽߸ജद OVMMч؀नӝࠄчࢎਊ  ߡ੹ীࢲ೧Ѿ ,"',"

     ਗੋLBGLB - DPOOFDU - KECDۄ੉࠳۞ܻҙ۲  KTPOё୓ܳࣻ೯ؼ௪ܻ۽߸ജद OVMMч؀नӝࠄчࢎਊ ੉गਗੋ౵ঈ
  18. ੉गLBGLB - DPOOFDUۄ੉࠳۞ܻ۽૒ // ߡ੹ 3.4 ੉ೞ private JsonNode convertToJson(Schema

    schema, Object value) { … if (schema.defaultValue() != null) return convertToJson(schema, schema.defaultValue()); } // ߡ੹ 3.5 ੉࢚ private JsonNode convertToJson(Schema schema, Object value) { … // ࢸ੿ ч ഛੋ ઑѤ ୶о if (schema.defaultValue() != null && config.replaceNullWithDefault()) return convertToJson(schema, schema.defaultValue()); }  
  19. ੉गLBGLB - DPOOFDU - KECDۄ੉࠳۞ܻ۽૒ public Object get() { Object

    val = values[field.index()]; // ӝࠄ ч੉ ੓ਵݶ ೦࢚ ӝࠄ ч ࢎਊ if (val == null && field.schema().defaultValue() != null) { val = field.schema().defaultValue(); } return val; } 
  20.  KTPOё୓ী؀਽غחۄ੉࠳۞ܻղࠗё୓ীࢲӝࠄчઁডઁѢ ੉गழझథ4.5 ઁѢറ ઁѢ੹ PSHBQBDIFLBGLBDPOOFDUEBUB4USVDU LFZ4USVDU\JE^ JE */5 DOVMM

    */5 PQUJPOBM EFGBVMU Dt"u 453*/( PQUJPOBM PSHBQBDIFLBGLBDPOOFDUEBUB4USVDU LFZ4USVDU\JE^ JE */5 DOVMM */5 PQUJPOBM Dt"u 453*/( PQUJPOBM
  21.  ஠೐஠੄ઓࢿઁѢ 
 -> ࢎղҕਊ஠೐஠о੉٘ۄੋҊ۰೙ਃ9 
  ஠೐஠੄ઓࢿઁѢীٮۄ߸҃ػݫद૑ನݘ  "4

    - *4٣࠺૑਑੄DIBOHFFWFOU  50 - #&೒݂௼੄3PX%BUB ૐ࠙झշࢫױ҅ݫद૑੹࣠ܫઁড೧ࣗ // AS-IS: change event ನݘ ݫद૑ { "schema": {...}, "payload": { "before": {...}, "after": {...}, "source": {...}, "op": r, ... } } // TO-BE: RowData ನݘ ݫद૑ +I(25,hong,gildong,[email protected],Employee,1)
  22. রۨ௏٘ప੉࠶झ౵௼ࣗयदр࠺Ү .Z42-ప੉࠶ࣗय *DFCFSHప੉࠶ࣗय झ౵௼ 
 ੊झ௸ఠࢸ੿ ௏যࣻ ݫݽܻH ѐࣻ ௏যࣻ

    ݫݽܻH ѐࣻ ଵҊࢎ೦ ࠗೞ۽ੋ೧ഈ੄ػ੊झ௸ఠࢸ੿ ஹಂ࣌ࣻ೯दр҃җ ಣӐࣻ೯दр ࠙ ࠙
  23.  ই੉झߡӒח౵ੌ۽ؘ੉ఠٜਸҙܻ  ೒݂௼ח೦࢚.FSHF - PO - 3FBEߑधਵ۽ই੉झߡӒীؘ੉ఠ੸੤  .FSHF

    - PO - 3FBEؘ੉ఠ౵ੌҗ࢏ઁ౵ੌী࠙ܨೞৈؘ੉ఠ੷੢ ઑഥद੼ী೤୛ࠁৈષ ࢤࢿغח౵ੌٜ    ؘ੉ఠ౵ੌ ࢏ઁ౵ੌ 'MJOL$%$
  24. ࣗयदр߸ച ࣻ೯दр ࠙ ࠙ ࠙ ࠙ ࠙ ࠙ ࠙ ੌ

    ੌ ੌ ੌ ੌ ஹಂ࣌૒റ ࠙ ࠙ ࠙ ࠙ ࠙
  25.  ୨೤রۨ௏٘ѐࢥ٬ػప੉࠶  झ౵௼ܳా೧ೞա੄ই੉झߡӒప੉࠶ࣗय  ಣӐࣻ೯दрୡ  ୌ݅ۨ௏٘ప੉࠶_ୡ పझ౟Ѿҗ *DFCFSHప੉࠶ࣗय

    झ౵௼ 
 ੊झ௸ఠࢸ੿ ௏যࣻ ݫݽܻH ѐࣻ ଵҊࢎ೦ ஹಂ࣌ࣻ೯റदр҃җ ಣӐࣻ೯दр ୡ
  26.  ৈ۞೒݂௼੟ীࢲೞա੄ই੉झߡӒప੉࠶ীழ޿ࣻ೯ 
 -> زदࢿ੉ग۽р೵੸ழ޿पಁ  ழ޿੤दبപࣻטܾࣻ੓ਵա पജ҃ীࢲחউ੿੸਍৔੉؊઺ਃ ੸ਊޅೠ੉ਬ //

    ழ޿ਵ۽ ୭न ݫఋؘ੉ఠо ׳ۄઉ ী۞ ߊࢤ org.apache.iceberg.exceptions.CommitFailedException: Cannot commit: 
 Base metadata location ‘hdfs://.../.../XXX-A.metadata.json' is not same as the current table metadata location 'hdfs://.../.../XXX-B.metadata.json' for namespace.source_table
  27. 2"