-
Notifications
You must be signed in to change notification settings - Fork 0
[fix] 게시글 좋아요 500 error(deadlock) 해결 #334
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
Open
hd0rable
wants to merge
19
commits into
develop
Choose a base branch
from
test/#322-k6-feed-like-pessimistic-lock
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 18 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
5ac36e6
[test] k6 테스트파일 추가 (#322)
hd0rable 480e850
[test] 피드 좋아요 상태변경 다중 스레드 테스트 (#322)
hd0rable f14a490
[test] 피드 좋아요 상태변경 다중 스레드 테스트코드 수정 (#322)
hd0rable 1731bcc
[test] k6 테스트파일 추가 (#322)
hd0rable 9bfc799
[test] k6 테스트파일 추가 (#322)
hd0rable 8827e93
[test] 피드 좋아요 상태변경 다중 스레드 테스트코드 수정 (#322)
hd0rable 56e757f
[refactor] 게시글 좋아요 상태변경 비관적 락 도입 (#322)
hd0rable 27f7532
[refactor] 게시글 좋아요 상태변경 비관적 락 도입하여 조회시 post 레코드에 lock 과함께 조회하는 함수 추가 …
hd0rable 5393625
[refactor] 게시글 좋아요 상태변경 비관적 락 도입하여 조회시 post 레코드에 lock 과함께 조회하는 함수 추가-…
hd0rable 0a6f7b1
[refactor] 게시글 좋아요 상태변경 비관적 락 도입하여 조회시 post 레코드에 lock 과함께 조회하는 함수 추가-…
hd0rable 3946830
[refactor] 게시글 좋아요 상태변경 비관적 락 도입하여 조회시 post 레코드에 lock 과함께 조회하는 함수 추가-…
hd0rable 7b3c2a3
[test] k6 테스트파일 추가 (#322)
hd0rable 8a4c489
Merge remote-tracking branch 'origin/develop' into test/#322-k6-feed-…
hd0rable d7a5c42
[delete] 사용하지않는 테스트 스크립트 삭제 (#322)
hd0rable cf0d246
[chore] 테스트 스크립트 파일 위치 변경 (#322)
hd0rable 38aed85
[refactor] 비관락 적용 메서드 네이밍 변경 (#322)
hd0rable 775e16b
[refactor] 동시성 테스트 파일 위치 변경 (#322)
hd0rable 3b9abb9
[test] 서비스 로직 수정하면서 깨지는 테스트 수정 (#322)
hd0rable 7677566
[chore] 주석 오타 수정 (#322)
hd0rable File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,79 @@ | ||
| // 낮은 동시성 20명이서 동시성 기능 안전성 테스트 | ||
| import http from 'k6/http'; | ||
| import { sleep,check } from 'k6'; // sleep 기능 사용 시 추가 (sleep(n) -> 지정한 n 기간 동한 VU 실행을 일시 중지) | ||
|
|
||
| const BASE_URL = 'http://localhost:8080'; | ||
| const FEED_ID = 1; // 테스트할 피드 ID | ||
| const VUS = 20; // 원하는 VU 수 | ||
|
|
||
| export let options = { | ||
| thresholds: { | ||
| // 요청 95%가 500ms 이내 응답을 받아야 함 | ||
| http_req_duration: ['p(95)<500'], | ||
| // 전체 요청 중 실패율 1% 미만이어야 함 | ||
| http_req_failed: ['rate<0.01'], | ||
| }, | ||
| vus: VUS, | ||
| duration: '30s', // 30초동안 테스트 | ||
| }; | ||
|
|
||
| // 테스트 전 사용자 별 토큰 발급 | ||
| export function setup() { | ||
| let tokens = []; | ||
| let likeStatus = []; | ||
|
|
||
| // 유저 ID에 대해 토큰을 미리 발급 | ||
| for (let userId = 1; userId <= VUS; userId++) { | ||
| const res = http.get(`${BASE_URL}/api/test/token/access?userId=${userId}`); | ||
| check(res, { 'token received': (r) => r.status === 200 && r.body.length > 0 }); | ||
| tokens.push(res.body); | ||
| likeStatus.push(true); // 좋아요 요청 | ||
| } | ||
|
|
||
| return { tokens, likeStatus }; | ||
| } | ||
|
|
||
| export default function (data) { | ||
| const vuIdx = __VU - 1; | ||
| const token = data.tokens[vuIdx]; | ||
|
|
||
| if (data.lastStatusCode === 200) { | ||
| data.likeStatus[vuIdx] = !data.likeStatus[vuIdx]; | ||
| } | ||
|
|
||
| // FeedIsLikeRequest DTO에 맞는 요청 body | ||
| const payload = JSON.stringify({ | ||
| type: data.likeStatus[vuIdx], | ||
| }); | ||
|
|
||
| const params = { | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| 'Authorization': `Bearer ${token}`, | ||
| }, | ||
| }; | ||
|
|
||
| const res = http.post(`${BASE_URL}/feeds/${FEED_ID}/likes`, payload, params); | ||
| data.lastStatusCode = res.status; | ||
|
|
||
| // 응답 체크 | ||
| check(res, { | ||
| 'status 200': (r) => r.status === 200, | ||
| 'status 400': (r) => r.status === 400, | ||
| 'Internal server error': (r) => r.status === 500, | ||
| }); | ||
|
|
||
| if (res.status !== 200) { | ||
| console.error(`[VU${__VU}] ERROR status=${res.status} body=${res.body}`); | ||
| } | ||
|
|
||
| sleep(0.5); // 500ms 간격으로 요청, 일반적 사용자 환경 모의 | ||
| } | ||
|
|
||
| // 테스트 결과 html 리포트로 저장 | ||
| import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js"; | ||
| export function handleSummary(data) { | ||
| return { | ||
| "summary.html": htmlReport(data), | ||
| }; | ||
| } | ||
This file contains hidden or 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,83 @@ | ||
| // 점진적 부하 증가 (Ramp-up) VU: 20 → 50 → 100 → 150 (1분 단위로 증가) | ||
| import http from 'k6/http'; | ||
| import { sleep,check } from 'k6'; // sleep 기능 사용 시 추가 (sleep(n) -> 지정한 n 기간 동한 VU 실행을 일시 중지) | ||
|
|
||
| const BASE_URL = 'http://localhost:8080'; | ||
| const FEED_ID = 1; // 테스트할 피드 ID | ||
|
|
||
| export let options = { | ||
| thresholds: { | ||
| http_req_duration: ['p(95)<500'], | ||
| http_req_failed: ['rate<0.01'], | ||
| }, | ||
| stages: [ | ||
| { duration: '1m', target: 20 }, // 1분간 VU 20명으로 점진적 증가 | ||
| { duration: '1m', target: 50 }, // 1분간 VU 50명으로 증가 | ||
| { duration: '1m', target: 100 }, // 1분간 VU 100명으로 증가 | ||
| { duration: '1m', target: 150 }, // 1분간 VU 150명으로 증가 | ||
| { duration: '30s', target: 0 }, // 30초 동안 VU 0명으로 줄이며 테스트 종료 | ||
| ], | ||
| }; | ||
|
|
||
| // 테스트 전 사용자 별 토큰 발급 | ||
| export function setup() { | ||
| // 점진적 증가하는 최대 VU 수 계산 | ||
| const maxVUs = 150; | ||
| let tokens = []; | ||
| let likeStatus = []; | ||
|
|
||
| // 유저 ID에 대해 토큰을 미리 발급 | ||
| for (let userId = 1; userId <= maxVUs; userId++) { | ||
| const res = http.get(`${BASE_URL}/api/test/token/access?userId=${userId}`); | ||
| check(res, { 'token received': (r) => r.status === 200 && r.body.length > 0 }); | ||
| tokens.push(res.body); | ||
| likeStatus.push(true); // 좋아요 요청 | ||
| } | ||
|
|
||
| return { tokens, likeStatus }; | ||
| } | ||
|
|
||
| export default function (data) { | ||
| const vuIdx = __VU - 1; | ||
| const token = data.tokens[vuIdx]; | ||
|
|
||
| if (data.lastStatusCode === 200) { | ||
| data.likeStatus[vuIdx] = !data.likeStatus[vuIdx]; | ||
| } | ||
|
|
||
| // FeedIsLikeRequest DTO에 맞는 요청 body | ||
| const payload = JSON.stringify({ | ||
| type: data.likeStatus[vuIdx], | ||
| }); | ||
hd0rable marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const params = { | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| 'Authorization': `Bearer ${token}`, | ||
| }, | ||
| }; | ||
|
|
||
| const res = http.post(`${BASE_URL}/feeds/${FEED_ID}/likes`, payload, params); | ||
| data.lastStatusCode = res.status; | ||
|
|
||
| // 응답 체크 | ||
| check(res, { | ||
| 'status 200': (r) => r.status === 200, | ||
| 'status 400': (r) => r.status === 400, | ||
| 'Internal server error': (r) => r.status === 500, | ||
| }); | ||
|
|
||
| if (res.status !== 200) { | ||
| console.error(`[VU${__VU}] ERROR status=${res.status} body=${res.body}`); | ||
| } | ||
|
|
||
| sleep(0.5); // 500ms 간격으로 요청, 일반적 사용자 환경 모의 | ||
| } | ||
|
|
||
| // 테스트 결과 html 리포트로 저장 | ||
| import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js"; | ||
| export function handleSummary(data) { | ||
| return { | ||
| "summary.html": htmlReport(data), | ||
| }; | ||
| } | ||
This file contains hidden or 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,116 @@ | ||
| // 80%는 상세조회(GET), 20%는 좋아요 변경(POST) 요청 | ||
| import http from 'k6/http'; | ||
| import { sleep,check } from 'k6'; | ||
|
|
||
| const BASE_URL = 'http://localhost:8080'; | ||
| const FEED_ID = 1; // 테스트할 피드 ID | ||
|
|
||
| export let options = { | ||
| scenarios: { | ||
| read_scenario: { | ||
| executor: 'constant-vus', | ||
| vus: 160, // 전체 200명 중 160명은 상세 조회 전담 | ||
| duration: '2m', | ||
| exec: 'readFeed', | ||
| }, | ||
| write_scenario: { | ||
| executor: 'constant-vus', | ||
| vus: 40, // 전체 200명 중 20명은 좋아요 변경 전담 | ||
| duration: '2m', | ||
| exec: 'likeFeed', | ||
| }, | ||
| }, | ||
| thresholds: { | ||
| http_req_duration: ['p(95)<500'], | ||
| http_req_failed: ['rate<0.01'], | ||
| }, | ||
| }; | ||
|
|
||
| // 테스트 전 사용자 별 토큰 발급 | ||
| export function setup() { | ||
| // 최대 VU 수 계산 | ||
| const maxVUs = 200; | ||
| let tokens = []; | ||
|
|
||
| // 유저 ID에 대해 토큰을 미리 발급 | ||
| for (let userId = 1; userId <= maxVUs; userId++) { | ||
| const res = http.get(`${BASE_URL}/api/test/token/access?userId=${userId}`); | ||
| check(res, { 'token received': (r) => r.status === 200 && r.body.length > 0 }); | ||
| tokens.push(res.body); | ||
| } | ||
|
|
||
| return {tokens}; | ||
| } | ||
|
|
||
| // 상세조회만 실행 | ||
| export function readFeed(data) { | ||
| let vuIdx = __VU - 1; | ||
| let token = data.tokens[vuIdx]; | ||
| let params = { | ||
| headers: { | ||
| 'Authorization': `Bearer ${token}`, | ||
| 'Content-Type': 'application/json', | ||
| } | ||
| }; | ||
|
|
||
| let res = http.get(`${BASE_URL}/feeds/${FEED_ID}`, params); | ||
| check(res, { | ||
| 'feed detail 200': (r) => r.status === 200, | ||
| 'feed detail status 400': (r) => r.status === 400, | ||
| 'feed detail Internal server error': (r) => r.status === 500, | ||
| }); | ||
|
|
||
| if (res.status !== 200) { | ||
| console.error(`[VU${__VU}] ERROR status=${res.status} body=${res.body}`); | ||
| } | ||
|
|
||
| sleep(Math.random()); // 0~1초 내 랜덤 대기(실사용 패턴 반영) | ||
| } | ||
|
|
||
| // 좋아요 변경만 실행 | ||
| export function likeFeed(data) { | ||
| let vuIdx = __VU - 1; | ||
| let token = data.tokens[vuIdx]; | ||
| let params = { | ||
| headers: { | ||
| 'Authorization': `Bearer ${token}`, | ||
| 'Content-Type': 'application/json', | ||
| } | ||
| }; | ||
|
|
||
| // 상세 조회로 좋아요 상태 확인 | ||
| let getRes = http.get(`${BASE_URL}/feeds/${FEED_ID}`, params); | ||
| let isLiked = false; | ||
| if (getRes.status === 200) { | ||
| try { | ||
| let body = JSON.parse(getRes.body); | ||
| isLiked = body.data.isLiked; | ||
| } catch (e) { | ||
| console.error(`[VU${__VU}] 상세조회 파싱 오류:`, getRes.body); | ||
| } | ||
| } | ||
|
|
||
| // 상태 반대로 좋아요 또는 취소 요청 | ||
| let payload = JSON.stringify({ type: !isLiked }); | ||
| let res = http.post(`${BASE_URL}/feeds/${FEED_ID}/likes`, payload, params); | ||
hd0rable marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| check(res, { | ||
| 'feed like 200': (r) => r.status === 200, | ||
| 'feed like status 400': (r) => r.status === 400, | ||
| 'feed like Internal server error': (r) => r.status === 500, | ||
| }); | ||
|
|
||
| if (res.status !== 200) { | ||
| console.error(`[VU${__VU}] ERROR status=${res.status} body=${res.body}`); | ||
| } | ||
|
|
||
| sleep(Math.random() + 0.5); // 0.5~1.5초 랜덤 대기 | ||
| } | ||
|
|
||
| // 테스트 결과 html 리포트로 저장 | ||
| import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js"; | ||
| export function handleSummary(data) { | ||
| return { | ||
| "summary.html": htmlReport(data), | ||
| }; | ||
| } | ||
File renamed without changes.
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.