์ฃผํ‚คํผ ๋Œ€์‹  KRaft๋ฅผ ๋„์ž…ํ•˜๊ฒŒ ๋œ ์ด์œ ์— ๋Œ€ํ•ด์„œ.

9 minute read

ํšŒ์‚ฌ์—์„œ Confluent๋ฅผ ํ†ตํ•ด Kafka ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ž˜ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ, ์ด ์นดํ”„์นด์— ๋Œ€ํ•ด์„œ ์ข€๋” ์ž์„ธํžˆ ์•Œ๊ณ , ์ „๋ฌธ์„ฑ์„ ๊ฐ–์ถ”๊ณ  ์‹ถ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด์„œ 2025๋…„ ์ฒซ ๋ชฉํ‘œ๋กœ Confluent์˜ Kafka ์ž๊ฒฉ์ฆ์ธ Confluent Certified Developer for Apache Kafkaยฎ ์ž๊ฒฉ์ฆ์„ ์ค€๋น„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค โœŒ๏ธ

๋“ค์–ด๊ฐ€๋ฉฐ

CCDAK ์‹œํ—˜์„ ์ค€๋น„ํ•˜๋ฉด์„œ, Confluent์—์„œ ๋ฐœํ–‰ํ•œ ๊ฐ์ข… ๋ฌธ์„œ๋“ค์„ ์ฝ์–ด๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„ 

โ€œWhy ZooKeeper Was Replaced with KRaft โ€“ The Log of All Logsโ€

๋ผ๋Š” ์•„ํ‹ฐํด์„ ์ฝ์œผ๋ฉด์„œ, ๋ฉ”๋ชจํ•œ ๊ฒƒ๋“ค์„ ํฌ์ŠคํŠธ๋กœ ๊ธฐ๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ ์ด ํฌ์ŠคํŠธ๋Š” ๊ฐœ์ธ์ ์ธ ๋ฉ”๋ชจ์ด๋ฏ€๋กœ ์ธํ„ฐ๋„ท์—์„œ ๊ฒ€์ƒ‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Introduction

์™œ Zookeeper์—์„œ KRaft๋กœ ๋ฐ”๊พธ์—ˆ๋Š”๊ฐ€?

์™œ Raft ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ฑ„ํƒ ํ–ˆ๋Š”๊ฐ€?

2012๋…„, kafka controller์— ๊ธฐ๋Šฅ ์ถ”๊ฐ€? ์ด controller๋Š” topic partition log ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, cluster/broker metadata์™€ cluster-wide config, security credential ๋“ฑ์„ ๋ชจ๋‘ ์ €์žฅํ•˜๋„๋ก ๋””์ž์ธ ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค?

zookeeper๋Š” SOT๋กœ ์‚ฌ์šฉ ํ–ˆ์Œ.

๊ทธ๋Ÿฐ๋ฐ, non-controller broker๋„ zookeeper์— ์ ‘์†ํ•ด ISR ์ •๋ณด๋‚˜ ๋ฆฌ๋” ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์—ˆ์Œ. ๊ทธ๋Ÿผ controller๋Š” ZK์—์„œ ๊ทธ ์ •๋ณด๋ฅผ ๋ฐ›์•„์•ผ ํ–ˆ์Œ.

๊ทธ๋ž˜์„œ ์›๋ž˜๋Š” Controller๊ฐ€ ZK๋ฅผ SOT๋กœ ์‚ฌ์šฉํ•˜๋ฉด์„œ ํด๋Ÿฌ์Šคํ„ฐ ๊ด€๋ฆฌ๋ฅผ ํ•˜๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ, ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ZK์™€ ์†Œํ†ตํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ controller๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ํด๋Ÿฌ์Šคํ„ฐ ์ •๋ณด๋ฅผ ์—…๋Žƒํ•˜๋Š” ์ผ์ด ์ผ์–ด๋‚˜๊ฒŒ ๋จ.

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

์ด๋ ‡๊ฒŒ ZK ์ง์ ‘ ์ ‘๊ทผ์„ ๋ง‰๋Š” ์ด์œ ๋Š” ZK์— ๋Œ€ํ•œ R/W ๋ถ€ํ•˜๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด์„œ ์˜€์Œ.

Zookeeper watcher

Q. โ€œZooKeeper watcherโ€ ์ด๊ฒŒ ๋ญ์ง€? ์ด๊ฒŒ ๊ณง Controller ๋ธŒ๋กœ์ปค ์•„๋‹˜?

โ€œwatcherโ€๋Š” ZK ์‹œ์Šคํ…œ ๋‚ด์—์„œ์˜ ๊ฐœ๋…์ž„. ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” ZK์˜ โ€œevent notificationโ€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž„.

ZK watcher๋Š” Znode(๋ฐ์ดํ„ฐ ๋…ธ๋“œ)์— ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ZK ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ž…๋‹ˆ๋‹ค. ์นดํ”„์นด์—์„œ๋Š” ZK ํด๋ผ์ด์–ธํŠธ๋Š” โ€œ๋ธŒ๋กœ์ปคโ€ ์ž…๋‹ˆ๋‹ค.

Znode์— ๋ณ€ํ™”๋Š” (1) ๋ธŒ๋กœ์ปค๊ฐ€ ํด๋Ÿฌ์Šคํ„ฐ์— joinํ•˜๊ฑฐ๋‚˜ leave ํ•  ๋•Œ, (2) ํ† ํ”ฝ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ, (3) ์ปจํŠธ๋กค๋Ÿฌ ๋ธŒ๋กœ์ปค๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ๋Œ€๋ถ€๋ถ„ ์ปจํŠธ๋กค๋Ÿฌ ๋ธŒ๋กœ์ปค๊ฐ€ ๋งŒ๋“ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์นดํ”„์นด ๋ธŒ๋กœ์ปค๋Š” Znode์— ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€(watch)ํ•˜๊ณ , ๋ณ€ํ™”๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ ์ด๋ฒคํŠธ๋ฅผ ํ™•์ธํ•ด ๋Œ€์‘ ํ•ฉ๋‹ˆ๋‹ค.

Controller Scalability Limitaiton

๋˜, ํ˜„์žฌ๋Š” ํ•˜๋‚˜์˜ Controller ๋ธŒ๋กœ์ปค๊ฐ€ ZK์— ์ ‘์†ํ•˜๋„๋ก ํ•˜๋ฉด์„œ, ํด๋Ÿฌ์Šคํ„ฐ ๋Œ€๊ทœ๋ชจ๋กœ ํ™•์žฅ๋˜๋ฉด ํ•ด๋‹น Controller ๋ธŒ๋กœ์ปค๊ฐ€ ํฐ ๋ถ€ํ•˜๋ฅผ ๋ฐ›๊ฒŒ ๋จ.

Broker Shutdown

non-controller ๋ธŒ๋กœ์ปค ํ•˜๋‚˜๋ฅผ ๋‚ด๋ฆฌ๊ฒŒ ๋˜๋ฉด, ์ด ๋ธŒ๋กœ์ปค๋ฅผ ๋‚ด๋ฆฌ๊ธฐ ์œ„ํ•ด์„œ broker->controller->ZK ์ผ๋ จ์˜ ๊ณผ์ •์ด ์ผ์–ด๋‚˜์•ผ ํ•˜๊ณ , ๋ฐ˜๋Œ€๋กœ ZK->controller->(other) borkers๋กœ ์ „ํŒŒ๊ฐ€ ์ผ์–ด์•„๋ƒ ํ•จ. ๊ทธ๋Ÿฐ๋ฐ, ์ด ๊ณผ์ •์€ ๊ฝค ๊ธด ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๊ณ  ํด๋Ÿฌ์Šคํ„ฐ์˜ ์ฆ‰๊ฐ์ ์ธ ๋‹ค์šด์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค์—ˆ์Œ.

Controler Failover

์ปจํŠธ๋กค๋Ÿฌ ๋ธŒ๋กœ์ปค๋„ ์…ง๋‹ค์šด ๋  ์ˆ˜ ์žˆ์Œ.

์ด ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜๋ฉด, ๋‚˜๋จธ์ง€ ๋ชจ๋“  ๋ธŒ๋กœ์ปค๊ฐ€ ZK์— ํ•‘์„ ๋ณด๋‚ด๊ณ , ๊ทธ ์ค‘์—์„œ ๊ฐ€์žฅ ๋จผ์ € ์‘๋‹ต์„ ๋ฐ›๋Š” ๋…€์„์ด Controller ๋ธŒ๋กœ์ปค๋กœ ์ž„๋ช… ๋จ.

Controller๊ฐ€ ๋œ ๋ธŒ๋กœ์ปค๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ํ•˜๋Š” ์ผ์€ ZK์—์„œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ž„. ๋งŒ์•ฝ ๊ธฐ์กด ์ •๋ณด์™€ ๋ถˆ์ผ์น˜ ํ•˜๋Š” ์ •๋ณด๊ฐ€ ์žˆ๋‹ค๋ฉด, ๊ทธ๊ฑธ ํ•ธ๋“ค๋ง ํ•˜๊ณ (=์‹ ๊ทœ ๋ฉ”ํƒ€ ์ •๋ณด๋กœ overwrite), ์‹ ๊ทœ ์ •๋ณด๋ฅผ ํ•˜์œ„ ๋ธŒ๋กœ์ปค์— ์ „ํŒŒํ•จ.

์ด ๊ณผ์ •์—์„œ์˜ ๋ณ‘๋ชฉ์€ ์‹ ๊ทœ๋กœ ์ž„๋ช…๋œ controller๊ฐ€ ZK์—์„œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ fetching ํ•˜๋Š” ๊ฒƒ์ž„. ์ด ๊ณผ์ •์€ topic partition์ด ๋งŽ์„์ˆ˜๋ก ์˜ค๋ž˜๊ฑธ๋ฆผ. ์ด๋Ÿฐ bootstraping ๊ณผ์ • ๋™์•ˆ์€ ์ปจํŠธ๋กค๋Ÿฌ ๋ธŒ๋กœ์ปค๊ฐ€ ์–ด๋–ค ์š”์ฒญ๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํด๋Ÿฌ์Šคํ„ฐ์˜ ์ผ๋ถ€ ๊ธฐ๋Šฅ์ด ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ๋จ.

Why choose KRaft?

ZK์— ์ €์žฅํ•˜๋Š” ์ •๋ณด๊ฐ€ ๋ญ”์ง€ ์ž˜ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ, ๊ฒฐ๊ตญ์€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ฐ”๋€Œ๋Š”์ง€์— ๋Œ€ํ•œ transaction log ์˜€์Œ.

๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฐ log ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š”๋ฐ ๊ฐ€์žฅ ์ข‹์€ ๋…€์„์ด ๋ฐ”๋กœ ์นดํ”„์นด ์ž์‹ ์ž„!! ใ…‹ใ…‹

๊ทธ๋ž˜์„œ ์ด metadata log๋ฅผ ์ €์žฅํ•˜๋Š” ๋‚ด๋ถ€ ํ† ํ”ฝ์„ ๋‘๊ณ , controller๊ฐ€ ์ด ์ •๋ณด๋ฅผ โ€œ์ง์ ‘โ€ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•˜๋Š”๊ฒŒ ์–ด๋–จ๊นŒ ํ•˜๋Š” ์ƒ๊ฐ์œผ๋กœ ์ด์–ด์ง.

๊ทธ๋ž˜์„œ ๋ช‡๊ฐœ์˜ ๋ธŒ๋กœ์ปค๋ฅผ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ์–ด์„œ ์ด metadata log๋ฅผ ๊ด€๋ฆฌํ•˜๋„๋ก ์—ญํ• ์„ ๋ถ€์—ฌํ•จ. ๊ทธ๋ฆฌ๊ณ  ์ด ๊ทธ๋ฃน์€ quorum์„ ์ด๋ฃธ. (์ด์ „์—๋Š” ํ•˜๋‚˜์˜ ์ปจํŠธ๋กค๋Ÿฌ ์˜€๋Š”๋ฐ, ์ด์   quorum์œผ๋กœ ์šด์˜!)

โ€œPrimary-backupโ€ replication algorithm

  • single leader replica takes all of the incoming writes
  • and tries to replicate them to other replicas as its followers.
  • after the followers have acks, the leader considers it committed and returns to writing ot its client. ^the metadata log also takes this procedure also!

โ€œQuorumโ€ replication algorithm

  • still a single leader trying to take writes, and replicating to followers.
  • But, instead of waiting for all followers to ack
  • it only waits for the majority of replicas, including itself. ^ ์ผ์ข…์˜ ๋ถ„์‚ฐ ํ™˜๊ฒฝ์—์„œ ์ •๋ณด ์ €์žฅ์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” consuensus algorithm ์ž„.

primary-backup๊ณผ ๋น„๊ตํ•ด์„œ quorum ๋ฐฉ์‹์€ ์ข€๋” ๋น ๋ฅธ availability guaratee๋ฅผ ์ œ๊ณตํ•จ.

Kraft

Kafka Raft Implementation

์ƒˆ๋กœ์šด ์ปจํŠธ๋กค๋Ÿฌ ๊ทธ๋ฃน์€ metadata log์— ๋Œ€ํ•ด์„œ ์ด quorum replication ๋ฐฉ์‹์„ ์ฑ„ํƒ ํ•จ.

๊ทธ๋Ÿฐ๋ฐ, ์ด๊ฒƒ์€ metadata log์— ๋Œ€ํ•ด์„œ ZK์˜ ์—ญํ• ์„ ๊ฐ€์ ธ์˜จ ๊ฒƒ์ž„. ๊ธฐ์กด์— ZK์—์„œ ๋‹ด๋‹นํ•˜๋˜ ๋ฆฌ๋” ์ปจํŠธ๋กค๋Ÿฌ ์„ ์ถœ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•ด์„œ์„œ๋„ ์ด๊ด€์ด ํ•„์š”ํ•จ. ์ด ์„ ์ถœ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ZK์— ๋ณด์žฅํ•˜๋˜, ๋™์‹œ์— ์—ฌ๋Ÿฌ ๋ฆฌ๋”๊ฐ€ ์กด์žฌํ•˜๋Š” ์ƒํ™ฉ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ.

โ€œgridlock scenarioโ€ = ๊ต์ฐฉ์ƒํƒœ

  • ๋ธŒ๋กœ์ปค๊ฐ€ ํŠน์ • ์กฐ๊ฑด์—์„œ ์„œ๋กœ ๋Œ€๊ธฐํ•˜๊ฑฐ๋‚˜ ์ถฉ๋Œํ•˜์—ฌ ์•„๋ฌด๊ฒƒ๋„ ์ง„ํ–‰ํ•˜์ง€ ๋ชปํ•˜๋Š” ์ƒํƒœ์ž„.

deadlock๊ณผ ๋น„์Šทํ•œ ๊ฐœ๋…์ด๊ธด ํ•œ๋ฐ, gridlock์€ ๋ถ„์‚ฐ ์‹œ์Šคํ…œ์˜ ๊ฐ€์šฉ ์ƒํƒœ์— ๋Œ€ํ•ด ๋งํ•  ๋•Œ ์“ฐ๋Š” ๋“ฏ?

Leader Election

๋ธŒ๋กœ์ปค๋Š” 3๊ฐ€์ง€ ์—ญํ• ๋กœ ๋‚˜๋‰จ.

  • voter
    • ์ปจํŠธ๋กค๋Ÿฌ ๊ทธ๋ฃน์— ์†ํ•˜๋Š” ๋ธŒ๋กœ์ปค
  • leader candidate
    • ๋žœ๋คํ•˜๊ฒŒ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด voter ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฆฌ๋” ํ›„๋ณด๊ฐ€ ๋จ.
  • observer
    • ์ปจํŠธ๋กค๋Ÿฌ ๊ทธ๋ฃน์— ์†ํ•˜์ง€ ์•Š๋Š” ์ผ๋ฐ˜ ๋ธŒ๋กœ์ปค

๋งŒ์•ฝ ์–ด๋–ค ํ›„๋ณด๋„ ๋‹ค์ˆ˜๊ฒฐ์„ ์–ป์ง€ ๋ชปํ–ˆ๋‹ค๋ฉด, ํˆฌํ‘œ๋ฅผ ๋ฌดํšจ๋กœ ํ•˜๊ณ  epoch์„ ๋Š˜๋ฆฐ ํ›„, ๋‹ค์‹œ ์„ ๊ฑฐ๋ฅผ ์ง„ํ–‰ํ•จ.

Log Replication

๊ธฐ์กด Raft ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ push-based๋กœ log replication์„ ์ˆ˜ํ–‰ํ•จ. KRaft ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ZK ๋•Œ์ฒ˜๋Ÿผ pull-based๋กœ log replication์„ ์ˆ˜ํ–‰ํ•จ.

we can see that this fetch request is also leveraged as a heartbeat to determine the liveness of the leader.

Other voters within the quorum actively replicate the metadata log so that newly appended records get committed.

Quorum Controller

The quorum controller receives the linveness of all registered brokers with heartbeats.

When an existing broker is shutting down, it can piggyback its intention within a heartbeat and the controller can remove it from all of its partitions.

Quorum controlller batch all of the partition movement events when appending them to the metadata log.

๋งบ์Œ๋ง

KRaft ๋ชจ๋“œ์— ๋Œ€ํ•œ ์—ญ์‚ฌ์™€ ๋™์ž‘ ๋ฐฉ์‹ ๊ทธ๋ฆฌ๊ณ  ์‹คํ—˜ ๊ฒฐ๊ณผ๊นŒ์ง€ ์•„์ฃผ ์•Œ์ฐฌ ํฌ์ŠคํŠธ ์˜€์Šต๋‹ˆ๋‹ค! ์ฃผ๋ง์— ์—ฌ์œ ๋กญ๊ฒŒ ์นดํŽ˜์—์„œ ์ฝ๋Š”๋ฐ ์ˆ ์ˆ  ์ฝํžˆ๋”๋ผ๊ตฌ์š” ใ…Žใ…Ž

Raft๊ฐ€ push-based ์˜€๋‹ค๋ฉด, KRaft๋Š” pull-based๋กœ ๋™์ž‘ํ•œ๋‹ค๋Š” ๊ฒƒ๋„ ์ด ํฌ์ŠคํŠธ๋ฅผ ์ฝ์œผ๋ฉด์„œ ์ฒ˜์Œ ์•Œ์•˜๋„ค์š” ^^

์•„ํ‹ฐํด์— ์žˆ๋˜ ํ‘œํ˜„ ์ค‘์— โ€œnot reinventing the wheelโ€๊ฐ€ ์ธ์ƒ์  ์ž…๋‹ˆ๋‹ค. ์นดํ”„์นด ๊ฐœ๋ฐœ์ž๋“ค์ด ๊ธฐ์กด ์ฝ”๋“œ์™€ ์‹œ์Šคํ…œ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋Š” ๋ฐฉํ–ฅ์„ ์„ ํƒํ–ˆ๋‹ค๋Š” ๊ฒƒ์ด ์ฐธ ๋˜‘๋˜‘ํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

โ€œnot reinventing the wheelโ€ ์ •์ฑ…์€ ๋Œ€๊ทœ๋ชจ ์˜คํ”ˆ์†Œ์Šค๋ฅผ ์šด์˜ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ์— ์ข‹์€ ๊ธธ์žก์ด๊ฐ€ ๋˜์–ด์ค„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์–ด๋–ค ์ˆœ๊ฐ„์—๋Š” ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๋„๊ตฌ๋ฅผ ๊ฐœ๋ฐœํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ, ๊ทธ๊ฒƒ์ด ๋ฐ”ํ€ด(wheel)๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๊ฒƒ(์˜ˆ๋ฅผ ๋“ค๋ฉด, ๋ฐ”ํ€ด๋ฅผ ํ™œ์šฉํ•˜๋Š” ์ž์ „๊ฑฐ๋ผ๋Š” ์‹œ์Šคํ…œ?)์ธ์ง€ ๋น ๋ฅด๊ฒŒ ํŒ๋‹จํ•˜๊ณ  ๊ฐœ๋ฐœ ๋ฐฉํ–ฅ์„ ์ •ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Categories:

Updated: