Home > ๐Ÿ–Š๏ธ ์˜คํ”ˆ์†Œ์Šค ๊ธฐ์—ฌ > ๐Ÿ‘‰ Apache Iceberg > ๐Ÿ“˜ Iceberg Flink Catalog v2.0 MiniClusterWithClientResource ์ข…์†์„ฑ ์ œ๊ฑฐ

๐Ÿ“˜ Iceberg Flink Catalog v2.0 MiniClusterWithClientResource ์ข…์†์„ฑ ์ œ๊ฑฐ
OpenSource PR Iceberg Flink

โœ๏ธ 1. ์„œ๋ก 


์ž‘๋…„ 10์›”๊ฒฝ, ์ฒซ ์˜คํ”ˆ ์†Œ์Šค ๋ฉ˜ํ† ๋ง ํ”„๋กœ๊ทธ๋žจ์— ์ฐธ์—ฌํ•˜๋ฉด์„œ Spring Kafka ํ”„๋กœ์ ํŠธ์˜ Contributor ๊ฐ€ ๋˜๋Š” ์†Œ์ค‘ํ•œ ๊ฒฝํ—˜์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹œ์—๋Š” ์˜คํ”ˆ ์†Œ์Šค ์ƒํƒœ๊ณ„๊ฐ€ ์ฒ˜์Œ์ด์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋‹ค์†Œ ๋‚ฏ์„ค๊ณ  ์–ด๋ ต๊ฒŒ ๋А๊ปด์กŒ์ง€๋งŒ, ์šด ์ข‹๊ฒŒ๋„ ์ž…๋ฌธ์ž๋“ค์„ ์œ„ํ•œ ๋น„๊ต์  ๋‹จ์ˆœํ•œ ์ด์Šˆ๋ฅผ ํ†ตํ•ด ๊ธฐ์—ฌ๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ด์Šˆ๋Š” ๋ฌธ์„œ(Docs)์˜ ์ •์ •๊ณผ ์ผ๋ถ€ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ์ˆ˜์ • ์ •๋„์˜€์ง€๋งŒ, ์ €์—๊ฒŒ๋Š” ์˜คํ”ˆ ์†Œ์Šค์— ์ฒซ ๋ฐœ์„ ๋‚ด๋”›๋Š” ๋ฐ ๋งค์šฐ ์˜๋ฏธ ์žˆ๋Š” ๊ธฐํšŒ์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์˜ฌํ•ด, ๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฐ™์€ ๋ฉ˜ํ† ๋ง ์‹œ์Šคํ…œ์— ์ฐธ์—ฌํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋ฒˆ์—๋Š” ๋ฉ˜ํ† ๋ง์„ ๋ฐ›๋Š” ์ž…์žฅ์ด ์•„๋‹ˆ๋ผ, ๋ฉ˜ํ† ๋ง์„ ์ง€์›ํ•˜๊ณ  ์šด์˜ํ•˜๋Š” ์ž…์žฅ์œผ๋กœ ์ฐธ์—ฌํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฉ˜ํ‹ฐ๋“ค์˜ ์ด์Šˆ ์„ ์ •๊ณผ PR ๊ณผ์ •์— ์กฐ์–ธ์„ ์ฃผ๋ฉด์„œ, ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ €๋„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์˜คํ”ˆ ์†Œ์Šค ๊ธฐ์—ฌ๋ฅผ ๋„์ „ํ•ด๋ณด๊ณ  ์‹ถ์€ ์˜์š•์ด ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค. ( ์ด๋ฒˆ ํฌ์ŠคํŒ…์€ ICeberg ๊ธฐ์—ฌ ํฌ์ŠคํŒ…์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ฉ˜ํ† ๋ง์—์„œ ์šด์˜์ง„์œผ๋กœ์„œ ํ™œ๋™ํ•œ ๋‚ด์šฉ์€ ์ตœ์†Œํ™” ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ฒฐ๋ก ์—๋งŒ ์‚ด์ง ํฌ์ŠคํŒ…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. :D )

๊ทธ ๊ณผ์ •์—์„œ ๋ˆˆ๊ธธ์ด ๊ฐ„ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋ฐ”๋กœ Apache Iceberg์˜€์Šต๋‹ˆ๋‹ค. ์ด ํ”„๋กœ์ ํŠธ๋Š” ๋‹จ์ˆœํžˆ ๊ด€์‹ฌ๋งŒ ์žˆ์—ˆ๋˜ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํšŒ์‚ฌ ๋‚ด๋ถ€์—์„œ ์‹ ๊ทœ ์†”๋ฃจ์…˜ ๋„์ž… ์‹œ ์ง์ ‘ Iceberg๋ฅผ ์ œ์•ˆํ•˜์—ฌ ์‹ค์ œ๋กœ ์ ์šฉ๋˜๊ธฐ๋„ ํ–ˆ๊ณ , ํ•ด๋‹น ๊ธฐ์ˆ ์„ ๋ฐ”ํƒ•์œผ๋กœ ์‚ฌ๋‚ด ์ปจํผ๋Ÿฐ์Šค ๋ฐœํ‘œ๊นŒ์ง€ ์ง„ํ–‰ํ–ˆ๋˜ ๋งŒํผ, ๊ฐœ์ธ์ ์œผ๋กœ๋„ ์˜๋ฏธ๊ฐ€ ๊นŠ๊ณ  ์• ์ฐฉ์ด ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ด๋ฒˆ์—๋Š” ๋‹จ์ˆœํ•œ ๋ฌธ์„œ ์ˆ˜์ •์— ๋จธ๋ฌด๋ฅด์ง€ ์•Š๊ณ , ์‹ค์งˆ์ ์ธ ์ฝ”๋“œ ์ˆ˜์ค€์˜ ๊ธฐ์—ฌ๋ฅผ ๋ชฉํ‘œ๋กœ ์‚ผ์•˜์Šต๋‹ˆ๋‹ค. Apache Iceberg์˜ ๊ตฌ์กฐ๋ฅผ ๋” ๊นŠ์ด ์žˆ๊ฒŒ ์ดํ•ดํ•˜๊ณ , ์‹ค์ œ ๋™์ž‘์„ ๋ถ„์„ํ•˜๋ฉด์„œ ํ”„๋กœ์ ํŠธ์— ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ๋Š” ํฌ์ธํŠธ๋ฅผ ์ฐพ๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธฐํšŒ๋ฅผ ํ†ตํ•ด ๋” ํฐ ๋„์ „๊ณผ ์„ฑ์žฅ์˜ ๊ณ„๊ธฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.


โ—ˆ


โœ๏ธ 2. ๋ณธ๋ก 

๐Ÿค” 2.1. ์ด์Šˆ ์„ ํƒ ๊ณผ์ •


์ด๋ฒˆ ์ด์Šˆ ์„ ์ • ๊ณผ์ •์€ AI์˜ ๋„์›€ 50%, ๊ทธ๋ฆฌ๊ณ  ์ €์˜ ํŒ๋‹จ 50%๋กœ ์ด๋ฃจ์–ด์กŒ์Šต๋‹ˆ๋‹ค.

๋จผ์ €, ๊ธฐ์—ฌํ•˜๊ณ  ์‹ถ์€ ํ”„๋กœ์ ํŠธ๋กœ๋Š” ๋‹จ์—ฐ Apache Iceberg๊ฐ€ 1์ˆœ์œ„์˜€์Šต๋‹ˆ๋‹ค. Iceberg ์™ธ์—๋„ Spark, Airflow, Hadoop, Flink ๋“ฑ์˜ Apache ์žฌ๋‹จ ํ”„๋กœ์ ํŠธ๋ฅผ ํ›„๋ณด๊ตฐ์— ๋‘๊ณ , ๊ธฐ์—ฌ ๊ฐ€๋Šฅํ•œ ์ด์Šˆ๋“ค์„ ํ•˜๋‚˜์”ฉ ํƒ์ƒ‰ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์—์„œ Google์˜ Gemini๋ฅผ ํ™œ์šฉํ•ด Iceberg์˜ GitHub ์ €์žฅ์†Œ์—์„œ ์ด์Šˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆ˜์ง‘ํ–ˆ๊ณ , AI์—๊ฒŒ โ€œ๊ธฐ์—ฌํ•˜๊ธฐ ์ข‹์€ ์ด์Šˆ์˜ ๊ธฐ์ค€โ€์„ ํ”„๋กฌํ”„ํŠธ๋กœ ์ œ์‹œํ•˜์—ฌ ํ•„ํ„ฐ๋ง ์ž‘์—…์„ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๊ฒฐ๊ณผ, ์—ฌ๋Ÿฌ ์ด์Šˆ ์ค‘์—์„œ good first issue ๋ผ๋ฒจ์ด ๋ถ™์–ด ์žˆ๋Š” ํ•ญ๋ชฉ๋“ค์„ ์„ ๋ณ„ํ•ด๋‚ผ ์ˆ˜ ์žˆ์—ˆ๊ณ , ๊ทธ์ค‘์—์„œ๋„ ๋‹จ๋ฒˆ์— ๋ˆˆ์— ๋„๋Š” ์ด์Šˆ ํ•˜๋‚˜๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ ์ด๋ฒˆ์—๋Š” ์ˆ˜์ž‘์—…์œผ๋กœ๋งŒ ํƒ์ƒ‰ํ–ˆ๋˜ ๊ณผ๊ฑฐ์™€ ๋‹ฌ๋ฆฌ, AI ๋„๊ตฌ๋ฅผ ๋ณ‘ํ–‰ํ•˜์—ฌ ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•˜๋ฉด์„œ๋„ ํšจ์œจ์ ์œผ๋กœ ๊ธฐ์—ฌ ๋Œ€์ƒ ์ด์Šˆ๋ฅผ ์„ ์ •ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

1

1

์ด๋ ‡๊ฒŒ ์ด์Šˆ๋ฅผ ์„ ํƒํ•œ ์ €๋Š”, ์ด์Šˆ๋ฅผ ์˜ฌ๋ฆฐ Maintainer ์™€์˜ ์†Œํ†ต์„ ํ†ตํ•˜์—ฌ ํ•ด๋‹น ์ด์Šˆ๋ฅผ ๋งก๊ฒ ๋‹ค๊ณ  ์š”์ฒญํ•˜์˜€์Šต๋‹ˆ๋‹ค.

1

์ด๋Ÿฌํ•œ ๊ณผ์ •์„ ํ†ตํ•˜์—ฌ Exclude JUnit4 dependency from classpath ์—์„œ Remove JUnit4 dependency from Flink ๊นŒ์ง€ ์ด์–ด์ง€๋Š” ํ•ด๋‹น ์ด์Šˆ์— ๊ธฐ์—ฌ๋ฅผ ํ•˜๊ธฐ๋กœ ํ™•์ •ํ•˜์˜€๊ณ , ํšŒ์‚ฌ์—์„œ๋„ ๊ด€์‹ฌ์„ ๊ฐ€์ง€๊ณ , ์ € ๋˜ํ•œ ์ตœ๊ทผ ๊ณต๋ถ€๋ฅผ ํ•˜๊ณ  ์žˆ๋˜ Apache Iceberg ์— ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋ฅผ ์žก๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


Exclude JUnit4 dependency from classpath ์™€,
Remove JUnit4 dependency from Flink ์ด์Šˆ ๋ฅผ ๋ณด๋ฉด,
Apache Iceberg์˜ Maintainer๋Š” ์ „์ฒด ์ฝ”๋“œ๋ฒ ์ด์Šค, ํŠนํžˆ Flink ๊ด€๋ จ ๋ชจ๋“ˆ์—์„œ JUnit4 ์˜์กด์„ฑ์„ ์™„์ „ํžˆ ์ œ๊ฑฐํ•˜๋ ค๋Š” ๋ช…ํ™•ํ•œ ์˜์ง€๋ฅผ ๋“œ๋Ÿฌ๋‚ด๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‘ ์ด์Šˆ ๋ชจ๋‘ ๊ณตํ†ต์ ์œผ๋กœ, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ JUnit5 ๊ธฐ๋ฐ˜์œผ๋กœ ํ†ต์ผ๋˜๊ธธ ์›ํ•˜๋ฉฐ, ์˜ค๋ž˜๋œ ํ…Œ์ŠคํŠธ ์œ ํ‹ธ์ด๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋ฌถ์—ฌ ์žˆ๋Š” ์ž”์กด JUnit4 ์ข…์†์„ฑ์„ ์ œ๊ฑฐํ•˜๋Š” ๋ฐ ๋ชฉ์ ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € #12937 ์ด์Šˆ์—์„œ๋Š” iceberg-flink ๋ชจ๋“ˆ ๋‚ด์—์„œ JUnit4 ๊ด€๋ จ ์ข…์†์„ฑ์„ ์ œ๊ฑฐํ•˜๊ณ , JUnit5 ์Šคํƒ€์ผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•œ ์ผ๋ถ€ ์ž‘์—… ๋‚ด์—ญ์ด ๊ณต์œ ๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด Assume.assumeFalse(โ€ฆ)์™€ ๊ฐ™์€ ์ฝ”๋“œ๋Š” assumeThat(โ€ฆ).isEqualTo(โ€ฆ)์™€ ๊ฐ™์€ JUnit5 ์Šคํƒ€์ผ๋กœ ๋Œ€์ฒด๋˜๊ณ  ์žˆ์—ˆ์œผ๋ฉฐ, build.gradle ํŒŒ์ผ์—์„œ๋Š” junit ๊ทธ๋ฃน์„ ๋ช…์‹œ์ ์œผ๋กœ exclude ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์•„์ง๋„ ์™„์ „ํžˆ ์ œ๊ฑฐํ•˜์ง€ ๋ชปํ•œ ๋ถ€๋ถ„๋“ค์ด ์กด์žฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, TestIcebergSourceFailover ํ…Œ์ŠคํŠธ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ Flink์˜ MiniClusterWithClientResource๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๊ณ , ์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ๋Š” JUnit4์— ์˜์กดํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์™„์ „ํ•œ ์ œ๊ฑฐ์—๋Š” ์ œํ•œ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์ด์Šˆ์ธ #13049์—์„œ๋Š” ํ”„๋กœ์ ํŠธ ์ „์ฒด build.gradle์˜ classpath ๋ ˆ๋ฒจ์—์„œ JUnit4๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ œ์™ธํ•˜์ž๋Š” ์ œ์•ˆ์ด ๋‹ด๊ฒจ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์—ญ์‹œ Flink ๋ชจ๋“ˆ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, Testcontainers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ผ๋ถ€ ํด๋ž˜์Šค(GenericContainer)๋„ ์—ฌ์ „ํžˆ JUnit4์— ์˜์กดํ•˜๊ณ  ์žˆ์–ด, ์™„์ „ํ•œ ์ œ๊ฑฐ๋ฅผ ์œ„ํ•ด์„œ๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐฐ๊ฒฝ์—์„œ, ์ €๋Š” ํ•ด๋‹น ์ด์Šˆ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์ฒด์ ์ธ ๊ธฐ์—ฌ ๋ฐฉํ–ฅ์„ ์ •ํ•˜๊ณ  ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœํ•œ ๋ฌธ์„œ ์ˆ˜์ •์ด๋‚˜ ์„ค์ • ๋ณ€๊ฒฝ์„ ๋„˜์–ด์„œ, ์ง์ ‘ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ๊ตฌ์กฐ๋ฅผ ๊ฐœ์„ ํ•˜๊ณ , Gradle ์˜์กด์„ฑ์„ ๋‹ค๋ฃจ๋ฉฐ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ๊นŒ์ง€ ๊ณ ๋ฏผํ•ด์•ผ ํ•˜๋Š” ๋„์ „์ ์ธ ๊ณผ์ œ์˜€๊ธฐ์— ๋”์šฑ ์˜๋ฏธ๊ฐ€ ์ปธ์Šต๋‹ˆ๋‹ค.


๐Ÿ‘‰ ํ•ด๋‹น ์ด์Šˆ๋Š” ์œ„์—์„œ ์„ค๋ช…ํ•œ, Apache Iceberg ์˜ #13049 ์™€, #12937 ์ด์Šˆ ์— ์žˆ๋Š” ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

๐Ÿ’ฌ 2.3. Maintainer ์™€์˜ ์†Œํ†ต ๊ณผ์ •์„ ํ†ตํ•œ, PR ๋ฐฉํ–ฅ์„ฑ ํ™•๋ฆฝ


์ €๋Š” Apache Iceberg ํ”„๋กœ์ ํŠธ์˜ Maintainer์ธ @nastra ๋‹˜๊ณผ ์ฃผ์š” ๊ธฐ์—ฌ์ž ์ค‘ ํ•œ ๋ถ„์ธ @tomtongue ๋‹˜๊ณผ ๋ฐ”๋กœ ์†Œํ†ต์„ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.
๋จผ์ €, ํ•ด๋‹น ์ž‘์—…์— ์ฐธ์—ฌํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ์˜์‚ฌ๋ฅผ ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒผ๊ณ , Maintainer๋‹˜๊ป˜์„œ๋Š” ๋งค์šฐ ํ™˜์˜ํ•ด ์ฃผ์‹œ๋ฉฐ ์ž์œ ๋กญ๊ฒŒ ์ž‘์—…์„ ์ง„ํ–‰ํ•ด๋„ ๋œ๋‹ค๋Š” ๊ธ์ •์ ์ธ ๋‹ต๋ณ€์„ ์ฃผ์…จ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ, ์ €๋ณด๋‹ค ๋จผ์ € ๊ฐ™์€ ์ด์Šˆ์— ๊ด€์‹ฌ์„ ๋ณด์ธ tomtongue ๋‹˜๊ณผ ํ˜‘์—… ๊ฐ€๋Šฅ์„ฑ๋„ ์—ด์–ด๋‘์—ˆ๋Š”๋ฐ, ๊ทธ๋ถ„์€ Flink ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ž‘์—…์—๋Š” ์‹œ๊ฐ„์ด ์ข€ ๋” ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ๋ง์”€ํ•ด ์ฃผ์…จ์Šต๋‹ˆ๋‹ค.
์ด์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฐ€ ๋จผ์ € ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์—ญํ• ์ด ์ •๋ฆฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ตฌ์ฒด์ ์ธ ์ž‘์—… ๊ณ„ํš์œผ๋กœ๋Š”, ์šฐ์„  JUnit4์— ์˜์กดํ•˜๊ณ  ์žˆ๋˜ TestIcebergSourceFailover ํด๋ž˜์Šค๋ฅผ JUnit5๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ๊ฒƒ๊ณผ, Gradle ์„ค์ •์—์„œ JUnit4 ์ข…์†์„ฑ์„ ์ œ๊ฑฐํ•˜๋Š” ์ž‘์—…์„ ํฌํ•จํ–ˆ์Šต๋‹ˆ๋‹ค.
์ฒ˜์Œ์—๋Š” Flink 2.0 ๋ฒ„์ „๋ถ€ํ„ฐ ์ž‘์—…์„ ์‹œ์ž‘ํ•œ ๋’ค, ์ดํ›„ 1.20 ๋ฐ 1.19 ๋ฒ„์ „์œผ๋กœ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ฐฑํฌํŒ…(backport)ํ•˜๊ฒ ๋‹ค๋Š” ๊ณ„ํš์„ Maintainer๋‹˜๊ป˜ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.

Maintainer๋‹˜๋„ ์ด ๊ณ„ํš์ด ์ ์ ˆํ•˜๋‹ค๋ฉฐ, ์šฐ์„  Flink 2.0 ๋ชจ๋“ˆ์—์„œ ์ž‘์—…์„ ์ง„ํ–‰ํ•œ ๋’ค ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€ํ† ๋ฐ›๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ๋‹ค๋Š” ํ”ผ๋“œ๋ฐฑ์„ ์ฃผ์…จ์Šต๋‹ˆ๋‹ค.
์ดํ›„ ์ €๋Š” ์ฒซ ๋ฒˆ์งธ PR์ธ #13016์„ ์ œ์ถœํ•˜์˜€๊ณ , ๊ธฐ์กด์— ์‚ฌ์šฉ๋˜๋˜ MiniClusterWithClientResource ์˜์กด์„ฑ์„ ์ œ๊ฑฐํ•˜๋ฉด์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์™€ Gradle ์„ค์ •์„ ํ•จ๊ป˜ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ Gradle ์„ค์ •์„ ์ˆ˜์ •ํ•˜๋Š” ๊ณผ์ •์—์„œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‹œ๋„ํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , JUnit4์— ๋Œ€ํ•œ ์ข…์†์„ฑ์„ ์™„์ „ํžˆ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์‰ฝ์ง€ ์•Š์•˜๊ณ , ๋นŒ๋“œ์™€ ํ…Œ์ŠคํŠธ ๊ณผ์ •์—์„œ ์ง€์†์ ์œผ๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์— Maintainer๋‹˜๊ณผ ๋‹ค์‹œ ์†Œํ†ตํ•œ ๊ฒฐ๊ณผ, Flink ๋‚ด๋ถ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ค‘ ํ•˜๋‚˜์ธ InternalMiniClusterExtension์ด ์—ฌ์ „ํžˆ JUnit4๋ฅผ ํ•„์š”๋กœ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์™„์ „ํ•œ ์ œ๊ฑฐ๋Š” ํ˜„์‹ค์ ์œผ๋กœ ์–ด๋ ต๋‹ค๋Š” ์ ์— ํ•จ๊ป˜ ๋™์˜ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , Iceberg ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด์—์„œ๋Š” JUnit4 ์˜์กด์„ฑ์„ ์ตœ์†Œํ™”ํ•˜๊ณ , ๊ฐ€๋Šฅํ•˜๋ฉด JUnit5 ์ค‘์‹ฌ์œผ๋กœ ํ†ต์ผํ•˜๋Š” ๋ฐฉํ–ฅ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ค๋Š” ์˜๊ฒฌ์„ ์ฃผ์…”์„œ, ์ € ์—ญ์‹œ ์ด ๊ฐ€์ด๋“œ๋ผ์ธ์— ๋งž์ถฐ TestIcebergSourceFailover ํด๋ž˜์Šค๋ฅผ ์ค‘์‹ฌ์œผ๋กœ PR์„ ์ง€์†ํ•ด์„œ ์ •์ œํ•ด ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ์†Œํ†ต ๊ณผ์ •์„ ํ†ตํ•ด, ๋‹จ์ˆœํ•œ ์ฝ”๋“œ ์ˆ˜์ •๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ”„๋กœ์ ํŠธ ๋‚ด๋ถ€ ์ƒํ™ฉ๊ณผ ์ œ์•ฝ์„ ์ดํ•ดํ•˜๋ฉฐ ํ˜‘๋ ฅํ•˜๋Š” ๊ฒฝํ—˜์„ ์Œ“์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

โ€๐Ÿ’ป 2.4. PR: JUnit4 ์˜์กด์„ฑ ์ตœ์†Œํ™” ๋ฐ MiniClusterWithClientResource ์ข…์†์„ฑ ์ œ๊ฑฐ


ํ•ด๋‹น ์†Œ์Šค๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์ „, ์ €๋Š” Iceberg์— ๋Œ€ํ•ด์„œ๋Š” ์‚ฌ๋‚ด ์ปจํผ๋Ÿฐ์Šค๋ฅผ ์ง„ํ–‰ํ•  ๋งŒํผ ์ถฉ๋ถ„ํžˆ ๊ณต๋ถ€ํ•œ ์ƒํƒœ์˜€์ง€๋งŒ, ์นดํƒˆ๋กœ๊ทธ ์—”์ง„๊ณผ ๊ด€๋ จํ•ด์„œ๋Š” Spark์™€ JDBC ๊ธฐ๋ฐ˜์˜ ๋ช‡ ๊ฐ€์ง€์— ๋Œ€ํ•ด์„œ๋งŒ ์ฃผ๋กœ ์•Œ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๋ฐ˜๋ฉด, Flink์— ๋Œ€ํ•ด์„œ๋Š” ์ƒ๋Œ€์ ์œผ๋กœ ์ต์ˆ™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. Flink๋Š” ์ฃผ๋กœ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆฌ๋ฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ถ„์‚ฐ ์ฒ˜๋ฆฌ ์—”์ง„์œผ๋กœ, Iceberg์—์„œ๋Š” Flink ์ปค๋„ฅํ„ฐ๋ฅผ ํ†ตํ•ด ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ํ™œ์šฉ๋˜๊ณ  ์žˆ๋‹ค ์ •๋„๋กœ๋งŒ ์•Œ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
( ์ €ํฌ ํšŒ์‚ฌ๋Š” Flink ๋ฅผ ์“ฐ๊ณ  ์žˆ์ง€๋Š” ์•Š์ง€๋งŒ, Iceberg ๋ฅผ ๊ณต๋ถ€ํ•  ๋•Œ ์ฐธ๊ณ ํ•˜์˜€๋˜ Kakao ๊ธฐ์ˆ  ๋ธ”๋กœ๊ทธ์˜ louis ๋‹˜ ๊ธ€ ๋•๋ถ„์— Flink ์— ๋Œ€ํ•˜์—ฌ ๊ณต๋ถ€๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Apache Iceberg์™€ Flink CDC ์‹ฌ์ธต ํƒ๊ตฌ, ์•„ํŒŒ์น˜ ํ”Œ๋งํฌ์™€ CDC์˜ ๋งŒ๋‚จ. ํ”Œ๋งํฌ CDC ๋ง›๋ณด๊ธฐ )

ํ•˜์ง€๋งŒ Flink ๋‚ด๋ถ€์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” โ€˜MiniClusterโ€™๋ผ๋Š” ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ๋Š” ์ „ํ˜€ ์•Œ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด์— Flink ๊ณต์‹ ๋ฌธ์„œ์™€ ์ปค๋ฎค๋‹ˆํ‹ฐ ์ž๋ฃŒ, ๊ทธ๋ฆฌ๊ณ  GitHub ์ €์žฅ์†Œ ๋“ฑ์„ ์ฐธ๊ณ ํ•˜์—ฌ โ€˜MiniClusterโ€™๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๊ณต๋ถ€ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

MiniCluster๋Š” Flink ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ๊ฐ€๋ณ๊ฒŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ์ผ์ข…์˜ ๋ฏธ๋‹ˆ ๋ฒ„์ „ ํด๋Ÿฌ์Šคํ„ฐ๋กœ, ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์‹ค์ œ ๋ถ„์‚ฐ ํ™˜๊ฒฝ๊ณผ ์œ ์‚ฌํ•œ ์กฐ๊ฑด์„ ๋งŒ๋“ค์–ด Flink ์ž‘์—…์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
์ฆ‰, ์‹ค์ œ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๋„์šฐ์ง€ ์•Š๊ณ ๋„ ๋กœ์ปฌ์—์„œ Flink ์žก์„ ์‹คํ–‰ํ•ด๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ์ž๋™ํ™”์™€ ๋””๋ฒ„๊น…์— ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ MiniCluster๊ฐ€ Flink ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์–ด๋–ค ํ•ต์‹ฌ์ ์ธ ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด, ์ด๋ฒˆ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•œ ์ฒซ๊ฑธ์Œ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ์€, ๋“œ๋””์–ด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์‹œ์ž‘ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
์ˆœ์„œ๋Š” Junit4 ๋ฅผ ์–ด์ฉ” ์ˆ˜ ์—†์ด ์˜์กดํ•ด์•ผํ•˜๋Š” ๋ถ€๋ถ„์€ ์‚ด๋ฆฌ๊ณ , ์ด์ „ ์ปค๋ฏธํ„ฐ๊ฐ€ ๋ฏธ์ฒ˜ ์ˆ˜์ •ํ•˜์ง€ ๋ชปํ•œ Junit5 ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ•˜๋Š” ์ž‘์—…์„ ๋จผ์ € ์ง„ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ดํ›„์—๋Š”, TestIcebergSourceFailover ํด๋ž˜์Šค์—์„œ Junit4 ๋ฅผ ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์ด ์–ด๋””์ธ์ง€๋ฅผ ์ฐพ๊ณ , ๊ทธ ๋ถ€๋ถ„์„ Junit5 ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

1๏ธโƒฃ COMMIT : GenericAppenderHelper ์˜ ์ƒ์„ฑ์ž @Deprecated ์ œ๊ฑฐ

์ฒซ ๋ฒˆ์งธ๋กœ, GenericAppenderHelper.java ์ฝ”๋“œ์—์„œ, ์ƒ์„ฑ์ž๊ฐ€ @Deprecated ๋˜์–ด์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ์— JUnit์—์„œ ํ”ํžˆ ์“ฐ๋˜ TemporaryFolder ๊ฐ์ฒด๋ฅผ ์ธ์ž๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค. TemporaryFolder๋Š” ํ…Œ์ŠคํŠธ ์ค‘ ์ž„์‹œ ํŒŒ์ผ/๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ž๋™ ์ƒ์„ฑํ•˜๊ณ  ์ •๋ฆฌํ•ด์ฃผ๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์•„๋งˆ, Junit4 ์˜์กด์„ฑ์„ ์™„์ „ํžˆ ๊ฑท์–ด๋‚ด๊ธฐ ์œ„ํ•œ ๊ณผ์ •์—์„œ @Deprecated ๋ฅผ ํ•ด๋‘” ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์œ„์—์„œ ์ด์•ผ๊ธฐํ•˜์˜€๋“ฏ ํ˜„์žฌ Junit4 ๋ฅผ ์™„์ „ํžˆ ๊ฑท์–ด๋‚ด๋Š” ๊ฒƒ์€ ์–ด๋ ต๋‹ค๊ณ  ํŒ๋‹จํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์—, ์•„์ง๊นŒ์ง€ GenericAppenderHelper ํด๋ž˜์Šค๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ์†Œ์Šค๋“ค์„ ์œ„ํ•ด์„œ, @Deprecated ๋ฅผ ์‚ญ์ œํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ( ์‚ญ์ œํ•˜์ง€ ์•Š์œผ๋ฉด, CI ํ…Œ์ŠคํŠธ ์‹œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. )

Before:

@Deprecated
public GenericAppenderHelper(Table table, FileFormat fileFormat, TemporaryFolder tmp, Configuration conf) {
    this.table = table;
    this.fileFormat = fileFormat;
    this.temp = tmp.getRoot().toPath();
    this.conf = conf;
}

@Deprecated
public GenericAppenderHelper(Table table, FileFormat fileFormat, TemporaryFolder tmp) {
    this(table, fileFormat, tmp, null);
}

After:

public GenericAppenderHelper(Table table, FileFormat fileFormat, TemporaryFolder tmp, Configuration conf) {
    this.table = table;
    this.fileFormat = fileFormat;
    this.temp = tmp.getRoot().toPath();
    this.conf = conf;
}

public GenericAppenderHelper(Table table, FileFormat fileFormat, TemporaryFolder tmp) {
    this(table, fileFormat, tmp, null);
}


2๏ธโƒฃ COMMIT : Junit4 ์˜ Assume ์„ ๊ฑท์–ด๋‚ด๊ณ , AssertJ ๋ฐฉ์‹ ํ™œ์šฉ

๋‘ ๋ฒˆ์งธ๋กœ ์ด์ „์— Junit4 ์—์„œ Junit5 ๋กœ ์˜์กด์„ฑ ๋ณ€๊ฒฝ์„ ์‹œ๋„ํ–ˆ๋˜ ์ปค๋ฏธํ„ฐ๋ถ„์ด ๋ฏธ์ฒ˜ ์ˆ˜์ •ํ•˜์ง€ ๋ชปํ•œ ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์ณค์Šต๋‹ˆ๋‹ค.

Flink 2.0 ์˜ TestIcebergSink ํด๋ž˜์Šค์—์„œ, ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ Junit4 ๋ฐฉ์‹์˜ Assume.assumeFalse(...) ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ถ€๋ถ„์ด ์žˆ์–ด์„œ, ๋‹ค๋ฅธ ๋ฒ„์ „์˜ TestIcebergSink ํด๋ž˜์Šค๋“ค๊ณผ ๋™์ผํ•˜๊ฒŒ AssertJ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ assumeThat ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

Before:

import org.junit.Assume;

// ...

@TestTemplate
  void testErrorOnNullForRequiredField() throws Exception {
    Assume.assumeFalse(
        "ORC file format supports null values even for required fields.", format == FileFormat.ORC);
		
	// Next Code ...
  }

After:

import static org.assertj.core.api.Assumptions.assumeThat;

// ...

@TestTemplate
  void testErrorOnNullForRequiredField() throws Exception {
    assumeThat(format)
        .as("ORC file format supports null values even for required fields.")
        .isNotEqualTo(FileFormat.ORC);
		
	// Next Code ...
  }


3๏ธโƒฃ COMMIT : MiniClusterWithClientResource ์ข…์†์„ฑ ์ œ๊ฑฐ

๋งˆ์ง€๋ง‰์ด ๋“œ๋””์–ด, ์ด๋ฒˆ PR ์˜ ๊ฝƒ์ธ, TestIcebergSourceFailover ํด๋ž˜์Šค์—์„œ MiniClusterWithClientResource ์ข…์†์„ฑ์„ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ถ€๋ถ„์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์กฐ๊ธˆ ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ, ๋จผ์ € ASIS ์ฝ”๋“œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Before:

import org.apache.flink.test.util.MiniClusterWithClientResource;
import org.apache.flink.util.function.ThrowingConsumer;

// ...

@Test
public void testBoundedWithTaskManagerFailover() throws Exception {
    runTestWithNewMiniCluster(
        miniCluster -> testBoundedIcebergSource(FailoverType.TM, miniCluster));
}

@Test
public void testBoundedWithJobManagerFailover() throws Exception {
    runTestWithNewMiniCluster(
        miniCluster -> testBoundedIcebergSource(FailoverType.JM, miniCluster));
}
  
// ...

@Test
public void testContinuousWithTaskManagerFailover() throws Exception {
    runTestWithNewMiniCluster(
        miniCluster -> testContinuousIcebergSource(FailoverType.TM, miniCluster));
}

@Test
public void testContinuousWithJobManagerFailover() throws Exception {
    runTestWithNewMiniCluster(
        miniCluster -> testContinuousIcebergSource(FailoverType.JM, miniCluster));
}

// ...

private static void runTestWithNewMiniCluster(ThrowingConsumer<MiniCluster, Exception> testMethod) throws Exception {
    MiniClusterWithClientResource miniCluster = null;
    try {
        miniCluster = new MiniClusterWithClientResource(MINI_CLUSTER_RESOURCE_CONFIG);
	    miniCluster.before();
        testMethod.accept(miniCluster.getMiniCluster());
    } finally {
        if (miniCluster != null) {
          miniCluster.after();
        }
    }
}

๋จผ์ €, JUnit 5์—์„œ๋Š” @BeforeAll, @AfterAll, @BeforeEach, @AfterEach๋ฅผ ์‚ฌ์šฉํ•ด ๋ฆฌ์†Œ์Šค ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒŒ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•ด๋‹น ์ฝ”๋“œ๋Š” ํ…Œ์ŠคํŠธ๋งˆ๋‹ค miniCluster.before() / after()๋ฅผ ์ˆ˜๋™์œผ๋กœ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋ถ€๋ถ„์ด JUnit 4 ์Šคํƒ€์ผ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ, MiniClusterWithClientResource ๋Š” ๋ณดํ†ต JUnit4์˜ ExternalResource ๋ฅผ ์ƒ์†ํ•ด์„œ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. JUnit4์—์„œ๋Š” ๋ฆฌ์†Œ์Šค ์ดˆ๊ธฐํ™”์™€ ์ •๋ฆฌ๋ฅผ ์œ„ํ•ด @Rule ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ExternalResource ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š”, Flink ๊ฐœ๋ฐœ ์ดˆ๊ธฐ ์‹œ์ ๊ณผ JUnit5 ๋„์ž… ์‹œ์ ์˜ ์‹œ๊ธฐ์  ์ฐจ์ด ๋•Œ๋ฌธ์—, ๊ธฐ์กด์— ์ž˜ ๋งŒ๋“ค์–ด์ง„ ํ…Œ์ŠคํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋“ค์ด JUnit4 ์Šคํƒ€์ผ๋กœ ๋งŽ์ด ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ด์œ  ๋•Œ๋ฌธ์—, ์‚ฌ์‹ค ์™„์ „ํžˆ Junit4 ๋ฅผ ๋‹น์žฅ ๊ฑท์–ด๋‚ด๋Š” ๊ฒƒ์ด ์–ด๋ ต๋‹ค๊ณ  ํŒ๋‹จํ•œ ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฆ‰, Flink ์˜ Minicluster ๋ฅผ ํ™œ์šฉํ•œ ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์ž์ฒด๊ฐ€ ์™„์ „ํžˆ JUnit5๋กœ ์™„์ „ํžˆ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๋˜์ง€ ์•Š์€ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์—, Iceberg ์—๋„ ๋‹น์žฅ ์ ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์œผ๋กœ ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค.

๊ณ„์† ์ด์–ด์„œ ์„ค๋ช…ํ•˜์ž๋ฉด, ์—ฌ๊ธฐ์„œ๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค MiniClusterWithClientResource ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜๊ณ , ์ˆ˜๋™์œผ๋กœ before()์™€ after()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํด๋Ÿฌ์Šคํ„ฐ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ œ์–ดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๋“ค์€ MiniCluster๋ฅผ ์ง์ ‘ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์ง€ ์•Š๊ณ , ๋žŒ๋‹ค ThrowingConsumer์— ๋„˜๊ฒจ์„œ ๊ฐ„์ ‘์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ๋ฅผ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ์ œ์–ดํ•˜๋Š” ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค. ๋ณดํ†ต ์ด๋Ÿฐ ๋ฐฉ์‹์€ JUnit4์—์„œ @Rule ๊ฐ™์€ ์ž๋™ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ๊ฐ€ ์—†๊ฑฐ๋‚˜ ์ปค์Šคํ…€ ์ƒํ™ฉ์—์„œ ์“ฐ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋กœ ์ˆ˜์ •์„ ์ง„ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

After:

import org.apache.flink.test.junit5.InjectMiniCluster;

// ...

@Test
public void testBoundedWithTaskManagerFailover(@InjectMiniCluster MiniCluster miniCluster) throws Exception {
    testBoundedIcebergSource(FailoverType.TM, miniCluster);
}
  
@Test
public void testBoundedWithJobManagerFailover(@InjectMiniCluster MiniCluster miniCluster) throws Exception {
    testBoundedIcebergSource(FailoverType.JM, miniCluster);
}
  
// ...
  
@Test
public void testContinuousWithTaskManagerFailover(@InjectMiniCluster MiniCluster miniCluster) throws Exception {
    testContinuousIcebergSource(FailoverType.TM, miniCluster);
}

@Test
public void testContinuousWithJobManagerFailover(@InjectMiniCluster MiniCluster miniCluster) throws Exception {
    testContinuousIcebergSource(FailoverType.JM, miniCluster);
}

์ค‘์ ์€, ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ๋ฉด์—์„œ, MiniClusterWithClientResource ์ˆ˜๋™ ์ƒ์„ฑ ๋ฐ before()/after() ํ˜ธ์ถœ ํ•˜๋Š” ๋ถ€๋ถ„์„ @InjectMiniCluster๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ ์ฃผ์ž… ๋ฐ ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ๋” ๋ณ€๊ฒฝํ–ˆ๋‹ค๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ, ๋žŒ๋‹ค ๋ฐฉ์‹์œผ๋กœ ํ…Œ์ŠคํŠธ ์‹คํ–‰, ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ๋ฅผ ์ง์ ‘ ์ œ์–ดํ•˜๋Š” ๋ฐฉ์‹์—์„œ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฆฌ์†Œ์Šค ์ฃผ์ž… ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€๊ณ ,

ExternalResource ๊ธฐ๋ฐ˜ (JUnit4 Rule) ๋ฐฉ์‹์—์„œ ParameterResolver ๋˜๋Š” Extension ๊ธฐ๋ฐ˜ (JUnit5) ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค๋Š” ์ ์ด ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์— MainTainer ๋“ค์€ ํ† ๋ก ์„ ํ•˜์˜€๊ณ , ๊ดœ์ฐฎ์€ ๋ฐฉ์‹์ด๋ผ๋Š” ๊ฒฐ๋ก ์— ๋‹ค๋‹ค๋ฅด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ๋‹ค๋ฅธ ์ปจํŠธ๋ฆฌ๋ทฐํ„ฐ๋“ค ์—ญ์‹œ, ๊ดœ์ฐฎ๋‹ค๋Š” ๋ฆฌ๋ทฐ๋ฅผ ๋‹ฌ์•„์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

1


๐Ÿ”ง MiniCluster ์ฃผ์ž… ํ›„ ์‹คํ–‰ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๋ฐ ์ˆ˜๋™ ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ ์ฝ”๋“œ ์ถ”๊ฐ€

๊ทธ๋Ÿฌ๋‚˜, ์ด๋ถ€๋ถ„์— ๋Œ€ํ•˜์—ฌ ์ฒ˜์Œ์—๋Š” CI ํ…Œ์ŠคํŠธ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค.

1

1

1

ํ…Œ์ŠคํŠธ๊ฐ€ 120์ดˆ ์•ˆ์— ๋๋‚˜์ง€ ์•Š๊ณ  Timeout์œผ๋กœ ์‹คํŒจํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@InjectMiniCluster๋ฅผ ํ†ตํ•ด MiniCluster๋ฅผ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ์— ์ฃผ์ž…๋ฐ›์•˜์ง€๋งŒ ์ฃผ์ž…๋งŒ ๋œ ์ƒํƒœ์ด์ง€, ๋ช…์‹œ์ ์œผ๋กœ start()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด MiniCluster๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ํ…Œ์ŠคํŠธ ๋กœ์ง์—์„œ MiniCluster๋ฅผ ์‚ฌ์šฉํ•˜๋ ค ํ–ˆ์„ ๋•Œ, ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ โ€œ๋น„ํ™œ์„ฑ ์ƒํƒœโ€์ด๋ฏ€๋กœ, ์ž‘์—…์ด ์‹œ์ž‘๋˜์ง€ ์•Š๊ฑฐ๋‚˜, ์‹คํ–‰ ์ค‘ hang ์ด ๋ฐœ์ƒํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

์ข€ ๋” ์›์ธ์„ ์ฐพ์•„๋ณด๋‹ˆ. JUnit5์˜ ํ™•์žฅ ๋ชจ๋ธ์—์„œ๋Š” @Injectโ€ฆ ๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฐ์ฒด ์ฃผ์ž…์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ํ•ด๋‹น ๊ฐ์ฒด์˜ ์ƒ๋ช…์ฃผ๊ธฐ(start/stop)๋Š” ์ž๋™์œผ๋กœ ๋ณด์žฅ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ MiniCluster๋Š” ๋ช…์‹œ์ ์œผ๋กœ .start() ํ˜ธ์ถœ์ด ํ•„์š”ํ•˜๊ณ , ์ฃผ์ž…์€ ๋‹จ์ˆœํžˆ ์ƒ์„ฑ๋งŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋ฉฐ, ์‹คํ–‰์€ ๋ณ„๋„ ๋‹จ๊ณ„๋ผ๋Š” ์›์ธ์„ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ MiniCluster์— ์ž‘์—…์„ ์ œ์ถœํ•˜๋ ค ํ–ˆ์ง€๋งŒ, MiniCluster๊ฐ€ ์‹œ์ž‘๋˜์ง€ ์•Š์•˜๊ณ , ์ด๋Š” ํ…Œ์ŠคํŠธ timeout (120์ดˆ) ์ดˆ๊ณผ๋กœ ์‹คํŒจ๊นŒ์ง€ ์ด์–ด์ง€๊ฒŒ ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ TestIcebergSourceFailover ํด๋ž˜์Šค์— ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ ์ปค๋ฐ‹ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Add Code:

import org.junit.jupiter.api.AfterEach; // AfterEach ์ถ”๊ฐ€

@BeforeEach
protected void startMiniCluster(@InjectMiniCluster MiniCluster miniCluster) throws Exception {
    if (!miniCluster.isRunning()) {
      miniCluster.start();
    }
}

@AfterEach
protected void stopMiniCluster(@InjectMiniCluster MiniCluster miniCluster) throws Exception {
    miniCluster.close();
}

@BeforeEach์™€ @AfterEach๋ฅผ ํ†ตํ•ด MiniCluster์˜ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ œ์–ดํ•จ์œผ๋กœ์จ, ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ ํ•„์š”ํ•œ Flink ํด๋Ÿฌ์Šคํ„ฐ ํ™˜๊ฒฝ์ด ์ •์ƒ์ ์œผ๋กœ ์ดˆ๊ธฐํ™”๋˜๊ณ  ์ •๋ฆฌ๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ ๊ฒฐ๊ณผ, ์ตœ์ข…์ ์œผ๋กœ๋Š” Iceberg ์— PR Merge ๋ฅผ ์„ฑ๊ณตํ•˜์—ฌ, Apache ์žฌ๋‹จ์˜ Iceberg ํ”„๋กœ์ ํŠธ์— ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , Contributor ๊ฐ€ ๋  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ‘‰ My PR: Iceberg Flink Catalog v2.0 Remove the MiniClusterWithClientResource dependency



1

1


๐Ÿน Local Test ๋ฐ CI ํ†ต๊ณผ๋ฅผ ์œ„ํ•œ ์ ˆ์ฐจ ์•ˆ๋‚ด

์ฒ˜์Œ Iceberg ํ”„๋กœ์ ํŠธ์— ๊ธฐ์—ฌํ•˜๋ฉด์„œ ๊ฐ€์žฅ ํ—ท๊ฐˆ๋ ธ๋˜ ๋ถ€๋ถ„ ์ค‘ ํ•˜๋‚˜๊ฐ€, ๋กœ์ปฌ ํ…Œ์ŠคํŠธ์™€ CI ํ†ต๊ณผ ๋ฐฉ์‹์ด์—ˆ์Šต๋‹ˆ๋‹ค.

ํ˜น์‹œ ์ €์ฒ˜๋Ÿผ Iceberg์— ๊ธฐ์—ฌํ•˜๊ณ ์ž ํ•˜๋Š” ๋ถ„๋“ค์ด ๊ณ„์‹œ๋‹ค๋ฉด, ์•„๋ž˜ ์ ˆ์ฐจ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

โœ… ์ฝ”๋“œ ์Šคํƒ€์ผ ์ •๋ฆฌ: spotlessApply
Iceberg๋Š” Spotless๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ ํฌ๋งทํŒ…์„ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ PR์„ ์ƒ์„ฑํ•˜๊ธฐ ์ „ ๋ฐ˜๋“œ์‹œ ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ฝ”๋“œ ์Šคํƒ€์ผ์„ ์ž๋™์œผ๋กœ ์ •๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

./gradlew :iceberg-flink:iceberg-flink-2.0:spotlessApply

์ด ๋ช…๋ น์–ด๋Š” Java ์ฝ”๋“œ์˜ ์ •ํ•ด์ง„ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ์— ๋งž๊ฒŒ ๋“ค์—ฌ์“ฐ๊ธฐ, ์ •๋ ฌ, ๊ณต๋ฐฑ ๋“ฑ์„ ์ž๋™์œผ๋กœ ์ˆ˜์ •ํ•ด์ค๋‹ˆ๋‹ค. ์ด๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด CI์—์„œ spotlessCheck ๋‹จ๊ณ„์—์„œ ์‹คํŒจํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.



โœ… ๋กœ์ปฌ ํ…Œ์ŠคํŠธ ์ˆ˜ํ–‰: test โ€“stacktrace
CI์— ์˜ฌ๋ฆฌ๊ธฐ ์ „์—, ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ๋จผ์ € ์œ ๋‹› ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ด์ƒ์ด ์—†๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

./gradlew :iceberg-flink:iceberg-flink-2.0:test --stacktrace

โ€“stacktrace ์˜ต์…˜์€ ๋งŒ์•ฝ ํ…Œ์ŠคํŠธ ์‹คํŒจ ์‹œ ์ƒ์„ธํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.
ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•˜๋ฉด CI ๋‹จ๊ณ„์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ์‹คํŒจํ•˜๋ฏ€๋กœ, ๋กœ์ปฌ์—์„œ ๋ฐ˜๋“œ์‹œ ๋จผ์ € ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ, ์ €๋Š” flink 2.0 ์— ๋Œ€ํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์ด ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
./gradlew projects ๋ฅผ ํ†ตํ•˜์—ฌ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•œ ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก์„ ํ™•์ธํ•œ ํ›„์—, ์›ํ•˜๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์ง„ํ–‰ํ•ด์ฃผ๋ฉด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.


โ—ˆ


โœ๏ธ 3. ๊ฒฐ๋ก 


์ด๋ฒˆ ๊ธฐ์—ฌ๋ฅผ ํ†ตํ•ด ๊ธฐ์ˆ ์ ์ธ ์—ญ๋Ÿ‰๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ์—์„œ์˜ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์˜ ์ค‘์š”์„ฑ์„ ๊นŠ์ด ์ฒด๊ฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๋‹จ์ˆœํžˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์ œ์ถœํ•˜๋Š” ๊ฒƒ์„ ๋„˜์–ด, Maintainer ๋ฐ ๋‹ค๋ฅธ ๊ธฐ์—ฌ์ž๋“ค๊ณผ์˜ ์ง€์†์ ์ธ ์†Œํ†ต, ํ”ผ๋“œ๋ฐฑ ์ˆ˜์šฉ, ๊ทธ๋ฆฌ๊ณ  ํ˜‘์—… ๋ฐฉํ–ฅ ์กฐ์œจ์ด ์–ผ๋งˆ๋‚˜ ์ค‘์š”ํ•œ์ง€ ์ง์ ‘ ๊ฒฝํ—˜ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ ์ด์Šˆ๋ฅผ ๊ณต์œ ํ•˜๊ณ , ์ž‘์—… ๊ณ„ํš์„ ๋ช…ํ™•ํžˆ ์ „๋‹ฌํ•˜๋ฉฐ, ๋ฆฌ๋ทฐ์–ด์˜ ํ”ผ๋“œ๋ฐฑ์„ ๋น ๋ฅด๊ฒŒ ๋ฐ˜์˜ํ•˜๋Š” ๊ณผ์ •์„ ํ†ตํ•ด ์˜คํ”ˆ์†Œ์Šค ์ƒํƒœ๊ณ„์˜ ํ˜‘์—… ๋ฌธํ™”๊ฐ€ ์‹ ๋ขฐ์™€ ํšจ์œจ์„ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ตฌ์กฐ์ž„์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ PR์„ ํ†ตํ•ด ๊ธ์ •์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›์€ ๋’ค, Maintainer๋กœ๋ถ€ํ„ฐ ์š”์ฒญ๋ฐ›์•˜๋˜ Flink 1.20 ๋ฐ 1.19 ๋ฒ„์ „์— ๋Œ€ํ•œ backport ์ž‘์—… ์—ญ์‹œ ๋น ๋ฅด๊ฒŒ ์ง„ํ–‰ํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ๋™๊ธฐ๋ถ€์—ฌ๊ฐ€ ์ƒ๊ฒผ๊ณ , ๊ธฐ์ˆ ์  ๊ธฐ์—ฌ๋ฟ ์•„๋‹ˆ๋ผ ํ”„๋กœ์ ํŠธ ์š”๊ตฌ์— ์‹ ์†ํžˆ ๋Œ€์‘ํ•˜๋Š” ํƒœ๋„์˜ ์ค‘์š”์„ฑ๋„ ๋А๊ผˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ, ์˜คํ”ˆ์†Œ์Šค ๋ฉ˜ํ† ๋ง์—์„œ ์šด์˜์ง„ ์—ญํ• ์„ ๋งก์•„ ์ €์˜ ๊ธฐ์—ฌ๋ฅผ ํ•˜๋ฉด์„œ ๋™์‹œ์— ๋งŽ์€ ๋ฉ˜ํ‹ฐ๋“ค์ด ์˜คํ”ˆ์†Œ์Šค์— ๋„์ „ํ•˜๋Š” ๊ณผ์ •์„ ์ง€์ผœ๋ณด๊ณ , ๊ทธ๋ถ„๋“ค๊ป˜ ๋‹ต๊ธ€๋กœ ๋ฐฉํ–ฅ์„ฑ์„ ์ œ์‹œํ•˜๋Š” ๊ฒฝํ—˜์€ ์ € ์ž์‹ ์˜ ์„ฑ์žฅ์—๋„ ํฐ ์ž๊ทน์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
๋น„๋ก ์˜ค๋Š˜ ํฌ์ŠคํŒ…์—์„œ๋Š” ๋ฉ˜ํ† ๋ง ๋‚ด์šฉ์ด ์ž์„ธํžˆ ๋‹ค๋ค„์ง€์ง€ ์•Š์•˜์ง€๋งŒ, ์ €๋Š” ์•ž์œผ๋กœ๋„ ์ด ๋ฉ˜ํ† ๋ง ํ™œ๋™๊ณผ ์˜คํ”ˆ์†Œ์Šค ๊ธฐ์—ฌ๋ฅผ ๊พธ์ค€ํžˆ ์ด์–ด๊ฐˆ ๊ฒƒ์ด๋ฉฐ, ์šฐ๋ฆฌ๋‚˜๋ผ์— ์˜ฌ๋ฐ”๋ฅด๊ณ  ๊ฑด๊ฐ•ํ•œ ์˜คํ”ˆ์†Œ์Šค ๊ธฐ์—ฌ ๋ฌธํ™”๊ฐ€ ์ž๋ฆฌ์žก๋„๋ก ๋…ธ๋ ฅํ•˜๋Š” 1์„ธ๋Œ€๊ฐ€ ๋˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

์•ž์œผ๋กœ๋„ ๋‹จ์ˆœํ•œ ์ฝ”๋“œ ์ œ๊ณต์„ ๋„˜์–ด, ์‹ ๋ขฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ํ•˜๊ณ , ํ”„๋กœ์ ํŠธ์— ์‹ค์งˆ์ ์ธ ๊ฐ€์น˜๋ฅผ ๋”ํ•˜๋Š” ๊ธฐ์—ฌ์ž๊ฐ€ ๋˜๊ธฐ ์œ„ํ•ด ๊พธ์ค€ํžˆ ๋…ธ๋ ฅํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.