Backend (19) 썸네일형 리스트형 k6 부하테스트 이후 느린 API 수정하기 k6로 프로젝트의 대략적인 서비스 흐름을 테스트하겠습니다.유저 생성 -> 토큰 발행 -> 워크스페이스 생성 -> 프로젝트 생성 -> 보드 생성 -> B 생성 -> ... 보드 수정까지TOTAL RESULTS checks_total.......: 18801 279.157521/s checks_succeeded...: 98.57% 18534 out of 18801 checks_failed......: 1.42% 267 out of 18801 ✓ 1. User A Created ✓ 2. Token A Status 200 ✗ 3. Workspace Created ↳ 84% — ✓ 1500 / ✗ 267 ✓ 4. Project Created ✓ 5. Bo.. Spring boot 비즈니스 메트릭 수집하기 현재 진행하고 있는 프로젝트에서 모니터링 데이터를 추출해서 그라파나에서 시각화를 해야하는 됩니다. 이때 스프링 부트의 비즈니스 매트릭 예를 들어, 총 사용자 수 , 활성화된 사용자, 게시판의 개수 등 비즈니스 서비스 관련된 데이터를 뽑아내는 과정에서 발생한 트러블 슈팅을 기록하겠습니다. @Bean public Gauge usersTotalGauge(MeterRegistry meterRegistry, UserRepository userRepository) { return Gauge.builder("user_service_users_total", userRepository, ur -> (double) ur.count()) .description("Total n.. EntityManager란? JPA 를 사용하는데 있어 중요한 개념이다. EntityManager엔티티를 저장하고, 관리하는 1차 캐시 역할을 하는 메모리 공간이다.이 컨텍스트는 EntityManager가 관리하게 되며, 동일 트랜잭션 내에서 동일한 객체를 계속 반환하고 변경사항을 추적하게 된다. 영속성에 대한 특성은 총 4가지가 존재 한다.비영속: 영속성 컨텍스트와 무관한 일반적인 Java객체 new로 생성되는거영속: 영속성 컨텍스트에 주입 또는 관리 em.persist() 이후 상태준영속: 영속화 되었다가 분리된 경우 ( 식별자는 있지만, 영속성 컨텍스트에 없는 객체) em.detach() or em.clear()삭제: 영속성 컨텍스트에서 아예 삭제된 데이터 트랜잭션 커밋 시 DB에서 삭제 em.remove() 여기서 의미하는 .. Spring 성능 부하 테스트 Thread Pool 저번에 쓴 글에 이어서 이번에는좀 더 성능 오류와 서버가 죽는 문제를 해결해보려고 합니다. 저번 글에서는 서바가 일정 수치를 넘어서게 되면 계속 죽는 것을 그래프를 통해서 확인할 수 있었습니다.그리하여 해당 로직을 처리하는 과정에 Thread Pool 을 추가하여 좀 더 요청에 대해 비동기적으로 처리하여 서버가 죽는 형태를 방지해보려고 합니다. 서버의 오류를 줄이는 대신에 TPS,Executed Tests의 값은 내려갔지만, 서버가 죽지 않고 계속 처리를 할 수 있게 되었습니다.Thread Pool 보통 각 요청 마다 처리할 수 있는 Thread를 생성하여 요청을 처리하게 되는데 이때 발생하는 문제로는 생성하는데 생각보다 많은 시간이 걸리게 됩니다.처리속도 보다 더 빠르게 요청이 늘어난다면 스레드를 .. nGrinder 부하 테스트 오늘은 제가 진행했던 프로젝트의 성능을 측정하기 위해 네이버에서 개발한 오픈소스를 사용 해보도록 하겠습니다.nGrinder는 Java기반 성능 테스트 도구입니다. 우선 nGrinder를 사용하기 위해서는 docker가 필요합니다.docker pull ngrinder/controller 그 다음에 도커를 실행 하기 위해 다음과 같은 명령어를 입력합니다. docker run -d \ --platform linux/amd64 \ -v ~/ngrinder-controller:/opt/ngrinder-controller \ --name controller \ -p 8081:80 \ -p 16001:16001 \ -p 12000-12009:12000-12009 \ ngrinder/controller A.. [JPA] 랜덤값 가져오기 프로젝트를 진행 중에 사용자의 테마를 기준으로 랜덤 데이터 값을 가져오는 기능을 만들어야 했다. 어떻게 구현을 해야 하는지 고민을 해보았다.기본적으로 JPA는 랜덤으로 데이터를 추출하는 기능은 없다고 한다. 그래서 2가지 방법을 기본적으로 사용을 한다고 하는데첫 번째 방식은 페이징 방식이다. import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Page;import org.springframework.st.. [Project] Builder 패턴 사용 코드를 짜면서 setter를 사용하는것을 지양해야 한다는 얘기를 들어본적이 있다.하지만 왜 그렇게 짜면 안되는지 그러면 어떻게 사용해야 하는지는 잘 모른다. 그거에 대해서 알아보고 어떻게 작성해야 하는지 알아보겠다. setter 지양1.setter를 사용하면 값을 변경한 의도를 알기 어렵다.2.객체의 일관성을 유지하기 어렵다. setter를 사용하게 되면 외부에서 객체의 내부 상태를 변경 할 수 있으므로 객체의 상태가 언제든지 바뀔 수 있다. 코드의 유지보수를 어렵게 만들 수 있다. 그래서 대안으로 생성자를 통한 주입과 Builder 패턴을 통한 주입이 있다.Builder를 통한 예시를 알아보자우선 생성자보다는 Builder 패턴이 복잡한 객체를 유연하고 가독성 좋게 생성하기 편하다. @Builderp.. Spring Boot JPA를 이용한 수정하기 PUT Spring boot 에서 JPA 를 이용하여 학생 정보를 수정해보도록 하겠습니다. 파일 구성은 이렇게 진행 했고 DB는 mysql을 사용했습니다. 우선 DTO을 구현 합니다. DTO는 Data Transfer Object 의 약자로 로직을 가지지 않는 데이터 객체이고, getter, setter 메소드만 가진 클래스를 의미합니다. package com.Project.demo.DTO; import com.Project.demo.domain.Entity.UserEntity; import com.Project.demo.service.UserService; import lombok.Getter; import lombok.Setter; import org.springframework.stereotype.Serv.. Node.js 쿼리 인젝션 방지 mysql을 사용하면서 데이터베이스에 치명적인 데미지를 줄 수 있는 Sql 인젝션에 대해 알아보았습니다. 해커가 악의적인 Sql 쿼리문을 통해 데이터에 데미지를 주거나 권한을 뺏는 것을 얘기 합니다. 일반적으로 쿼리문을 사용 할 때 db.execute(` INSERT INTO products (title, price, imageUrl, description) VALUES ('${this.title}', ${this.price}, '${this.imageUrl}', '${this.description}') `); 이렇게 사용 하게 되면 쿼리 문자열로 포함이 되기 때문에 취약 해집니다. 따라서 쿼리 인젝션을 방지 하기 위해선 db.execute(` INSERT INTO products (title, pric.. Node.js 와 Mysql 데이터 삽입 유데미 Node.js 강의를 보면 기존의 쇼핑 사이트는 데이터를 json형태로 관리 하였습니다. 이제는 Mysql을 통해서 데이터를 집어 넣도록 하겠습니다. 제품을 관리하는 models폴더 안에 있는 product.js에서 제품을 저장 할 수 있게하는 save() 기능을 만들도록 하겠습니다. module.exports = class Product { constructor(id, title, imageUrl, description, price) { this.id = id; this.title = title; this.imageUrl = imageUrl; this.description = description; this.price = price; } save() { return db.execute ('INS.. 이전 1 2 다음