성능 테스트의 주요 측정 항목

응답 관련 평균 응답 시간: 사용자가 요청보내고 응답의 마지막 바이트를 받을 때까지 걸리는 평균적인 시간을 말한다. 실제 사용자 경험을 가장 잘 나타내는 수치다. 최대 응답 시간: 응답 시간 중에 가장 긴 경우를 말한다. 응답에 이상 현상을 식별할 때 사용한다. Error rate: (문제가 발생하는 요청 수)/(전체 요청 수)를 의미한다. 사용자 경험을 개선하려면 Error rate를 줄여야된다. 처리량 관련 동시 사용자(Concurrent users): 특정 시점에 활성 상태인 Virtual User의 수를 말한다. 시스템이 수용할 수 있는 유저의 수를 정할 때 사용할 수 있다....

2024-09-15 · 1 min · 192 words

성능 테스트

팀 프로젝트에 성능 테스트를 진행해보기 앞서 성능 테스트의 기본 지식을 학습할 필요가 있어서 글을 작성하게 되었다. 성능 테스트? 부하 테스트? 스트레스 테스트? 성능 테스트, 부하 테스트, 스트레스 테스트. 이름만 들어서는 전부 같은 같은 말로 보였다. 하지만 실제로 표현하는 사례들을 보니 어느 정도 차이가 있었다. 성능 테스트 성능 테스트는 소프트웨어와 인프라의 속도를 테스트한다. 메모리 사용량, 네트워크 대역폭 및 처리량, 응답 시간, CPU 사용률 등의 기준을 두고 측정할 수 있다. 시스템 내에 통신 과정의 병목을 찾아내기 위해서 진행 한다....

2024-09-15 · 2 min · 371 words

서비스 클래스가 다른 서비스 클래스를 의존해도 되는가

서비스가 다른 서비스를 참조하도록 설계를 하는게 좋을지, 아니면 서비스는 다른 서비스를 의존하지 않고, 여러 개의 DAO를 가지고 오도록 하면 좋을지에 대한 고민이였다. 서비스가 다른 서비스를 가지는 경우의 장단점은 명확했다. 장점: 유효성 검사 등 비즈니스 로직의 중복 코드를 제거할 수 있다. 단점: 서비스 간의 순환 참조가 발생할 수도 있다. → 내가 내린 결론 중복 코드 제거의 장점을 가져가기 위해 서비스가 다른 서비스를 가질 수 있는 방법을 선택 순환 참조가 발생하지 않게, 서비스간의 계층을 잘 설계해야된다....

2024-09-15 · 1 min · 74 words

서브 모듈 빌드하기

gradle의 서브 모듈 하나만 빌드하고 싶은 경우가 있었다. 아래 명령어로 원하는 서브 모듈의 빌드가 가능하다. gradlew :{서브 모듈 이름}:build 참고 자료 https://spring.io/guides/gs/multi-module/ https://stackoverflow.com/questions/16976214/gradle-build-only-one-module

2024-09-15 · 1 min · 23 words

상태 코드 301 vs 302

301 Moved Permanently: 리퀘스트된 리소스에는 새로운 URI로 영구히 이동되었기 떄문에 이후로는 그 리소를 참조하는 URI를 사용해야된다는 뜻이다. 새로운 URI는 Location 헤더 필드에 명시되어 있다. 브라우저는 이 페이지로 리디렉션되고 리소스에 대한 링크를 업데이트 한다. 302 Found: 리퀘스트된 리소스가 새로운 URI로 일시적으로 이동했다는 뜻이다. 브라우저는 사용자를 이 URL의 페이지로 리다이렉트시키지만 리소스에 대한 링크가 업데이트 되지 않는다. 참고 자료 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/301 https://developer.mozilla.org/ko/docs/Web/HTTP/Status/302

2024-09-15 · 1 min · 58 words

상속시 부모의 메서드 호출하는 법

super() 를 붙이면된다. class MaxLimitCalculator(Calculator): max_limit = 100 def add(self, val): super().add(val) if self.value > self.max_limit: self.value = self.max_limit 참고 자료 https://dev-ku.tistory.com/168

2024-09-15 · 1 min · 22 words

빠르게 입력 받기

많은 양의 데이터를 입력받아야 될 때 input() 함수가 느릴 수 있다. 이럴 때는 sys 라이브러리의 readline() 함수를 이용하면 된다. rstrip()은 string 오른쪽에 있는 개행 문자와 공백을 제거해주는 역할을 한다. readline()으로 입력하게 되면 문자열에 개행도 포함되기 때문이다. import sys input_data = sys.stdin.readline().rstrip() 참고 자료 https://www.delftstack.com/ko/howto/python/python-remove-newline-from-string/

2024-09-15 · 1 min · 44 words

빌드 시 profile 설정

-P {프로필 명} 쉼표로 구분해서 프로필을 여러개 설정할 수 있다. mvn -P profile-1,profile-2 package 참고 자료 https://maven.apache.org/guides/introduction/introduction-to-profiles.html

2024-09-15 · 1 min · 17 words

빈 생성자 만들지 않아도 되는 방법

@ConstructorProperties 어노테이션을 생성자에 붙이면 해결된다. class Employee { private final int id; private final String name; @ConstructorProperties({"id", "name"}) public Employee(int id, String name) { this.id = id; this.name = name; } public int getEmpId() { return id; } public String getEmpName() { return name; } } 참고 자료 https://www.tutorialspoint.com/when-to-use-constructorproperties-annotation-with-jackson-in-java

2024-09-15 · 1 min · 49 words

빈 등록시 @Component가 아닌 @Configuration을 사용하는 이유

@Configuration 안에 @Component가 있다. 즉 둘 다 클래스 자체가 빈으로 등록된다. 내부에서 선언한 빈을 싱글톤으로 등록하고자 하는 경우에는 @Configuration이 붙어야 된다. 큰 차이점은 @Configuration은 CGLIB wrapper를 사용하여 모든 빈 메서드가 자신이 현재 클래스의 첫 호출처럼 동작한다. 따라서 아래의 코드는 @Component는 동작을 하지 않는다. CGLIB은 프록시 빈 객체를 만들어서 실제로 사용될 때 객체가 생성되기 때문에 빈에 다른 빈을 의존할 수 있다. @Configuration public static class Config { @Bean public SimpleBean simpleBean() { return new SimpleBean(); } @Bean public SimpleBeanConsumer simpleBeanConsumer() { return new SimpleBeanConsumer(simpleBean()); } }

2024-09-15 · 1 min · 85 words

비즈니스 로직을 DB가 아닌 앱에 넣어야 하는 이유

배경 비즈니스 로직을 DB가 아닌 앱에서 처리해야 되는 주 이유는 애플리케이션 리소스가 더 확장하기 쉽기 때문이다. 하지만 DB에서 반환되는 결과의 양을 통제하려면 DB에 일부 로직을 넣을 수 밖에 없다. DB에서 처리할 로직과 앱에서 처리할 로직의 기준을 정해본다. 방법 추출과 필터링 분리하기 데이터 필터링에 필요한 일부 필드만 가져오고, 앱에서 필터링 로직을 수행한다. 필터링이 완료되면, 필터링이 완료된 ID 목록으로 후속 쿼리를 수행한다. select id,field1,field2 from my_table select * from my_table where id in (3,5,123,392,....

2024-09-15 · 1 min · 98 words

브레이크 포인트 지정시 해당 스레드만 멈추도록 설정하기

브레이크 포인트를 찍어두고 h2-console로 DB 상태를 확인해야되는 경우가 있었다. 하지만 브레이크 포인트에서 멈추면 모든 스레드가 멈추어서 h2-console에 접속하지 못하는 상황이 생겼다. 이를 해결하기 위해 해당 브레이크 포인트의 스레드만 멈추가 설정할 수 있다. 브레이크 포인트에 우클릭하면 설정이 가능하다. 참고 자료 https://stackoverflow.com/questions/35179110/spring-boot-is-blocking-h2-console-in-debug-mode

2024-09-15 · 1 min · 40 words

불변 객체 역직렬화 방법 분석

배경 data class Person(var id: Long? = null, var name: String? = null) fun main() { val objectMapper = ObjectMapper() val person: Person = objectMapper.readValue("{\"id\":1, \"name\": \"junroot\"}", Person::class.java) println(person.name) } ObjectMapper를 통해 역직렬화하는 경우, 기본 생성자를 이용해 객체를 생성한 뒤 자바 리플렉션을 이용해 값을 주입하고 있다. 따라서 기본 생성자가 필요한데 이렇게 되면 프로퍼티들이 불변일 수가 없게된다. @JsonCreator와 @JsonProperty를 통해서 생성 가능하다는 사실을 알게되고 이를 사용했었다. data class Person @JsonCreator constructor( @JsonProperty("id") val id: Long, @JsonProperty("name") val name: String ) fun main() { val objectMapper = ObjectMapper() val person: Person = objectMapper....

2024-09-15 · 2 min · 260 words

범위 탐색 시 인덱스 설계

목표 WHERE 절에서 범위 탐색 시에 인덱스 설계하는 방법을 이해한다. 상황 SELECT first_name, last_name, date_of_birth FROM employees WHERE date_of_birth >= '1971-01-01' AND date_of_birth <= '1971-01-09' AND subsidiary_id = 27 위와 같은 상황에 date_of_birth와 subsidiary_id 의 인덱스 컬럼 순서를 어떻게 해야될지 알아보자. date_of_birth, subsidiary_id 순으로 인덱스 설계할 경우 date_of_birth 기준으로 먼저 정렬되어 있다. 중간 노드만으로는 어느 리프 노드가 subsidiary_id가 27인 경우를 가지고 있는지 알 수 없다. 쿼리에 date_of_birth의 범위 조건이 있으므로, 이를 기준으로 먼저 범위 탐색을 하게 된다....

2024-09-15 · 1 min · 167 words

버블링과 캡처링

목표 이벤트 버블링과 캡처링이 무엇인지 이해한다. 이벤트 기본적으로 js에서는 각 요소(element)가 이벤트를 발생시킬 수 있고, 이벤트 리스너를 통해서 이벤트가 발생했을 때의 동작을 명시할 수 있다. const btn = document.querySelector("button"); btn.addEventListener("click", () => { console.log("event!"); }); 이벤트 전파 실제로 이벤트가 발생한 요소가 아니라 다른 요소에서 이를 처리하고 싶을 떄가 있다. 이 때 이벤트 전파를 이용하게 된다. 이벤트 전파는 버블링과 캡처링이 존재한다. 이벤트가 발생하면 3가지 단계로 이벤트가 흐른다. 캡처링 단계: 이벤트가 하위 요소에 전파되는 단계 타깃 단계: 이벤트가 실제 타깃 요소에 전달되는 단계 버블링 단계: 이벤트가 상위 요소로 전파되는 단계 이벤트가 발생하면 최상위 조상에서 시작해서 아래로 전파가 시작되고 캡처링 -> 타깃 -> 버블링 단계를 거치게 된다....

2024-09-15 · 1 min · 202 words

배포마다 DB 테이블이 삭제되지 않도록 구성하기

properties 파일에 아래의 설정을 추가하여 해결했다. spring.jpa.hibernate.ddl-auto=validate 문제점: 새로운 not null 컬럼이 추가되었을 때 기존 row들은 어떻게 처리하는 것이 좋을까? 예를들어, 서비스가 확장되면서 User에 Age컬럼이 추가되었을 때, Age가 not null 이라면 기존의 사용자 데이터는 어떻게 처리하는 것이 좋을까? → 구글링 결과, 방법은 1. not null을 포기하거나 2. default value를 설정하거나 두 가지 방법 밖에없다. 상태로 컬럼을 추가하는 수밖에 없다. (어떻게 보면 당연하다 우리가 사용자의 나이를 추측할 순 없으니까) 1. not null 포기 기존 데이터는 null로 두고 이후에 생성되는 데이터에서는 null이 들어오지 못하도록 DTO에서 null 값체크를 하도록 구현한다....

2024-09-15 · 2 min · 403 words

반환 값이 void인 메소드 아무것도 하지 않게 mocking

doNothing().when(myList).add(any(Integer.class), valueCapture.capture()); https://www.baeldung.com/mockito-void-methods

2024-09-15 · 1 min · 3 words

뮤텍스와 세마포어의 차이

공유 자원을 관리하기 위해서 뮤텍스와 세마포어라는 기법으로 상호배제를 보장할 수 있다. 이 둘은 비슷해보이지만 몇 가지 차이점이 있다. 간단하게만 정리해봤다. 유사점 세마포어는 공유할 수 있는 프로세스의 수를 정수형으로 저장하고 0보다 클 때 까지만, 접근에 허용한다. 만약 이 정수가 1로 시작한다면 뮤텍스와 동작이 비슷해보인다. 차이점 세마포어 정수형 데이터지만, 뮤텍스는 객체다. 세마포어는 신호 메커니즘이고, 뮤텍스는 잠금 메커니즘이다. 세마포어는 wait, signal 신호로 값이 수정된다. 뮤텍스는 뮤텍스를 소유하고 있는 프로세스가 lock 또는 unlock을 할 수 있다....

2024-09-15 · 1 min · 91 words

문자의 ASCII 코드 값 찾기

ord() 함수를 사용하면 된다. character = 'P' unicode_char = ord(character) print(unicode_char) 참고 자료 https://www.programiz.com/python-programming/methods/built-in/ord

2024-09-15 · 1 min · 14 words

무중단으로 DB 스키마 수정하기

배경 운영중인 DB에 여러 애플리케이션이 사용하고 있으면 컬럼 수정/삭제가 제한이 된다. Online Schema Change 정의 이름 그대로 운영중인 상태에서 스키마를 변경하는 기법을 말한다. 동작 과정 대상 테이블을 복제한다. 복제된 테이블에 스키마를 수정한다. binary log stream이나 trigger 등을 사용해서 복제된 테이블에 변경사항을 반영한다. 수정된 코드를 배포한다. 대상 테이블과 복제된 테이블을 swap한다. 주요 툴 Meta: https://github.com/facebookincubator/OnlineSchemaChange gh-ost: https://github.com/github/gh-ost 참고 자료 https://jojoldu.tistory.com/358 https://blog.myungseokang.dev/posts/online-schema-change/

2024-09-15 · 1 min · 60 words