Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

week5(상준): 동기 비동기 성능 테스트 메트릭 분석 #43

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ dependencies {
// prometheus micrometer
implementation 'io.micrometer:micrometer-registry-prometheus'

// //influxDB micrometer
// implementation 'io.micrometer:micrometer-registry-influx'

// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import http from 'k6/http';
import { check, sleep } from 'k6';

//100명의 사용자의 1분동안 동시 요청 수행
export const options = {
vus: 100,
duration: '1m'
};

const users = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
}));

export default function () {
const user = users[__VU - 1];

//async의 경우
const res = http.get(`http://localhost:8080/api/orders/async/${user.id}`);

check(res, {
'status was 200': (r) => r.status === 200
});

sleep(1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import http from 'k6/http';
import { check, sleep } from 'k6';

//100명의 사용자의 1분동안 동시 요청 수행
export const options = {
vus: 100,
duration: '1m'
};

const users = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
}));

export default function () {
const user = users[__VU - 1];

//sync의 경우
const res = http.get(`http://localhost:8080/api/orders/sync/${user.id}`);

check(res, {
'status was 200': (r) => r.status === 200
});

sleep(1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
DELIMITER $$
DROP PROCEDURE IF EXISTS insertLoop$$

CREATE PROCEDURE insertLoop()
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE j INT DEFAULT 1;
DECLARE pk INT DEFAULT 1;
WHILE i <= 10000 DO
WHILE j <=3 DO
INSERT INTO ORDER_PRODUCTS (order_product_id, order_id, product_id, count, created_at, updated_at)
VALUES (pk, i, j, 1, NOW(), NOW());
SET pk = pk+1;
SET j = j+1;
END WHILE;
SET j = 1;
SET i = i + 1;
END WHILE;
END$$
DELIMITER $$

CALL insertLoop;
$$
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.order.perf.application;

import com.order.perf.common.async.AsyncRepositoryService;
import com.order.perf.domain.*;
import com.order.perf.domain.repository.*;
import com.order.perf.application.dto.OrderDetailsResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -18,13 +18,16 @@
@Service
public class OrderService {

private final AsyncRepositoryService asyncRepositoryService;
private final OrderRepository orderRepository;
private final DeliveryRepository deliveryRepository;
private final RefundRepository refundRepository;

public OrderService(final OrderRepository orderRepository,
public OrderService(final AsyncRepositoryService asyncRepositoryService,
final OrderRepository orderRepository,
final DeliveryRepository deliveryRepository,
final RefundRepository refundRepository) {
this.asyncRepositoryService = asyncRepositoryService;
this.orderRepository = orderRepository;
this.deliveryRepository = deliveryRepository;
this.refundRepository = refundRepository;
Expand All @@ -34,24 +37,21 @@ public OrderDetailsResponse findOrderDetailsByAsync(final Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("Order not found"));

CompletableFuture<Delivery> deliveryCompletableFuture = CompletableFuture.supplyAsync(() -> deliveryRepository.findById(order.getDeliveryId())
.orElseThrow(() -> new RuntimeException("Delivery not found")));
CompletableFuture<Delivery> deliveryFuture = asyncRepositoryService.findDeliveryByIdAsync(order.getDeliveryId());
CompletableFuture<Refund> refundFuture = asyncRepositoryService.findRefundByIdAsync(order.getRefundId());
CompletableFuture<List<OrderProduct>> orderProductsFuture = asyncRepositoryService.findOrderProductsAsync(order);

CompletableFuture<Refund> refundCompletableFuture = CompletableFuture.supplyAsync(() -> refundRepository.findById(order.getRefundId())
.orElseThrow(() -> new RuntimeException("Refund not found")));
// 모든 작업 완료 대기
CompletableFuture.allOf(deliveryFuture, refundFuture, orderProductsFuture).join();

CompletableFuture<List<OrderProduct>> orderProductsCompletableFuture
= CompletableFuture.supplyAsync(() -> order.getOrderProducts());

CompletableFuture.allOf(orderProductsCompletableFuture, deliveryCompletableFuture, refundCompletableFuture).join();

return new OrderDetailsResponse(orderProductsCompletableFuture.join(), deliveryCompletableFuture.join(), refundCompletableFuture.join());
return new OrderDetailsResponse(orderProductsFuture.join(), deliveryFuture.join(), refundFuture.join());
}

public OrderDetailsResponse findOrderDetails(final Long orderId) {
public OrderDetailsResponse findOrderDetailsBySync(final Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("Order not found"));

log.info("findOrderDetailsBySync thread name: {}", Thread.currentThread().getName());
Delivery delivery = deliveryRepository.findById(order.getDeliveryId())
.orElseThrow(() -> new RuntimeException("Delivery not found"));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.order.perf.common.async;

import com.order.perf.domain.Delivery;
import com.order.perf.domain.Order;
import com.order.perf.domain.OrderProduct;
import com.order.perf.domain.Refund;
import com.order.perf.domain.repository.DeliveryRepository;
import com.order.perf.domain.repository.RefundRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
@AllArgsConstructor
public class AsyncRepositoryService {
private final DeliveryRepository deliveryRepository;
private final RefundRepository refundRepository;

@Async
public CompletableFuture<Delivery> findDeliveryByIdAsync(Long deliveryId) {
log.info("DeliveryByIdAsync thread name: {}", Thread.currentThread().getName());
return CompletableFuture.supplyAsync(() -> deliveryRepository.findById(deliveryId)
.orElseThrow(() -> new RuntimeException("Delivery not found")));
}

@Async
public CompletableFuture<Refund> findRefundByIdAsync(Long refundId) {
log.info("RefundByIdAsync thread name: {}", Thread.currentThread().getName());
return CompletableFuture.supplyAsync(() -> refundRepository.findById(refundId)
.orElseThrow(() -> new RuntimeException("Refund not found")));
}

@Async
public CompletableFuture<List<OrderProduct>> findOrderProductsAsync(Order order) {
log.info("OrderProductsAsync thread name: {}", Thread.currentThread().getName());
return CompletableFuture.supplyAsync(order::getOrderProducts);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setCorePoolSize(5);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("taskExecutor-");
executor.initialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ public OrderController(final OrderService orderService) {
this.orderService = orderService;
}

@GetMapping(path = "/api/orders/{id}")
public ResponseEntity<OrderDetailsResponse> findByOrderDetail(@PathVariable final Long id) {
OrderDetailsResponse response = orderService.findOrderDetails(id);
@GetMapping(path = "/api/orders/sync/{id}")
public ResponseEntity<OrderDetailsResponse> findOrderDetailBySync(@PathVariable final Long id) {
OrderDetailsResponse response = orderService.findOrderDetailsBySync(id);
return new ResponseEntity<>(response, HttpStatus.OK);
}

@GetMapping(path = "/api/orders/async/{id}")
public ResponseEntity<OrderDetailsResponse> findOrderDetailByAsync(@PathVariable final Long id) {
OrderDetailsResponse response = orderService.findOrderDetailsByAsync(id);
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ spring:
username: root
password: ${SPRING_DATASOURCE_PASSWORD}
defer-datasource-initialization: true
hikari:
maximum-pool-size: 200
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQLDialect
Expand Down