Eventloop& Thread Model

7.1 Threading model overview

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

7.1.1 ์Šค๋ ˆ๋“œ ๋ชจ๋ธ ๊ฐœ์š”

์Šค๋ ˆ๋“œ ๋ชจ๋ธ์€ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋ฐฉ์‹์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋™์‹œ ์‹คํ–‰์˜ ๊ฐ€๋Šฅํ•œ ๋ถ€์ž‘์šฉ์„ ํ•ญ์ƒ ๊ฒฝ๊ณ„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ์ ์šฉ๋˜๋Š” ๋ชจ๋ธ์˜ ์˜ํ–ฅ์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค

๋‹ค์ค‘ ์ฝ”์–ด ๋˜๋Š” CPU๋ฅผ ๊ฐ€์ง„ ์ปดํ“จํ„ฐ๊ฐ€ ๋ณดํŽธํ™”๋จ์— ๋”ฐ๋ผ ๋Œ€๋ถ€๋ถ„์˜ ํ˜„๋Œ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์‹œ์Šคํ…œ ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ •๊ตํ•œ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์ธ ์Šค๋ ˆ๋“œ ํ’€๋ง ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์Šค๋ ˆ๋“œ ํ’€์˜ ์ž์œ  ๋ชฉ๋ก์—์„œ ์Šค๋ ˆ๋“œ๊ฐ€ ์„ ํƒ๋˜์–ด ์ œ์ถœ๋œ ์ž‘์—…(Runnable ๊ตฌํ˜„)์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์Šค๋ ˆ๋“œ๋Š” ๋ชฉ๋ก์œผ๋กœ ๋ฐ˜ํ™˜๋˜์–ด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

7.2 Interface EventLoop

์—ฐ๊ฒฐ์˜ ์ˆ˜๋ช… ๋™์•ˆ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋ชจ๋“  ๋„คํŠธ์›Œํ‚น ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

์ด์™€ ๊ด€๋ จ๋œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ตฌ์กฐ๋Š” ์ข…์ข… ์ด๋ฒคํŠธ ๋ฃจํ”„๋ผ๊ณ  ๋ถˆ๋ฆฌ๋ฉฐ, Netty๋Š” ์ด ์šฉ์–ด๋ฅผio.netty.channel.EventLoop ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ฑ„ํƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

while (!terminated) {
    List<Runnable> readyEvents = blockUntilEventsReady();
    for (Runnable ev: readyEvents) {
        ev.run();
    }
}

Netty์˜ EventLoop๋Š” ๋‘ ๊ฐ€์ง€ ๊ธฐ๋ณธ API(๋™์‹œ์„ฑ ๋ฐ ๋„คํŠธ์›Œํ‚น)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ˜‘๋ ฅ์  ์„ค๊ณ„์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค.

  • io.netty.util.concurrent ํŒจํ‚ค์ง€๋Š” JDK ํŒจํ‚ค์ง€ java.util.concurrent๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์Šค๋ ˆ๋“œ ์‹คํ–‰๊ธฐ๋ฅผ ์ œ๊ณต

  • io.netty.channel ํŒจํ‚ค์ง€์˜ ํด๋ž˜์Šค๋Š” Channel ์ด๋ฒคํŠธ์™€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ชจ๋ธ์—์„œ EventLoop๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ๊ตฌ๋™๋˜๋ฉฐ, ์ฆ‰์‹œ ๋˜๋Š” ์˜ˆ์•ฝ๋œ ์‹คํ–‰์„ ์œ„ํ•ด EventLoop ๊ตฌํ˜„์— ์ง์ ‘ ์ œ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…(Runnable ๋˜๋Š” Callable)์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ์„ฑ๊ณผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”์–ด์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ EventLoop๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋‹จ์ผ EventLoop๊ฐ€ ์—ฌ๋Ÿฌ Channel์„ ์„œ๋น„์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

public interface EventLoop extends EventExecutor, EventLoopGroup {
    @Override
    EventLoopGroup parent();
}

7.3 Task scheduling

๋•Œ๋•Œ๋กœ ์ž‘์—…์„ ๋‚˜์ค‘์—(์ง€์—ฐ๋œ) ๋˜๋Š” ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๋„๋ก ์˜ˆ์•ฝํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์›๊ฒฉ ํ”ผ์–ด์— ํ•˜ํŠธ๋น„ํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด ์—ฐ๊ฒฐ์ด ์—ฌ์ „ํžˆ ์‚ด์•„ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

7.3.1 JDK scheduling API

Methods
Description

newScheduledThreadPool(int corePoolSize)

๋ช…๋ น์„ ์ง€์—ฐ ํ›„ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ScheduledThreadExecutorService๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ธ์ˆ˜ corePoolSize๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šค๋ ˆ๋“œ ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.

newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)

๋ช…๋ น์„ ์ง€์—ฐ ํ›„ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ScheduledThreadExecutorService๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

newSingleThreadScheduledExecutor()

ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ์•ฝ๋œ ์ž‘์—…์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

newSingleThreadScheduledExecutor(ThreadFactory threadFactory)

ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ์•ฝ๋œ ์ž‘์—…์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

ScheduledExecutorService๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ 60์ดˆ ํ›„์— ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•

fun main(args: Array<String>) {
    val executor = Executors.newScheduledThreadPool(10)
    val future: ScheduledFuture<*> = executor.schedule(fun() = println("60 seconds later"), 60, TimeUnit.SECONDS)
    executor.shutdown()
}

ScheduledExecutorService API๋Š” ์ง๊ด€์ ์ด์ง€๋งŒ, ๋ถ€ํ•˜๊ฐ€ ๋†’์€ ์ƒํ™ฉ์—์„œ๋Š” ์„ฑ๋Šฅ ๋น„์šฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

7.3.2 Scheduling tasks using EventLoop

ScheduledExecutorService ๊ตฌํ˜„์€ ํ’€ ๊ด€๋ฆฌ์˜ ์ผ๋ถ€๋กœ ์ถ”๊ฐ€ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋“ฑ์˜ ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Netty๋Š” ์ฑ„๋„์˜ EventLoop๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

fun main(args: Array<String>) {
    val group = NioEventLoopGroup()
    val channel: Channel = NioSocketChannel()

    with(channel) {
        group.register(this)

        eventLoop().schedule(fun() = println("60 seconds later"), 60, TimeUnit.SECONDS)
        eventLoop().scheduleAtFixedRate(fun() = println("Run every 60 seconds"), 60, 60, TimeUnit.SECONDS)
    }
}

Netty์˜ EventLoop๋Š” ScheduledExecutorService๋ฅผ ํ™•์žฅํ•˜๋ฏ€๋กœ, JDK ๊ตฌํ˜„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ(schedule(), scheduleAtFixedRate() ๋“ฑ)๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋น„๋™๊ธฐ ์ž‘์—…๋งˆ๋‹ค ๋ฐ˜ํ™˜๋˜๋Š” ScheduledFuture๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ ์ƒํƒœ๋ฅผ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

7.4 Implementation details

7.4.1 Thread management

Netty์˜ ์Šค๋ ˆ๋”ฉ ๋ชจ๋ธ์˜ ๋›ฐ์–ด๋‚œ ์„ฑ๋Šฅ์€ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์Šค๋ ˆ๋“œ์˜ ์‹๋ณ„์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ๊ฐ€ ํ˜„์žฌ ์ฑ„๋„๊ณผ ๊ทธ EventLoop์— ํ• ๋‹น๋œ ์Šค๋ ˆ๋“œ์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ๊ฐ€ EventLoop์˜ ์Šค๋ ˆ๋“œ์ธ ๊ฒฝ์šฐ, ํ•ด๋‹น ์ฝ”๋“œ ๋ธ”๋ก์ด ์ง์ ‘ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. EventLoop๋Š” ๋‚˜์ค‘์— ์‹คํ–‰๋  ์ž‘์—…์„ ์˜ˆ์•ฝํ•˜๊ณ  ๋‚ด๋ถ€ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

๊ฐ EventLoop๋Š” ๋‹ค๋ฅธ EventLoop์™€ ๋…๋ฆฝ์ ์ธ ์ž์ฒด ์ž‘์—… ํ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.

7.4.2 EventLoop/thread allocation

์ฑ„๋„์„ ์œ„ํ•œ I/O ๋ฐ ์ด๋ฒคํŠธ๋ฅผ ์„œ๋น„์Šคํ•˜๋Š” EventLoop๋Š” EventLoopGroup์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. EventLoop๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ํ• ๋‹น๋˜๋Š” ๋ฐฉ์‹์€ ์ „์†ก ๊ตฌํ˜„์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

ASYNCHRONOUS TRANSPORTS

๋น„๋™๊ธฐ ๊ตฌํ˜„์€ ์†Œ์ˆ˜์˜ EventLoop(๋ฐ ๊ด€๋ จ ์Šค๋ ˆ๋“œ)๋งŒ ์‚ฌ์šฉํ•˜๋ฉฐ, ํ˜„์žฌ ๋ชจ๋ธ์—์„œ๋Š” ์ฑ„๋„ ๊ฐ„์— ๊ณต์œ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ ์ฑ„๋„์— ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๋Œ€์‹ , ๊ฐ€๋Šฅํ•œ ์ตœ์†Œํ•œ์˜ ์Šค๋ ˆ๋“œ ์ˆ˜๋กœ ๋งŽ์€ ์ฑ„๋„์„ ์„œ๋น„์Šคํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

EventLoopGroup์€ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๊ฐ ์ฑ„๋„์— EventLoop๋ฅผ ํ• ๋‹นํ•  ์ฑ…์ž„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Last updated

Was this helpful?