TE__HO

  • 주니어 개발자가 대용량 트래픽, 대규모 데이터 경험하는 방법(Feat. 뇌피셜)

    주니어 개발자가 대용량 트래픽, 대규모 데이터 경험하는 방법(Feat. 뇌피셜)

    이 블로그 카테고리에서는 개인 프로젝트에 대한 글을 남길 것이고 그전에 진행한 이유와 과정들을 우선 서술해보려 합니다.저와 비슷한 상황의 대학생, 주니어, 신입, 취준생 백엔드 개발자분들에게 조금의 도움이라도 될까 싶어 적는 개인적/주관적인 생각이 많이 담긴 글입니다.우선 이 해결 방법으로 취업에 성공한 것은 아니고 반영하여 얼마 전에 이력서, 포폴을 마무리하여 지원을 하고 있는 중이지만프로젝트 진행 전, 중, 후 계속하여 나름 이름 있는 회사의 개발자분들께 직접 커피챗을 요청해 피드백을 받으며 진행하였기 때문에 조금은 도움 되는 부분이 있을 것이라 생각합니다! :]지금까지 프로젝트를 진행하면서 문제를 찾아 해결하고 왜? 문제가 발생했고, 왜? 이 방법으로 해결했는지를 기록하며 취업을 준비했다. 하지만 ..

  • Slack으로 서버 로그 모니터링하기 (Feat. Spring AOP, Logback)

    Slack으로 서버 로그 모니터링하기 (Feat. Spring AOP, Logback)

    프로젝트를 진행하면서 로그는 정말 중요한 요소라는 것을 깨닫고 있다. 예상치 못한 request 형태가 오거나, 서버 내부적으로 오류가 발생하면 로그를 읽고 해결을 계속하고 있기 때문이다. 하지만 ssh로 Ec2에 직접 접속해 로그 파일을 확인하는 것은 여러 불편함이 있어 이를 해결하기 위해 모니터링 툴을 만들어보기로 했다! 과정부터 결과까지 시간의 흐름 순으로 출발~기존 로그의 문제점사진 자체만으로도 문제이다. 일단 ui가 불편하고 음... 그냥 불편하다. 다른 문제점을 정리해 보자면 아래와 같다.에러 로그가 발생해도 실시간으로 확인할 수가 없다. -> 지금은 운영 전 개발용이어서 괜찮지만 실제 운영을 하게 된다면 에러가 발생하면 즉시 해결해야 하는데 위의 사진을 계속 켜놓고 확인하고 있지 않는 이상 ..

  • 이미지 조회 속도 개선 (Feat. CDN, AWS CloudFront, S3만 사용하다가 cloudfront 적용하려면?)

    이미지 조회 속도 개선 (Feat. CDN, AWS CloudFront, S3만 사용하다가 cloudfront 적용하려면?)

    유저 테스트를 끝내고 정식 출시 전에 서버 최적화 및 성능 개선을 하고 있다. 더 할 수 있는 게 뭐가 있을까 생각하던 중 문득 얼마 전에 "가상 면접사례로 배우는 대규모 시스템 설계 기초" 에서 읽은 CDN이 생각나서 사용해 보기로 했다. 마침 우리 어플에서 사진이 늦게 업로드되는 상황이 있어서 아주 적절한 해결책이라 생각했다.CDNCDN은 Content Delivery Network의 약자이며 위에 언급한 책에서 "정적 콘텐츠를 전송하는 데 쓰이는, 지리적으로 분산된 서버의 네트워크이다. 이미지, 비디오, CSS, JavaScript 파일 등을 캐시할 수 있다."라는 설명을 제공한다. 한마디로 정적 컨텐츠에 대한 캐싱을 담당해 준다고 생각할 수 있다. "지리적으로 분산된"이 나타내는 것은 아래의 예시..

  • 프로젝트 진행 시 엑셀에 작성한 데이터, DB에 저장하는 방법

    프로젝트 진행 시 엑셀에 작성한 데이터, DB에 저장하는 방법

    이 글은 프로젝트를 진행하면서 고민했던 부분부터 해결 과정까지가 나름 유의미하다고 생각해서 글로 남겨보려 한다.데이터 가공, 나열 -> 엑셀우리 프로젝트에서는 필요한 데이터를 크롤링하여 엑셀화를 진행한다. 그 이후 기획자분들께서 데이터를 가공하는 과정, 번역하는 과정(4개 국어를 지원하는 서비스이기 때문,,,)을 거쳐서 최종 엑셀 파일이 완성된다.지인 찬스로 외국인 분들께서 번역을 직접 검수해 주시지만 가끔 돌발 상황에서 엑셀 번역기능을 사용할 수도 있었고, 데이터를 정리하는데 엑셀이라는 플랫폼을 선택한다는 것은 고민할 필요가 없었다.이걸 어떻게 데이터 베이스에 저장하지?엑셀에 있는 데이터를 DB에 저장하는 방법을 정하는데 프로젝트 초창기인 3월쯤에 백엔드 팀원분과 많은 토론이 있었다. 여러 가지 방법들..

  • [CS] 대칭키 & 비대칭키 / HTTPS 통신 방법

    [CS] 대칭키 & 비대칭키 / HTTPS 통신 방법

    대칭키와 비대칭키는 데이터 보안 및 통신에서 중요한 역할을 하며, 정보를 안전하게 보호하고 전달하기 위해 사용되는 암호화 기법이다.자세한 내용들보다는 내가 기억하기 쉽게 이해한 과정을 서술해보려 한다. 앞으로 나올 "자물쇠를 잠구는 행위"는 암호화, "자물쇠를 여는 행위"는 복호화를 뜻한다.대칭키암호화하는 키와, 복호화하는 키가 같다고 하여 대칭키라고 불린다. 대칭키 기법을 이해하기 쉽게 한줄로 표현해 보면 아래와 같다.열쇠1로 자물쇠를 잠그고, 받을 사람에게 열쇠1과 자물쇠를 보내준다.대칭키 방식은 간단한 연산을 사용해 암호화를 진행한다. XOR 연산, 치환, 전치 등 단순한 연산으로 암호화를 진행해 빠른 연산이 가능하다. 하지만 암호화, 복호화 시 같은 키를 사용하기 때문에 안전하게 키를 전달하는 부..

  • 서버 재실행 후 첫 Response가 늦게 오는 이유 - JIT Compiler, Class Loader, JVM Warm Up

    서버 재실행 후 첫 Response가 늦게 오는 이유 - JIT Compiler, Class Loader, JVM Warm Up

    스프링 검색어 자동완성 비동기 처리 (Feat. 1만번의 부하테스트 결론은 Over Engineering 이었다고 한검색어 자동완성 구현하기 with Redis (Feat. Elasticsearch)기획 측 요구사항 지난주 스프린트에 검색어 자동 완성 기능이 있었다. 리뷰를 작성하기 위해 장소를 검색하는 부분인데 사용자가 검색어를te-ho.tistory.com Jmeter를 사용한 테스트 도중 특이한 점을 발견했다. 서버를 재실행한 후 API요청을 날리면 Response가 유독 늦게 도착한다는 점이었다. Redis, 비동기 처리를 한 후 진행했던 것이어서 "로직을 잘못 짰나?", "Redis 동작 방식에 문제가 있나?" 하는 생각으로 코드를 계속 고쳐보았지만 결과는 똑같았다. 그 후 구글링, GPT와 심..

  • 스프링 검색어 자동완성 비동기 처리 (Feat. 1만번의 부하테스트 결론은 Over Engineering 이었다고 한다..)

    스프링 검색어 자동완성 비동기 처리 (Feat. 1만번의 부하테스트 결론은 Over Engineering 이었다고 한다..)

    검색어 자동완성 구현하기 with Redis (Feat. Elasticsearch)기획 측 요구사항 지난주 스프린트에 검색어 자동 완성 기능이 있었다. 리뷰를 작성하기 위해 장소를 검색하는 부분인데 사용자가 검색어를 입력하면 해당 검색어가 제목에 포함되어 있는 게시te-ho.tistory.com 저번 포스트에서 redis를 활용해 검색어 자동 완성 기능을 구현하였다. 이미 redis를 사용해 DataBase의 부하는 줄였지만 신경 쓰이는 부분이 있어서 추가적으로 성능 개선을 해보려 했다.신경 쓰였던 기존 로직 사용자가 "티 스 토리" 라는 입력을 했을 경우 로직에 따라 원본, 공백 제거, 공백 기준으로 분리하여 키워드를 가공한다."티 스 토리""티스토리""티", "스", "토리" 이 후 미리 redis에..

  • 멀티스레드? 비동기? (동기, 비동기, 싱글 스레드, 멀티 스레드)

    멀티스레드? 비동기? (동기, 비동기, 싱글 스레드, 멀티 스레드)

    진행하고 있는 프로젝트에서 @Async를 통해 비동기 처리를 하여 성능 개선을 계획 중이다. 관련 공부를 하던 와중에 멀티스레드, 비동기의 차이가 뭐지?라는 질문에 대답을 못하였고 이번 기회에 제대로 알고 가기 위해서 정리해 본다. 우선 결론은 멀티스레드 ≠ 비동기동기, 비동기 VS 단일스레드, 멀티스레드 동기, 비동기 -> 작업(Task)에 관한 것 / 단일스레드, 멀티스레드 -> 작업자(Thread)에 관한 것 이 기본 개념이다. 이해를 돕기 위해 라면을 끓여 보겠다(?) (이해를 돕기 위함이므로 맛은 중요하지 않다. 처리 속도, 효율성을 생각해 보자~) Task -> 물 끓이기, 스프 넣기, 면 넣기 / Thread -> teho, 백종원님(이하 백선생) 동기 : 물이 다 끓으면 -> 스프를 다 ..

  • 검색어 자동완성 구현하기 with Redis (Feat. Elasticsearch)

    검색어 자동완성 구현하기 with Redis (Feat. Elasticsearch)

    기획 측 요구사항 지난주 스프린트에 검색어 자동 완성 기능이 있었다. 리뷰를 작성하기 위해 장소를 검색하는 부분인데 사용자가 검색어를 입력하면 해당 검색어가 제목에 포함되어 있는 게시글을 제목, 썸네일 사진 등과 함께 모두 보여줘야 했다. 자세한 내용은 아래와 같다.사용자가 검색 창에 타이핑을 하다가 0.6초 이상 액션이 없으면 지금까지 입력된 검색어를 제목에 포함한 게시물을 요청한다. (이 부분은 프론트 분들이 하실 거라서 딱히 생각할 필요 없다. )예를 들어 "태호 티스토리"를 입력하면 "태호 티스토리" / "태호" / "티스토리"를 제목에 포함한 모든 게시물을 사전 순으로 정렬 ("태호 티스토리"에 대한 검색 결과 사전 순 + "태호"에 대한 검색 결과 사전 순 + "티스토리"에 대한 검색 결과 사..

  • Stream API 사용 중 .toList()에서 UnsupportedOperationException 발생한 썰

    Stream API 사용 중 .toList()에서 UnsupportedOperationException 발생한 썰

    문제상황 검색어 자동 완성을 구현하는 과정에서 keyword를 여러 값으로 나눈 후 (ex: 사용자의 입력이 "teho tistory" 일 경우 {"teho tistory", "tehotistory", "teho", "tistory"} 4개로 키워드를 만들어서 검색어에 맞는 게시물로 자동 완성을 해준다.) redis에서 추천 게시물을 갖고온 후 모든 값을 하나의 리스트에 합치는 과정에서 UnsupportedOperationException이 발생했다. "사용할 수 없는 동작이야" 라는 오류인데 도대체 왜..? 어디서 발생하는 에러인지 한눈에 알 수 없어서 천천히 뜯어보았다. 원인 파악 전체적인 흐름은 메서드(searchByKeyword, searchBykeywordList)에서 keywrod를 포함하는 ..

  • QueryDsl 부모에 자식 리스트 넣기 -> Transform (부제 : 쿼리의 수와 속도는 무조건 정비례가 아니다..)

    QueryDsl 부모에 자식 리스트 넣기 -> Transform (부제 : 쿼리의 수와 속도는 무조건 정비례가 아니다..)

    이번 프로젝트에서는 QueryDsl을 사용하고 있다. 전 프로젝트까지만 해도 JPQL, QueryDsl을 왜 굳이 써야 하는지 감이 잡히지 않아서 Jpa method만 사용하였다. 자세한 내용은 추후 따로 글을 작성할 예정이다. 문제상황웬만한 조회에서 QuerDsl을 사용하고 있었다. 하지만 문제가 발생했는데 보통은 key - value 형태로만 조회를 했다. 그런데 key - list 형태로 조회를 해와야하는 상황이 생겨버렸다. 즉 부모에 자식이 리스트 형태로 들어가야 하는 것이다. 한 이틀동안 뇌피셜을 기반으로 여러 시도를 하다가 실패했다. 다음 작업을 해야 할 날짜가 다가와서 일단 JPA 메서드로 범벅을 해놓고 넘어갔다. 어느 정도 시간이 지나 여유가 생겨서 다시 수정을 해보려고 마음먹었다. JPA..

  • 보상받는 데이터 수집 플랫폼, 픽플리

    보상받는 데이터 수집 플랫폼, 픽플리

    오늘은 프로젝트를 진행하면서 많은 도움이 되었던, 또한 심심풀이 어플로 사용하고 있는 픽플리를 소개해보려 합니다! 보상받는 데이터 수집 플랫폼, 픽플리 대학생들이 프로젝트, 과제를 진행하면서 설문조사를 진행할 때 보통 직접 인스타 홍보, 에브리타임, 지인들에게 일일이 연락을 돌리게 됩니다. 하지만 이런 방법은 시간도 많이 소요되고 최소한의 참여 인원도 보장할 수 없는 경우가 많습니다. 하지만 픽플리(https://pickply.com/)를 사용하게 된다면 이런 걱정은 모두 해결할 수 있습니다!   저도 대학생 연합 동아리 잇타에서 프로젝트를 진행하면서 기획 단계에서 설문 조사가 필요해서 잇타와 파트너를 맺고 있는 픽플리르 처음 활용해보았습니다. 가볍게 진행하고 싶어서 정식 프로젝트 등록이 아닌 커뮤니티 ..

  • 맥에서 MySql, MaraiDB 두개 다 사용하기 (Feat. Docker 이래서 쓰는구나, 맥 mariaDB 설치하기)

    맥에서 MySql, MaraiDB 두개 다 사용하기 (Feat. Docker 이래서 쓰는구나, 맥 mariaDB 설치하기)

    문제의 시작은 이번 프로젝트에서 mariadb를 사용해 보기로 하면서 발생했다. 채용 공고들을 보면 RDBMS 중에는 MySql과 MariaDB가 많은 것 같아 사용해보지 않았던 MariaDB를 데이터 베이스로 선택했다. (maraidb는 mysql에서 파생되어 나온 데이터베이스여서 거의 동일하다고 한다 :]) 어제의 지옥편 맥은 homebrew를 통해 많은 프로그램들을 다운받기에 역시 brew install mariadb를 시원하게 입력했다. 찾아보니 둘은 거의 모든 곳에서 같은 구조를 이루고 있어 같은 로컬에 동시 설치하면 많은 오류가 발생할 수 있다고 했다. 이것을 알고 빠르게 다른 방법을 생각 했어야했는데.. "port를 다르게 설정하면 되지 않을까?"라는 천진난만한 생각으로 이것저것 만지다가....

  • Spring Builder 패턴 제대로 알고 어노테이션 사용하기 (@AllArgsConstructor, @NoArgsConstructor가 필요한 이유)

    Spring Builder 패턴 제대로 알고 어노테이션 사용하기 (@AllArgsConstructor, @NoArgsConstructor가 필요한 이유)

    처음 스프링으로 개발을 할 때는 생성자를 사용한 객체 생성만 사용했다. 여러 코드를 보다 보니 자연스레 builder 패턴에 대해 알게 되었고 지금은 Builder 패턴으로만 객체를 생성하는 것 같다. 이때 @NoArgsConstructor, @AllArgsConstructor를 @Builder와 함께 항상 작성했는데 원리를 정확하게 알고 싶어 공부할 겸 글을 작성한다. (builder와 생성자 방법의 차이점, builder의 장점 등은 생략한다. ) 어노테이션 없이 builder 사용하기 @Builder를 사용하기 전에 어노테이션 없이 builder 패턴을 사용하는 예제를 확인하겠다 public class User { private final String username; private final St..

  • java boolean? Boolean? (feat. boolean 값에 false만 들어오는 이유)

    java boolean? Boolean? (feat. boolean 값에 false만 들어오는 이유)

    문제상황 트렌드 설문 조사를 Get 요청하는 api에 참여 여부에 따라 설문 참여 페이지, 이미 참여한 페이지로 네비게이팅을 해야 하는데 그것을 판단할 수 있는 응답이 추가되어야 한다는 프론트 개발자 분의 요청이 있었다. 그래서 나는 응답으로 유저가 참여한 설문인지를 나타내는 boolean 형 변수 isParticipated를 추가했다. 포스트맨으로 테스트를 진행해 보니 항상 isParticipated에는 false만 담겼다. 프로젝트 막바지에 일어난 예상치 못한 에러는 멘탈에 상당한 데미지를 입혔다.. 정신 차리고 구글링을 해보니 생각해보지도 못한 정보들을 와르르 보게 되었다. 원인 java에는 원시 타입(int, short, char, double)과 참조 타입(Double, Integer, Stri..

  • Spring security + jwt 동작방식 이해하기

    Spring security + jwt 동작방식 이해하기

    이 글은 spring security와 jwt에 대한 개념을 설명하는 글이 아닌 동작 방식을 이해하는데 도움이 되는 글이다. 구현을 당장 해야 한다면 다른 블로그의 글을 보며 복붙을 한 후 읽어보면 동작 방식을 알기 쉬울 것이다. Univey 개발을 진행할 때 코드를 긁어와서 하다 보니 전체적 흐름이 궁금하였기에 이 글을 작성하여 기록을 남긴다. 정의와 이론 부분은 아래 블로그를 읽어보면 도움이 많이 된다. https://wildeveloperetrain.tistory.com/50 Spring Security 시큐리티 동작 원리 이해하기 - 1 스프링 시큐리티 (Spring Security)는 스프링 기반 어플리케이션의 보안(인증과 권한, 인가)을 담당하는 스프링 하위 프레임워크입니다. 보안과 관련해서 ..

  • 잇타 대학생연합 IT동아리 it’s time 4기 활동 간단 후기, 회고(Feat. 팀 불사조 - Univey)

    잇타 대학생연합 IT동아리 it’s time 4기 활동 간단 후기, 회고(Feat. 팀 불사조 - Univey)

    23년도 2학기와 함께 시작했던 나의 첫 대외 동아리 활동이 지난주 토요일 최종 발표와 함께 마무리 됐다. 정신없이 달리느라 쌓아둔 개발 관련 포스팅을 하기 전에 활동을 한번 되돌아보기 위해 이 글을 작성하고 있다. 동아리 전반적인 간단 후기를 작성 후 짧은 회고를 해보려 한다. 대학생 연합 IT 동아리 It's time, 잇타 4기 후기 준비 과정과 면접 내용은 간단하게 23년 회고록에 적어두었기에 생략하려 한다.2024.01.03 - [Scribble] - [회고록] 2023년 돌아보기 [회고록] 2023년 돌아보기하나 둘 졸업, 취업하는 주변 사람들을 볼 때마다 나는 언제 졸업하지라는 생각이 항상 들었는데 어느새 4학년을 시작하는 2024년이 되었다. 2023년을 돌아봤을 때 여전히 최고, 최선은 ..

  • [회고록] 2023년 돌아보기

    [회고록] 2023년 돌아보기

    하나 둘 졸업, 취업하는 주변 사람들을 볼 때마다 나는 언제 졸업하지라는 생각이 항상 들었는데 어느새 4학년을 시작하는 2024년이 되었다. 2023년을 돌아봤을 때 여전히 최고, 최선은 아니었지만(가장 큰 적은 역시 잠이다,,) 나름 계획대로 실행하고 풀린 1년이었다. 23년 시작부터 쌍문동 👵🏻와 새롭게 함께 했다. 개발, 공부 위주의 회고를 작성할 예정이였지만 나에게는 작년에 가장 큰 사건이었기 때문에 기록을 남기고 싶다. 우리가 많이 하는 말 중 하나이기도 하고 둘을 표현하는 가장 적절한 단어 '우당탕탕' 물론 좋은 의미로 우당탕탕이다🤭 함께 해준 덕분에 모든 것에 열정이 넘치게 몰입할 수 있었고 번아웃(올 정도로 뭘 한 것 같지는 않지만 멘탈이 약했던 사람으로서 쓸만한 단어다.)따위는 올 생각도..

  • @ModelAttribute, @SessionAttribute name 속성 차이

    @ModelAttribute, @SessionAttribute name 속성 차이

    강의를 듣다가 @SessionAttribute를 사용했다. 컨트롤러 매개 변수 단계에서 session을 받아오는 역할을 해주었다. 이때 name 속성을 사용했는데 이것저것 건드려보다 @ModelAttribute와 다른 점을 발견했다. 개인적으로 흥미로운 발견이어서 테스트하는 코드를 작성해 보았다. @ModelAttribute의 name 속성 @ModelAttribute는 사용자의 입력 값과 객체를 바인딩 후 model에 담아준다. name 속성을 지정해주면 그에 맞게 model의 이름이 설정된다. name 속성을 사용하지 않으면 클래스의 첫 글자를 소문자로 바꾼 문자를 name으로 설정한다. => member (@ModelAttribute가 클래스 이름인Member를 member로 바꿔 사용하기에 teh..

  • Spring Interceptor, @SessionAttribute 사용하기

    Spring Interceptor, @SessionAttribute 사용하기

    문제 상황 로그인 후 웹 사이트를 이용할 때 로그인이 유지가 되었는지 확인하기 위해 같은 코드를 거의 모든 컨트롤러 메서드에 반복 작성했다. 쓰면서도 이건 뭔가 잘못됐다,,,라고 생각했다. 메서드로 빼려고 하니 모든 컨트롤러에서 사용돼서 아닌 것 같고, 클래스로 따로 만들어 메서드를 작성하자니 기능이 애매해서 나중에 공부하다 보면 방법이 무조건 나올 거 같아서 참아보고 있었다. 심지어 인텔리제이도 몇 번째 같은 코드를 작성 중이라고 표시도 해주었다. HttpSession session = request.getSession(false); if (session == null) { return "redirect:/login"; } User loginUser = (User) session.getAttribute..