
실습의 편의를 위해 일부 코드를 작성해두었다.
@Entity(name = "daily_active_users") @Getter @NoArgsConstructor public class DailyActiveUser { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long userId; private LocalDate activeDate; public DailyActiveUser(Long userId, LocalDate activeDate) { this.userId = userId; this.activeDate = activeDate; } }
@RestController @RequestMapping("/dau") @RequiredArgsConstructor public class DailyActiveUserController { private final DailyActiveUserService dailyActiveUserService; // 활동 유저 기록 API @PostMapping("/record") public void recordActiveUser( @RequestBody RecordActiveUserRequestDto recordActiveUserRequestDto ) { dailyActiveUserService.recordActiveUser(recordActiveUserRequestDto.getUserId()); } // DAU 조회 API @GetMapping("/count") public long getDau( @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date ) { return dailyActiveUserService.getDau(date); } }
@Getter @NoArgsConstructor public class RecordActiveUserRequestDto { private Long userId; }
@Service @RequiredArgsConstructor public class DailyActiveUserService { private final DailyActiveUserRepository dailyActiveUserRepository; @Transactional public void recordActiveUser(Long userId) { LocalDate today = LocalDate.now(); // 이미 활동(방문) 기록이 있는 유저라면 저장하지 않는다. if (!dailyActiveUserRepository.existsByUserIdAndActiveDate(userId, today)) { // 활동 기록 저장 dailyActiveUserRepository.save(new DailyActiveUser(userId, today)); } } @Transactional(readOnly = true) public long getDau(LocalDate date) { // 특정 날짜의 DAU를 SQL문의 COUNT를 활용해 계산 return dailyActiveUserRepository.countByActiveDate(date); } }
public interface DailyActiveUserRepository extends JpaRepository<DailyActiveUser, Long> { // 특정 사용자가 특정 날짜에 활동(방문)했는지 확인 boolean existsByUserIdAndActiveDate(Long userId, LocalDate activeDate); // 특정 날짜의 DAU를 계산 long countByActiveDate(LocalDate activeDate); }




import http from 'k6/http'; import {check} from 'k6'; export const options = { // 가상 유저(VUs) 1000명으로 설정 vus: 1000, // 테스트를 10초 동안 진행 duration: '10s', }; export default function () { const userId = Math.floor(Math.random() * 100000) + 1; // 1 ~ 100000 사이의 랜덤 userId const payload = JSON.stringify({ userId: userId, }); const params = { headers: { 'Content-Type': 'application/json', }, }; // 1. 유저 활동 기록 API 호출 const recordRes = http.post('http://localhost:8080/dau/record', payload, params); check(recordRes, { 'record status is 200': (r) => r.status === 200, }); // 오늘 날짜를 YYYY-MM-DD 형식으로 가져온다. const today = new Date().toISOString().split('T')[0]; // 2. DAU 조회 API 호출 const countRes = http.get(`http://localhost:8080/dau/count?date=${today}`); check(countRes, { 'count status is 200': (r) => r.status === 200, }); }
$ k6 run scripts/script_4-1.js
