-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* chore: 임시로 ReentrantLogQueue에서 Primary 제거 * feat: MultiProcessor 추가 - 임시로 여러 큐를 가지는 MultiProcessor를 추가함 * chore: default queue개수 조정 * feat: flatterQueue 싱글 스레드풀 추가 및 queue count default를 3 설정 * chore: default queue사이즈 설정 * refactor: AsyncMultiProcessor 리팩토링 - 내부 로직 일원화 및 린팅을 적용했습니다. - MultiProcessor -> AsyncMultiProcessor 클래스 명 변경을 진행했습니다. * chore: 불필요한 메서드 구현 제거 - EventConsume<T> 구현을 제거했습니다. * chore: 의존성 정리, 사용하지 않는 Component 제거 --------- Co-authored-by: KyungMin Lee <[email protected]>
- Loading branch information
Showing
5 changed files
with
88 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
logbat/src/main/java/info/logbat/domain/log/repository/AsyncMultiProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package info.logbat.domain.log.repository; | ||
|
||
import com.zaxxer.hikari.HikariDataSource; | ||
import info.logbat.common.event.EventProducer; | ||
import info.logbat.domain.log.queue.ReentrantLogQueue; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.ThreadLocalRandom; | ||
import java.util.function.Consumer; | ||
import javax.sql.DataSource; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Primary; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Slf4j | ||
@Primary | ||
@Component | ||
public class AsyncMultiProcessor<E> implements EventProducer<E> { | ||
|
||
private final List<ReentrantLogQueue<E>> queues; | ||
private final List<ExecutorService> flatterExecutors; | ||
private Consumer<List<E>> saveFunction; | ||
private final int queueCount; | ||
|
||
public AsyncMultiProcessor(@Value("${queue.count:3}") int queueCount, | ||
@Value("${jdbc.async.timeout:5000}") Long timeout, | ||
@Value("${jdbc.async.bulk-size:3000}") Integer bulkSize, JdbcTemplate jdbcTemplate) { | ||
this.queueCount = queueCount; | ||
this.queues = new ArrayList<>(queueCount); | ||
this.flatterExecutors = new ArrayList<>(queueCount); | ||
int poolSize = getPoolSize(jdbcTemplate); | ||
setup(queueCount, timeout, bulkSize, poolSize); | ||
} | ||
|
||
public void init(Consumer<List<E>> saveFunction) { | ||
this.saveFunction = saveFunction; | ||
} | ||
|
||
@Override | ||
public void produce(List<E> data) { | ||
if (data.isEmpty()) { | ||
return; | ||
} | ||
int selectedQueue = ThreadLocalRandom.current().nextInt(queueCount); | ||
flatterExecutors.get(selectedQueue).execute(() -> queues.get(selectedQueue).produce(data)); | ||
} | ||
|
||
private void setup(int queueCount, Long timeout, Integer bulkSize, int poolSize) { | ||
ExecutorService followerExecutor = Executors.newFixedThreadPool(poolSize); | ||
ReentrantLogQueue<E> queue = new ReentrantLogQueue<>(timeout, bulkSize); | ||
|
||
for (int i = 0; i < queueCount; i++) { | ||
queues.add(queue); | ||
flatterExecutors.add(Executors.newSingleThreadExecutor()); | ||
} | ||
CompletableFuture.runAsync(() -> leaderTask(queue, followerExecutor)); | ||
} | ||
|
||
private void leaderTask(ReentrantLogQueue<E> queue, ExecutorService follower) { | ||
while (!Thread.currentThread().isInterrupted()) { | ||
List<E> element = queue.consume(); | ||
follower.execute(() -> saveFunction.accept(element)); | ||
} | ||
} | ||
|
||
private static int getPoolSize(JdbcTemplate jdbcTemplate) { | ||
DataSource dataSource = jdbcTemplate.getDataSource(); | ||
if (!(dataSource instanceof HikariDataSource)) { | ||
throw new IllegalArgumentException("DataSource is null"); | ||
} | ||
int poolSize = ((HikariDataSource) dataSource).getMaximumPoolSize(); | ||
log.debug("Creating AsyncLogProcessor with pool size: {}", poolSize); | ||
return poolSize * 5 / 10; | ||
} | ||
} |