μ΄ νλ‘μ νΈλ λ§μ€ν°-μ¬λ μ΄λΈ λ°μ΄ν°λ² μ΄μ€ μν€ν μ²μ Spring Batchλ₯Ό νμ©ν λμ©λ λ°°μΉ μ²λ¦¬λ₯Ό νμ΅νκΈ° μν μ€μ κ²½λ§€ μμ€ν μ λλ€.
μ½κΈ° μμ μ΄ λ§μ κ²½λ§€ μμ€ν μ νΉμ±μ νμ©νμ¬ μ½κΈ°/μ°κΈ° λΆλ¦¬(Read-Write Splitting)λ₯Ό ꡬννκ³ , κ²½λ§€ μ’ λ£ μ²λ¦¬μ κ°μ λλ μ λ°μ΄νΈ μμ μ Spring Batchλ‘ μμ μ μΌλ‘ μ²λ¦¬ν©λλ€.
- Spring Bootμμ λ§μ€ν°-μ¬λ μ΄λΈ λ°μ΄ν°λ² μ΄μ€ ꡬμ±
@Transactional(readOnly = true/false)λ₯Ό ν΅ν μλ λΌμ°ν- MySQL Replication μ€μ λ° κ΄λ¦¬
- μ½κΈ°/μ°κΈ° λΆλ¦¬λ₯Ό ν΅ν μ±λ₯ μ΅μ ν
- 볡μ μ§μ°(Replication Lag) μ΄ν΄ λ° λμ
- λμ©λ λ°μ΄ν° λ°°μΉ μ²λ¦¬ (κ²½λ§€ μ’ λ£ μλν)
- Chunk μ§ν₯ μ²λ¦¬ (Reader-Processor-Writer ν¨ν΄)
- JdbcPagingItemReaderλ₯Ό μ¬μ©ν νμ΄μ§ μ½κΈ°
- Late Bindingμ ν΅ν λμ νλΌλ―Έν° μ λ¬
- Spring Schedulerμ Batch μ°λ
- Framework: Spring Boot 3.5.6
- Language: Java 21
- Database: MySQL 8.0 (Master-Slave Replication)
- ORM: Spring Data JPA
- Batch: Spring Batch
- Scheduler: Spring Scheduler (@Scheduled)
- Connection Pool: HikariCP
- Build Tool: Gradle
- Containerization: Docker, Docker Compose
βββββββββββββββββββββββ
β Spring Boot App β
β (Port: 8081) β
ββββββββββββ¬βββββββββββ
β
ββββ @Transactional (μ°κΈ°) βββ Master DB (Port: 3306)
β β
β Replication (GTID)
β β
ββββ @Transactional(readOnly=true) βββ Slave DB (Port: 3307)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Spring Scheduler (λ§€ λΆ μ€ν) β
βββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Spring Batch Job (auctionEndJob) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Step: auctionEndStep (Chunk Size: 1000) β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Reader: JdbcPagingItemReader β β
β β - μ’
λ£ μκ°μ΄ μ§λ ACTIVE κ²½λ§€ μ‘°ν β β
β β - SQL κΈ°λ°μΌλ‘ νμν λ°μ΄ν°λ§ μ‘°ν β β
β β - Late BindingμΌλ‘ νμ¬ μκ° μ£Όμ
β β
β ββββββββββββββ¬ββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Writer: JdbcBatchItemWriter β β
β β - Chunk λ¨μλ‘ ENDED μνλ‘ μΌκ΄ μ
λ°μ΄νΈ β β
β β - JDBC λ°°μΉ μ
λ°μ΄νΈλ‘ μ±λ₯ μ΅μ ν β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
βΌ
Master DB (Port: 3306)
User (μ¬μ©μ)
β (1:N)
Auction (κ²½λ§€) βββ (1:N) βββ Bid (μ
μ°°)
β (seller_id) β (bidder_id)
User (νλ§€μ) User (μ
μ°°μ)
POST /api/users- μ¬μ©μ λ±λ‘ (μ°κΈ°)GET /api/users/{id}- μ¬μ©μ μ‘°ν (μ½κΈ°)GET /api/users/email/{email}- μ΄λ©μΌλ‘ μ¬μ©μ μ‘°ν (μ½κΈ°)
POST /api/auctions- κ²½λ§€ λ±λ‘ (μ°κΈ°)GET /api/auctions- κ²½λ§€ λͺ©λ‘ μ‘°ν (μ½κΈ°)GET /api/auctions/{id}- κ²½λ§€ μμΈ μ‘°ν (μ½κΈ°)GET /api/auctions/seller/{sellerId}- νλ§€μλ³ κ²½λ§€ (μ½κΈ°)PATCH /api/auctions/{id}/end- κ²½λ§€ μ’ λ£ (μ°κΈ°)POST /api/auctions/update-statuses- κ²½λ§€ μν μλ μ λ°μ΄νΈ (μ°κΈ°)
POST /api/bids- μ μ°°νκΈ° (μ°κΈ°)GET /api/bids/auctions/{auctionId}- κ²½λ§€λ³ μ μ°° λ΄μ (μ½κΈ°)GET /api/bids/auctions/{auctionId}/recent- μ΅κ·Ό μ μ°° 10κ° (μ½κΈ°)GET /api/bids/users/{userId}- μ¬μ©μλ³ μ μ°° λ΄μ (μ½κΈ°)GET /api/bids/auctions/{auctionId}/winning- νμ¬ μ΅κ³ κ° μ μ°° (μ½κΈ°)GET /api/bids/auctions/{auctionId}/statistics- μ μ°° ν΅κ³ (μ½κΈ°)
- μ€ν μ£ΌκΈ°: λ§€ λΆ (Cron: 0 * * * * *)
- μ²λ¦¬ λμ: μ’ λ£ μκ°μ΄ μ§λ¬μ§λ§ μνκ° ACTIVEμΈ κ²½λ§€
- Chunk Size: 1000건
- Reader: JdbcPagingItemReader
- SQL κΈ°λ°μΌλ‘ νμν λ°μ΄ν°λ§ μ‘°ννμ¬ λ©λͺ¨λ¦¬ μ΅μ ν
- Late BindingμΌλ‘ μ€μΌμ€λ¬ μ€ν μμ μ μκ°μ λμ μΌλ‘ μ£Όμ
- JDBC νμ΄μ§μΌλ‘ ν¨μ¨μ μΈ λ°μ΄ν° μ‘°ν
- Writer: JdbcBatchItemWriter
- JDBC λ°°μΉ μ λ°μ΄νΈλ‘ μ±λ₯ μ΅μ ν
- Chunk λ¨μλ‘ μ»€λ°νμ¬ νΈλμμ λΆμ°