CQRS(Command and Query Responsibility Segregation) Pattern
์ ๋ฑ์ฅํ๊ฒ ๋์์๊น์?
- ์กฐํ ํ๋ฉด ํน์ฑ์ ์กฐํ ์๋๊ฐ ๋น ๋ฅผ ์๋ก ์ข์๋ฐ ์ฌ๋ฌ Aggregate์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ๊ฐ์ ธ์ฌ๊น?๋ผ๋ ๊ณ ๋ฏผ์ ํ๊ฒ ๋ฉ๋๋ค.
- Aggregate๊ฐ์ ๊ด๊ณ๋ฅผ ID ์ฌ์ฉํด์ ์ด์ฉํ๋ค๋ฉด ์ฆ์ ๋ก๋ฉ(eager Loading) ๋ฐฉ์๊ณผ ๊ฐ์ JPA์ ์ฟผ๋ฆฌ ๊ด๋ จ ์ต์ ํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- Aggregate๊ฐ์ ๊ด๊ณ๋ฅผ ์ฐธ์กฐ ๋ฐฉ์์ผ๋ก ํ๋คํด๋ ๊ฒฝ์ฐ์ ๋ฐ๋ผ ์ง์ฐ ๋ก๋ฉ(lazy Loading) ๋ฐฉ์์ ์ฌ์ฉํ๊ธฐ ์ํด์ Native Query๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
๋๋ฉ์ธ์ ๊ตฌ์กฐ
- ์ํ๋ฅผ ๋ณ๊ฒฝํ ๋์ ์กฐํํ ๋ ๋จ์ผ ๋๋ฉ์ธ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ORM(Object-relational mapping)์ ๋๋ฉ์ธ์ ์ํ ๋ณ๊ฒฝ์ ๊ตฌํํ๋ ๋ฐ ์ ํฉํ์ง๋ง,
- ์ฌ๋ฌ Aggregate์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ์ถ๋ ฅํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค๋ณด๋ฉด ๋๋ฉ์ธ ๋ณต์ก๋๊ฐ ์ ์ ๋์์ง๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
CQRS๋ ๋จ์ผ ๋ชจ๋ธ์ ์ฌ์ฉํ ๋ ๋ฐ์ํ๋ ๋ณต์ก๋๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
CQRS๋?
-
์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ๊ธฐ๋ฅ๊ณผ ์ํ ์ ๋ณด๋ฅผ ์กฐํํ๋ ๊ธฐ๋ฅ์ ๋ถ๋ฆฌํ์ฌ ๋๋ฉ์ธ์ ๊ตฌ์ฑํ๋ ๊ฒ์ ๋๋ค.
-
๋๋ฉ์ธ ๋ชจ๋ธ ๊ด์ ์์ ์ํ ๋ณ๊ฒฝ ๊ธฐ๋ฅ์ ์ฃผ๋ก ํ Aggregate์ ์ํ๋ฅผ ๋ณ๊ฒฝํฉ๋๋ค.
- ์ฃผ๋ฌธ ์ทจ์ ๊ธฐ๋ฅ๊ณผ ๋ฐฐ์ก์ง ์ ๋ณด ๋ณ๊ฒฝ ๊ธฐ๋ฅ์ ํ ๊ฐ์ Order Aggregate์์ ์งํํฉ๋๋ค.
-
์กฐํ ๊ธฐ๋ฅ์ ํ๋์ Aggregate๋ ์กฐํํ ์ ์์ง๋ง, ๋ ๊ฐ ์ด์์ Aggregate์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ์ ์์ต๋๋ค.
- ๋จ์ผ ๋ชจ๋ธ๋ก ๋ ์ข ๋ฅ์ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ฉด ๋ชจ๋ธ์ด ๋ถํ์ํ๊ฒ ๋ณต์กํด์ง๋๋ค.
๋ค์ํ ๊ตฌ์กฐ
๋จ์ผ Database ๊ตฌ์กฐ
- Database๋ฅผ ๊ณต์ ํ๊ณ Model์ Command์ Query Model๋ก ๋ถ๋ฆฌํ์ฌ ์ ์ฉํ์์ต๋๋ค.
- ์ฝ๊ณ ๋จ์ํ๊ฒ ์ ์ฉํ ์ ์์ง๋ง, ๊ฐ์ Database๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ๋ํ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๊ธฐ ํ๋ ๊ตฌ์กฐ์ ๋๋ค.
Ployglot ๊ตฌ์กฐ
- Command Database์ Query Database๋ฅผ ๋ถ๋ฆฌํ๊ณ Message Broker(RabbitMQ, Kafka)๋ฅผ ํตํด Data ๋๊ธฐํ๋ฅผ ์ฒ๋ฆฌ ํ๋ ๋ฐฉ์์ ๋๋ค.
- ๊ฐ๊ฐ์ Model์ ์ ํฉํ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ ์ฅ์ ์ด ์์ต๋๋ค. : Ployglot ๊ตฌ์กฐ(RDBMS, NoSql, Cache)
- ๋๊ธฐํ ์ฒ๋ฆฌ๋ฅผ ์ํ Message Broker์ HA์ Message ์ ๋ฌ์ ์ ๋ขฐ๋์ ๋ํด ๋ณด์ฅ๋์ด์ผ ํ๋ ๋จ์ ์ด ์์ต๋๋ค.
Event Sourcing ๊ตฌ์กฐ
- Event Sourcing : Application๋ด์ ๋ชจ๋ Action์ ์ด๋ฒคํธ๋ก ์ ํํด์ ์ด๋ฒคํธ ์คํธ๋ฆผ(Event Stream)์ ๋ณ๋์ Database์ ์ ์ฅํ๋ ๋ฐฉ์์ ๋งํฉ๋๋ค.
Example Event Store
id | root_id | event |
---|---|---|
1 | 1 | ์นดํธ ์์ฑํจ |
2 | 1 | ์ํ1 ์ถ๊ฐํจ |
3 | 1 | ์ํ2 ์ถ๊ฐํจ |
4 | 1 | ์ํ2 ์ ๊ฑฐํจ |
5 | 1 | ๋ฐฐ์ก์ ๋ณด ์ ๋ ฅํจ |
- ์คํ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ์ฐ์ ์ฝ์ (insert) ๋ฟ์ ๋๋ค.
- ์๋์ด ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋, ์ญ์ ๋๋ ๋ถ๋ถ๋ ์ด๋ฒคํธ์ด๊ธฐ ๋๋ฌธ์ ๊ฐฑ์ (update)์ด๋ ์ญ์ (delete) ์ฐ์ฐ์ ์ํ๋์ง ์์ต๋๋ค.
- ๊ฐ์ฒด ๊ด๊ณํ ์ํผ๋์ค ๋ถ์ผ์น
์ฅ์ .
- ํธ๋์ญ์ ์ฒ๋ฆฌ ์ค ๊ฒฝํฉ์ด ์์ต๋๋ค.
- ๋ชจ๋ ๋ณ๊ฒฝ ๋ด์ญ์ด ์ด๋ฒคํธ๋ก ๊ธฐ๋ก๋๊ธฐ ๋๋ฌธ์ ์ํ๋ ์์ ์ผ๋ก Rollback์ด ๊ฐ๋ฅํ๊ฒ ๋ฉ๋๋ค.
- ๋ฉ์์ง ์ค์ฌ(Message-Driven) ์ํคํ ์ฒ์ ์ ํฉํฉ๋๋ค.
- Event Monitoring์ด ํ์ํ ๊ฒฝ์ฐ์ ์ ํฉํฉ๋๋ค.
๋จ์ .
- ์ํ ๋ถ์ผ์น๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ์ ๋ฐ์ดํธ ์ถฉ๋ ๋ฐ์์ด ๋งค์ฐ ์ ์ ์์คํ ์๋ ์ ํฉํ์ง ์์ต๋๋ค.
- ๋ฐ์ดํฐ ๋ทฐ ์ผ๊ด์ฑ ๋ฐ ์ค์๊ฐ ์ ๋ฐ์ดํธ๊ฐ ํ์ํ ์์คํ ์๋ ์ ํฉํ์ง ์์ต๋๋ค.
์ ๋ฆฌํ๋ฉฐ
CQRS ์ฅ์
- ๊ฐ๊ฐ์ ๋๋ฉ์ธ ๋ชฉ์ ์ ๋ง๊ฒ ์ง์คํ์ฌ ๊ฐ๋ฐํ ์ ์์ต๋๋ค.
- ๋ช ๋ น๊ณผ ์ฟผ๋ฆฌ ํ์ดํ๋ผ์ธ์ ์ํ๋๋๋ก ์ต์ ํํ๋ฉด์ ๋ค๋ฅธ ์์๊ฐ ๊นจ์ง ์ํ์ ๊ฑฐ์ ์๋ค๋ ๊ฒ
CQRS ๋จ์
- ๊ตฌํํด์ผ ํ ์ฝ๋๊ฐ ๋ ๋ง๋ค๋ ๊ฒ.
- ๋ ๋ง์ ๊ตฌํ ๊ธฐ์ ์ด ํ์ํ๋ค๋ ๊ฒ.
- ์ ์ง ๋น์ฉ ์ฆ๊ฐ.
์ฌ์ฉํ์ง ์์์ผ ํ ๊ฒฝ์ฐ
- ๋๋ฉ์ธ ๋๋ ๋น์ฆ๋์ค ๊ท์น์ด ๊ฐ๋จํ ๊ฒฝ์ฐ.
- ๋๊ท๋ชจ์ ๊ณ ์ฐจ์์ ์ธ ์ดํ๋ฆฌ์ผ์ด์ ์ด ์๋ ๊ฒฝ์ฐ.
Reference
- https://docs.microsoft.com/ko-kr/azure/architecture/patterns/cqrs
- https://www.popit.kr/cqrs-eventsourcing/
- https://msdn.microsoft.com/magazine/mt147237
- https://www.future-processing.pl/blog/cqrs-simple-architecture/
- https://docs.microsoft.com/ko-kr/azure/architecture/patterns/event-sourcing
- https://www.haruair.com/blog/4008