🗃️ 내가 다시 볼 것

서울우유와 함께 한 기업프로젝트가 끝났다.구현이 끝났으니, 성능을 측정해보고 개선을 해보자!개선을 해볼 API는 공지사항 조회이다.아무래도 모든 유저가 접근할 수 있는 API이기도 하고, 읽기 작업이 주를 이루는 API이므로 선택했다.성능 비교성능을 개선하기 전에 어떤 지점에서 조회 성능이 떨어지는지를 확인해보자! 서울우유 측에서 받은 정보이다.관련 업무를 처리하는 인원이 50명이므로, 테스트 시 인원 수 Max를 50으로 맞췄다.1 페이지에만 접근하기 모든 유저가 공지사항 페이지에 접근하면 첫 번째 페이지로 접근한다.page == 1 인 API에 대해 성능을 체크해보자.request  성공 여부 고려 11000 건 데이터 1000000건 데이터((백만건) 10000000건 데이터 (천만건) reques..
이 글을 쓰게 된 계기큐시즘 31기 기업프로젝트에서 서울우유의 업무 프로세스 개선 프로젝트를 하게되었다.우리가 개선하고 한 프로세스에 대해 간단히 소개하면...기존 업무 프로세스 서울우유의 대리점은 마트, 슈퍼에 납품을 한다.본사에서는 판매량 증가를 통한 이윤 상승을 위해→ 대리점이 저렴하게 납품을 하도록 한다. (할인해서 납품)이후 대리점은 납품한 내역(세금계산서)을 본사에 제출한다.본사는 국세청 홈택스 사이트에서 세금계산서의 *진위여부를 확인한다.맞다면, 지급결의서를 작성한다.이후 본사에서는 지급결의서의 내용대로 대리점에게 금액을 지급한다.그런데 이 과정을 직원들이 수기로 하고 있었다. 대리점에서 전달받은 세금계산서를 서울우유 지점 엄부 담당자가 국세청 홈택스 사이트에서 진위여부를 확인한다. (진위여..
최근 Kotlin과 SpringBoot, MSA를 활용한 프로젝트를 진행하고 있다.MSA는 장점이 많은 아키텍쳐이지만, 해결해야 할 문제도 있다. 그 중 이번 글에선 장애 전파를 막는 방법, 그 중에서도 서킷 브레이커에 대한 실습을 정리해본다. (코드는 https://github.com/HoyeongJeon/spring-circuit 에서 볼 수 있다.)개념 정리1. 장애 전파를 막는 것이 왜 중요할까?MSA 환경에선 각 서비스가 독립적으로 운영된다. 그러다 보니 다른 서비스에 필요한 데이터가 있을 경우, 요청을 보내 데이터를 얻어온다.여기서 문제는 다른 서비스에 장애가 생겼을 경우다. 이런 경우, 정상 서비스는 지속적인 에러 응답을 받게 된다. 이러면, B 서비스에서 발생한 장애가 A 서비스에도 전파 ..
(이 글을 적는 가장 큰 목적은 여러 상황(JPA, JPQL, Nativa Query, @Transactional 의 조합) 에서 쿼리가 어떻게 날아가는지 보는 것이기에, 영속성 컨텍스트에 대한 자세한 설명은 하지 않을 예정입니다.) JPA를 배우면 영속성 컨텍스트에 대해 배우게 된다.영속성 컨텍스트에 대해 간단히 설명하면 , "애플리케이션과 DB 사이에 영속화된 엔티티를 관리하는 논리적 공간" 으로 정의할 수 있다.영속화란 엔티티를 영속성 컨텍스트가 관리할 수 있게 만드는 것이다. 영속성 컨텍스트에 대해 간단히 알아보자.영속성 컨텍스트에 대한 간단한 공부영속성 컨텍스트는 DB로의 접근을 최소화고, 동일한 엔티티의 동등성을 보장하기 위해 다음 4가지 기능을 제공한다. 1. 1차 캐시개발자가 DB에 특정 ..
JPA의 쿼리가 어떻게 날아가는지 여러 방면으로 공부하다 save() 동작에 대한 의문이 생겼다.그래서 깊게 알아보려 한다.( 전체 코드 👉🏻 https://github.com/HoyeongJeon/blog-code/tree/main/howsavework )고민의 시작 public void testNoneAnnotation() { System.out.println("// JPA만 사용하기(@Transactional 이 없는 경우)"); Member member = memberRepository.findById(1L).get(); member.setAge(35); memberRepository.save(member); S..
무한스크롤의 경우, 어떻게 Redis 키를 설정하면 좋을지에 대한 고민(생각의 흐름을 적고, 정리해보는거라 두서없을 가능성 200%입니다.) 문제사항게시판 글목록 캐시하기 단, 100개씩 보여주는 무한 스크롤내가 생각한 캐시 고려사항데이터 정합성메모리 효율성TTL 관리 여러 사항을 고려해 보기 키 당 데이터를 50개씩 저장하면?가장 최신 글의 ID가 1100이라 해보자.처음 게시판에 들어오면 다음과 같이 데이터 캐시  1100 - 1051,1050 - 1001 유저 쭉쭉 내리다 1001에 닿으면서버로 요청을 보내서1000 - 951 캐시하고,950 - 901 캐시함. → 이건 좀 비효율적이다.왜 ?한 번에 보여줘야 할 데이터가 100개인데, 해당 데이터를 보여주기 위해 계속 2번 나눠서 저장해야 한다.즉..
N+1 문제란?N+1문제란 연관 관계가 설정된 엔티티를 조회할 때 ,엔티티를 조회하는 쿼리 1번에 해당 엔티티에 연관된 N번의 쿼리가 추가로 실행되는 것을 말한다.예를 들어, 멤버 한명이 10개의 글을 썼다고 가정할 때, 멤버를 조회하면 이 멤버와 연관된 10개의 글을 가져오기 위해 추가로 10개의 쿼리가 실행되는 것이다. (1+N이라 하는 것이 더 이해하기 쉬울듯!)왜 발생할까?멤버와 게시글을 예시로 코드를 보며 이해해보자. 멤버와 게시글의 관계는 1 : N 이다.  @Entity@Datapublic class Member { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "mem..
조각조각 프로젝트를 진행하면서 블루/그린 무중단 배포를 진행했다.이번 글에선어떻게 아키텍쳐가 변화해 왔는지왜 무중단 배포로 변경했는지어떻게 블루/그린 무중단 배포를 구현했는지의 순서로 적어보겠다! (무중단 배포가 궁금한 사람들은 해당 부분만 찾아서 보면 된다.)아키텍처가 변화해온 과정1. 초기 아키텍쳐 초기 상태는 위와 같았다.Github Actions를 사용해 CI/CD 파이프라인을 구성했다. Nginx를 통해 프록시를 설정했고, Docker를 사용해 스프링부트 애플리케이션을 띄웠다. 비용을 절감하기 위해 DB는 AWS를 사용했다. CI/CD는 다음과 같은 형식으로 이뤄졌다.테스트 및 빌드컨테이너 레지스트리에 이미지를 pushNCP에 docker image pullDocker를 통해 띄움.초기 배포에 ..
이번 글에선 refreshToken을 통해 만료된 accessToken을 재발급 받고 사용자의 로그인 상태를 유지하는 방법을 알아보자.프론트엔드 코드는 ReactJS를 사용할 예정이고, 백엔드는 SpringBoot , NestJS를 사용할 예정이다.(프론트엔드 개발자라면 ReactJS, 백엔드 개발자라면 본인이 사용하는 스택의 코드를 보면 된다!) 먼저 JWT 토큰에 대해선 모두 잘 알고있다 생각하고 간단히 설명을 하고 넘어가겠다. (기본적으로 제가 작성하는 모든 글은 프로그래밍을 처음 공부하는 저에게 필요했던 내용들입니다.과거의 제가 알고 싶었지만 찾지 못했던 내용들을 알게된 현재의 제가 과거의 저에게 설명한단 생각으로 쓰는 글입니다.그러니 매우 쉬운 내용도 자세히 풀어서 설명되어 있을 수 있습니다.아..
본 글의 예제 코드는 JavaScript를 사용했습니다. JavaScript를 모르고, Node.js를 모른다면 Node.js에는 이런 개념이 있구나~ 정도로 이해하면 감사하겠습니다~!최근 자바를 열심히 하고 있다.JS도 잊지않기 위해 간단한 개념 정리를 해보려고 한다.오늘은 비동기 프로그래밍에 대해 정리해보고자 한다. JS에서 함수를 호출하면 함수의 실행 컨텍스트(실행 컨텍스트란 JS에서 실행할 코드에 제공할 환경 정보를 모아놓은 객체이다!)가 생성된다.https://junilhwang.github.io/TIL/Javascript/Domain/Execution-Context/ 실행 컨텍스트(VE, LE , this binding)는 콜 스택에 쌓이고, 함수가 실행된다.함수가 실행을 끝내면, 해당 함수의..
이번 글에선 무료 도메인을 발급받고 https를 적용해보겠습니다. https를 적용한다는 것은 서버에 배포가 되어있는 상태이겠죠!? (서버에 배포가 되어있다 가정하고 글을 적어보겠습니다.) 1. 무료 도메인 발급받기https를 적용하려면 먼저 도메인을 발급받아야 합니다.도메인을 발급받는 방법은 여러가지이지만...(가비아, Route 53 등)돈은 아끼면 좋으니 여기선 무료 도메인을 발급받겠습니다. https://xn--220b31d95hq8o.xn--3e0b707e/  내도메인.한국 - 한글 무료 도메인 등록센터한글 무료 도메인 내도메인.한국, 웹포워딩, DNS 등 무료 도메인 기능 제공xn--220b31d95hq8o.xn--3e0b707e 1.1  회원가입 1.2  도메인 입력하기 위 검색 결과에서 원..
에러들...1. CI 도중 Redis 연결이 안됨2. CI 서버에서 배포 서버로 docker-compose.yml 파일 전송이 안됨.3. 배포서버의 deploy.sh 에서 에러가 발생함.문제를 해결하고 난 뒤 보니까 간단해보이지만... 새벽에 3시간넘게 붙잡고 있었다...(함께 에러 해결을 위해 정보를 찾아준 최고의 개발리드 성민아 고마워🥹)  시너지 프로젝트 작업 중 Redis를 사용하게 되었다. NCP를 지원받았지만 , Cloud for Redis 비용이 막대했기에 Redis는 컨테이너로 띄워서 배포하기로 결정했다.이때부터 CI/CD 에서 에러가 터지기 시작했다. 1. CI 도중 Redis 연결이 안됨일단 첫번째 에러는 CI 도중 Redis 연결이 안됐고, 의존성 주입이 되지 않았다. CI 도중 테..
문제상황개발자 유미님의 SpringSecurity 강의를 듣던 중 문제 발생. 컨트롤러import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class LoginController { @GetMapping("/login") public String loginP() { return "login"; }} 템플릿 엔진(mustache)login page  /login으로 접속을 하면 login 만 출력이 된다.문제해결@RestController -> @Controll..
현재 내가 속해있는 동아리 큐시즘에선 실제 기업들과 협업해 3주 동안 프로젝트를 진행한다. 내가 속한 팀은 렛츠커리어와 함께 프로젝트를 진행하고 있다. 렛츠커리어에선 현재 대표님이자 멘토님 한 분이 프로그램을 담당한다. 그러다보니 프로그램이 자주 업데이트 될 수 없는 환경이었기에 프로그램 목록을 보여주는 페이지에 캐싱을 적용하는 것이 조회 성능을 올려 줄 것이라고 생각했다. Redis를 선택한 이유캐싱을 하는 방법은 여러가지가 있다.인메모리에 구현하는 방법이 있고, 분산 캐시 시스템을 사용하는 방법도 있다. 인메모리 캐시를 사용하면 구현이 간단하고 빠르다. 렛츠커리어는 실제 제공되는 홈페이지니까 확장성을 고려해 Redis를 사용해 캐싱을 구현하기로 했다. 어떻게 적용했을까?캐싱 전략 중 Look Asid..
산악부 사이트를 배포했는데 문제가 생겼다. 현재 로직에서 로그인을 하면 accessToken과 accessToken의 만료시간을 프론트엔드에 전달하고, 쿠키에 refreshToken을 저장한다.accessToken의 만료시간이 현재 시간보다 과거가 되는 경우(accessToken이 만료된 경우) 쿠키의 refreshToken을 통해 백엔드에 토큰 재발급을 요청한다.문제는 백엔드 코드에서 프론트엔드의 refreshToken을 받지 못하는 것이었고, 브라우저의 쿠키를 보았을 때 refreshToken이 존재하지 않았다. 현재 백엔드 코드는 아래와 같다. @UseGuards(LocalAuthGuard) @Post('login') async login(@Request() req, @Res() res: Re..
현재 진행하고 있는 프로젝트의 CI/CD 스크립트를 작성했습니다. 나의 코드는 제대로 CI를 통과하는데, 함께 개발을 하던 친구의 코드가 CI를 통과하지 못했고, ApplicationTests > contextLoads() FAILED 에러를 마주했습니다. 해당 에러를 좀 더 자세히 보았습니다.LetscareerCApplicationTests > contextLoads() FAILED java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180 Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException at Construct..
웹사이트를 운영하다보면 실시간으로 알림을 받아야하는 경우가 있습니다.(현재 개발중인 동아리 웹사이트를 예로들면 에러 , 암벽화 대여 등) 저는 이를 Slack과 Slack Webhook을 통해 구현했습니다.1. Slack에 앱 추가하기원하는 워크스페이스의 채널로 들어가 아래 사진 순서대로 클릭!     이렇게 슬랙에서 해야할 일은 전부 끝났습니다. 코드로 구현해볼게요. 2. Nest.js 앱에 추가하기@Slack/webhook 라이브러리를 사용하겠습니다. @slack/webhookOfficial library for using the Slack Platform's Incoming Webhooks. Latest version: 7.0.2, last published: 7 months ago. Start u..
1. 에러 필터 작성 import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus,} from '@nestjs/common';import { HttpAdapterHost } from '@nestjs/core';import { timestamp } from 'rxjs';@Catch()export class AllExceptionsFilter implements ExceptionFilter { constructor(private readonly httpAdapterHost: HttpAdapterHost) {} catch(exception: unknown, host: ArgumentsHost) { const { httpA..
프로젝트를 구현할 때 db에 초기 데이터가 필요한 경우들이 있습니다.초기 관리자 계정, 테스트를 위한 더미 데이터 등..이렇게 db에 더미 데이터를 미리 삽입하는 것을 seeding이라 합니다.매번 다른 분들의 블로그 글을 참고하며 seeding을 했었는데, 이번 기회에 직접 정리해보려 합니다. 저는 seeding을 위해 typeorm-extension 라이브러리를 사용하겠습니다.(seeder 라이브러리로 typeorm-seeding, nestjs-seeder 라이브러리가 있었지만, 두 라이브러리 모두 현재 업데이트가 되고있지 않으며, 주간 사용자도 typeorm-extension에 비해 적기에 typeorm-extension을 선택했습니다.) typeorm-extensionA library to cr..
활동게시글은 동아리 활동에 대한 글입니다.매 활동마다 활동시 찍은 사진 몇장과 그에 대한 간략한 내용을 업로드 할 예정인데요,어떤 경우엔 활동게시글을 수정해야할 수 있습니다.사진을 잘못 올렸다던가... 내용에 오타가 있다던가... 이미 업로드한 사진은 그대로 두고, 다른 내용을 수정하려할 때 에러가 발생했습니다. 문제상황 위와 같이 content에 값만 수정을 하려할 때, 에러가 발생했습니다.게시글을 수정하는 로직은 아래와 같습니다. async updateActivity( userId: number, activityId: number, dto: EditActivityDto, images?: string[], ) { const { content, date } = dto; ..
전호영
'🗃️ 내가 다시 볼 것' 카테고리의 글 목록