최근에 회사 서비스에 AWS X-RAY를 적용하면서 요청 파라미터에 대한 정보를 트레이스 하려고 Reflection을 이용해서 파라미터의 변수이름과 값을 조회했는데 파라미터 값은 잘 나왔는데 변수이름이 'arg0', 'arg1' 이런식으로 나왔었다. 스프링 부트 환경의 서비스에서는 파라미터 이름이 정상적으로 나왔는데 스프링 부트가 아닌 XML 기반설정의 스프링 환경에서 저렇게 나왔었다. 문제원인은 해당 애플리케이션을 빌드할 때 컴파일 옵션을 추가해야하는데 추가가 안되있어서 발생된 것이다. 코드를 한번 살펴보자 예제 helloWorld 메서드의 첫번째 매개변수엔 String 타입의 message라는 이름의 매개변수가 있는데 이 message라는 이름을 출력하고 싶어서 다음과 같이 코드를 작성했는데 결과는 ..
프로젝트 환경 JAVA 17 Spring Boot 2.6.2 Intellij 2021.1 내용 JAVA 버전을 11에서 17로 변경 후 애플리케이션을 실행하니 OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release 라는 경고메세지가 출력되었다. 경고메세지를 확인해보니 해당 옵션은 JDK 13이상부터는 더이상 사용되지 않으며 향후 릴리스에서 제거될 가능성이 있다고 하는데 애플리케이션이 정상적으로 실행이 되는거 보면 문제는 없겠지만 찝찝해서 지워야겠다는 생각을 했다. Edit Configurations를 클릭 ..
회사 소스코드 application.yml 설정파일을 보면 데이터베이스 접속정보, api키값 등 보안에 민감한 데이터가 있어서 이러한 데이터를 외부에서 직접 주입 할 수 있도록 구성하려고 이것 저것 알아보다가 AWS 서비스중 하나인 Parameter Store 에 대해 알게되었는데 비용도 무료고 괜찮아 보여서 적용해보도록 하였다. Spring Boot 환경에서 AWS Parameter Store를 적용하는 블로그 글들은 많이 봤지만 Spring Boot 2.4 이상 환경에서 적용하려고 했지만 제대로 동작하지는 않았다. 여기를 보면 Spring Cloud 버전과 호환되는 Spring Boot 버전을 확인할 수 있는데 버전을 맞춰도 안되는건 마찬가지 였다. 필자는 Spring Boot 버전이 2.6이어서 호..
최근에 회사에서 AWS CloudWatch Log를 이용하여 애플리케이션에서 발생되는 로그를 볼 수 있게끔 구성하였다. 이번에는 애플리케이션이 처리하는 요청/응답에 대한 데이터를 수집하고 또 수집되는 과정에서 오류가 발생 시 원인을 쉽고 간편하게 파악할 수 있는 AWS X-RAY에 대해 알아보도록 하자. 그리고 CloudWatch에서는 CloudWatch ServiceLens라는 걸 제공해주는데 CloudWatch ServiceLens는 지표, 로그, 경보, 기타 리소스 상태정보를 한 곳에서 관리할 수 있으며 AWS X-RAY와 통합하여 애플리케이션에 대한 전체적인 서비스맵을 제공하여 한눈에 볼 수 있도록 기능을 제공한다. AWS X-RAY를 JAVA 웹 애플리케이션에 적용하기 위해서는 X-RAY SDK..
AWS EC2 인스턴스의 상태가 실행되거나 혹은 서버가 다운되었을 경우 이메일로 알람을 받아보는 기능을 구현하고자 한다. 공식문서를 보면 내용자체가 이해하기 어렵고 옛날자료들이 있다보니 정상적으로 돌아가지 않는부분도 있다. 그래서 이번에 삽질했던 내용으로 정리하고자 한다. 순서대로 정리하니 잘만 따라오면 문제없이 구현할 수 있다. ㅎㅎ AWS EC2 인스턴스 생성 EC2 인스턴스 생성하는 방법은 여기를 보면 상세히 적어두었다. 여기에서 보안그룹 설정 및 키페어로 접근하는 과정도 나오는데 이번에는 그부분은 생략하고 단순히 생성만 해두자. AWS SNS 주제 및 구독 생성 AWS Management Console에 들어가서 SNS이라고 검색후 접속하면 다음과 같은 화면이 나온다. '주제 생성' 버튼을 클릭하..
Spring에서 Controller의 메서드에 예외가 발생되면 @ControllerAdvice가 선언된 클래스가 동작하여 발생된 예외타입에 맞는 메서드가 호출된다. 그리고 그 메서드 내부에는 개발자마다 다르겠지만 e.printStackTrace()를 호출하는 코드가 작성되있는 경우가 있다. 혹은 특정 로직을 try/catch로 감싸서 처리할 경우 catch 블록에도 e.printStackTrace()를 호출하는 코드가 작성되있는 경우가 있다 그러나 e.printStackTrace()는 특히 운영환경에서는 지양해야될 요소이며 이유는 다음과 같다. JAVA의 Reflection을 이용하여 예외를 추적하는 것이라 많은 오버헤드가 발생할 수 있다. 메서드 스택정보를 취합하기 때문에 서버 부하의 원인이기도 하다...
이번글에서는 Spring 애플리케이션에서 발생된 로그를 AWS Cloud Watch로 전송하는 방법에 대해 알아보자. 그전에 Spring 애플리케이션에서 AWS Cloud Watch로 로그를 전송하려면 CloudWatchLogsFullAccess 라는 Role을 가진 IAM 사용자의 액세스 키, 시크릿 키가 존재해야 한다. IAM 사용자를 추가하고 Role을 부여하는 방법은 여기를 참고하자. 프로젝트 환경 JAVA 11 Spring Boot 2.6.2 Maven AWS Log Appender 라이브러리 추가 Maven ca.pjer logback-awslogs-appender 1.6.0 Gradle implementation group: 'ca.pjer', name: 'logback-awslogs-app..
Spring에서는 @Component(@Controller, @Service, @Repository)을 이용하여 Bean을 생성할 수 있는데 이때 해당 클래스 내부의 메서드에 Proxy 기반으로 동작하는 어노테이션이 존재할 경우 target class 타입의 Bean이 아닌 Proxy로 래핑된 Bean이 생성된다. @Transactional, @Async, @Cacheable 등 이런 어노테이션들은 런타임 시 target class를 Proxy가 래핑하여 로직을 처리하는데 사용 시 주의할 점이 있다. 한번 살펴보자 Proxy Bean 생성 @Service 어노테이션으로 Bean을 생성 후 @Async 어노테이션으로 Future타입의 결과값을 반환하는 메서드를 선언하였다. 그리고 외부에서 접근이 가능한 S..
Java 애플리케이션을 AWS EC2에 배포하고나면 자주 발생되는 문제중 하나가 바로 타임존문제다. 타임존 문제는 쉽게 얘기해서 현재 시간과 서버의 시간이 맞지않아 현재날짜를 출력했을 때 이전 또는 이후의 시간이 출력되는건데 EC2 같은경우는 타임존이 UTC이고 한국은 타임존이 KST이다 KST는 UTC보다 9시간이 빠르기 때문에 Java 애플리케이션을 EC2에 배포하고 현재시간을 확인해보면 -9시간된 시간이 출력된다. 이 부분은 EC2에 배포할 때 간단하게 해결할 수 있다. 현재시간 출력 로컬에서 현재시간을 출력하는 애플리케이션을 개발하여 EC2에 배포해보자. JVM 파라미터 추가 EC2에 배포후 해당 Jar파일을 실행하면 현재시간보다 -9시간이 되서 나오지만 JVM 파라미터 중 user.timezon..
평소에 즐겨보는 개발자 유튜버 '치얼스헤나'님이라고 계시는데 이분의 유튜브 인터뷰에 출연하였습니다. 치얼스헤나님의 유튜브 영상들의 댓글들을 보면 신입개발자 및 국비교육생분들이 많다는 걸 느꼈습니다. 그런데 댓글을 읽으면서 개인적으로는 안타깝다 라고 느낀점이 있습니다. 1. 비전공인데 국비의 학습내용이 어려워 진도를 따라가지 못해서 멘탈이 붕괴되거나 2. 취업준비를 어떻게 해야 좋을지 3. 어떤방식으로 학습을 해야 좋을지 이런 댓글들이 있었는데 그걸 보니까 과거 저의 모습이 생각났습니다. 저 또한 위 3가지 케이스의 상황을 겪었습니다. 그래서 위 케이스들의 상황이 나에게 닥쳐올 때 어떻게 해야 극복해 나갈 수 있는지 이 영상을 봐주시는 국비교육생 & 개발자 취준생분들에게 조금이나마 도움이 되고자 영상에 출..
오늘 회사에서 운영하는 서비스에 장애가 발생되었는데 로그를 확인해보니 NullPointerException이 발생되었다. 그래서 해당 예외가 발생된 코드를 확인해봤는데 null값을 참조하여 코드를 작성한건 아니었다. 하지만 NullPointerException은 null값이 참조된 인스턴스의 필드 or 메서드를 호출한 경우 외에 다른상황에서도 발생될 수 있는데 그 케이스에 대해 알아보자. NullPointerException (1) str이라는 String 타입의 변수에 null을 할당하고 charAt() 메서드를 호출한 결과 NullPointerException이 발생되었다. str이라는 변수에 null이 할당됨으로써 객체의 주소값이 메모리상에서 제거되어 참조할 수 없는 값이 할당되었기 때문에 Null..
백오피스의 신규기능을 추가해달라는 운영팀의 요구사항이 들어와서 해당기능을 구현했다. 해당 기능은 상세페이지에서 해당 내용과 관련된 파일들을 S3에 업로드하는 기능이었는데 파일의 용량은 적었지만 갯수가 최대 15개까지 업로드가 되야했다. 문제는 파일을 업로드 하고 업로드된 파일을 서버에 전송할 때 서버에서 처리하는 시간이 2 ~ 2.5초 내외로 걸리다 보니 바로 응답이 오지 않아 운영팀에서는 로딩바를 추가해달라고 요청이 들어왔다. 하지만 나는 백엔드 개발자다보니 로딩바를 추가하는 것 보다 서버에서 처리속도를 개선하고 싶어서 어떻게 하면 빨리 처리될 수 있을까 고민을 하다가 비동기 방식의 멀티쓰레드를 이용해서 처리하면 아무래도 하나의 쓰레드로 모든 요청을 처리하는 것 보단 시간이 오래걸리는 작업들은 별도 쓰..
MongoDB는 Collection에 데이터를 생성, 조회, 삭제, 수정할 수 있는 명령어를 지원하고 JavaScript처럼 변수에 데이터를 할당해서 저장할 수 있다. 먼저 insert에 대해 다뤄보자. insert 명령어는 3가지를 제공한다. insert - 단일 or 다중의 Document를 생성 insertOne - 단일 Document를 생성 insertMany - 다중의 Document를 생성 Collection 데이터 저장하기 object = {"name":"kimjonghyun", "age":28} db.developers.insert(object) db.developers.find() object 변수에 이름과 나이를 저장 후 insert함수 인자로 넘겨 insert를 실행하고 조회한 결과..
이번장에는 MongoDB에서 Database와 Collection을 다루는 기본적인 명령어를 알아보자. Database 생성 use 데이터베이스명 생성할 데이터베이스명을 입력한다. 생성 후 해당 데이터베이스를 바라보게 된다. Database 조회 (1) db 현재 연결된 데이터베이스명을 출력한다. Database 조회 (2) show dbs 존재하는 데이터베이스 목록을 출력한다. 위 목록에서 생성된 데이터베이스가 나오지 않은 이유는 컬렉션이 존재하지 않기 때문이다. Collection 생성 db.createCollection("생성할 컬렉션 명"); 생성할 컬렉션 명을 입력한다. RDBMS에서는 테이블 생성과 같은 개념이다. 다시한번 show dbs 명렁어를 실행하니 생성된 컬렉션이 출력되었다. Coll..
JAVA로 Thread 관련 프로그래밍을 학습하다보면 start() 메서드와 run() 메서드를 보게되는데 두 메서드를 실행하게되면 Thread의 run() 메서드를 실행하게 된다. 다만 이 두 메서드의 동작방식을 제대로 이해하지 못하고 사용하면 프로그램이 원치않게 실행 될 수 있다. 이 두 메서드의 동작방식의 차이를 한번 살펴보자. Thread.start() main 메서드에 현재 실행된 Thread 이름을 출력하고 Thread 인스턴스를 5개 생성한다. 인스턴스 생성시 생성자로 Runnable 타입을 주입해준 후 start() 메서드를 실행하였다. 출력결과로 main Thread와 Thread 인스턴스 5개가 출력된 걸 확인할 수 있다. Thread.run() 이번에는 run() 메서드를 실행해보았다..
이번에는 AWS RDS 인스턴스를 생성해보자. RDS에 대해 잘 모른다면 아래링크를 참조하자. https://aws.amazon.com/ko/rds/ AWS 콘솔접속 AWS에 로그인하여 콘솔화면 검색창에 RDS를 검색해서 들어간다. AWS RDS 인스턴스 생성 데이터베이스 생성버튼을 눌러준다. 손쉬운 생성을 선택하게되면 DB엔진만 선택 후 RDS 인스턴스를 생성할 수 있으며 추가설정은 인스턴스 생성이후에 가능하다. 이 글에서는 설정들에 대한 정보를 알아보기 위해 표준생성을 선택한다. 연습용이기 때문에 프리티어를 선택한다. DB 인스턴스 식별자는 AWS 계정이 소유하는 모든 DB 인스턴스에 대한 고유이름을 작성한다. 마스터 사용자 이름과 암호는 DB 인스턴스생성 후 접속하기위한 마스터 접속정보를 적는다. ..
Spring Boot로 애플리케이션을 개발하다보면 데이터베이스 접속정보, AWS accessKey와 secretKey 등 중요한 정보는 application.properties(yml)에 값을 세팅하고 개발하게되는데 이런 정보들이 그대로 노출되면 위험하기 때문에 외부에서 애플리케이션을 실행할 때 넣어주는게 안전하다. 테스트할 코드 작성 해당코드는 application.properties에 secret-key라는 key값에 임의의 값을 세팅하고 Controller에서 @Value 어노테이션으로 해당값을 주입받아서 Get 요청을 보내면 그 값을 리턴한다. 이제 해당 값을 외부에서 주입해보자 Command line arguments application.properties에 secret-key라는 key값엔 ..
Spring의 Controller 클래스도 Spring Bean이고 Spring Bean은 기본적으로 싱글톤인데 어떻게 수많은 요청을 Thread-Safe하게 처리가 가능한지 궁금했다. 그런데 이 문제에 대한 답은 JAVA 메모리 구조를 공부했으면 금방 이해할 수 있을 것이다. @RestController public class UserController { @PostMapping("/users") public void save(User user) { ... } } 위 코드는 사용자의 정보를 저장하는 Controller의 save 메서드가 있다. 동시에 여러개의 요청이 들어오면 Tomcat은 내부적으로 다음과 같이 요청을 처리한다. 요청이 들어온 순서대로 Queue에 담는다. ThreadPool에 현재 ..
Spring으로 개발하면 @Controller, @Service, @Repository 등의 어노테이션으로 Bean을 생성할 수 있는데 그렇다면 Bean을 생성할 때 어떤 클래스를 Bean으로 생성해야하는 것 일까? 그건 바로 값들을 담는 클래스가 아니라 작업을 하는 클래스를 Bean으로 생성해야한다. 예를들어 유저의 정보를 담고 있는 User클래스가 있고 유저의 정보로 관련된 작업을 하는 UserController클래스가 있다고 할 때 UserController는 Bean으로 등록해야하고 User클래스는 Bean으로 등록하지 않는다. @RestController public class UserController { @PostMapping("/users") public void save(User user..
MongoDB Atlas MongoDB를 설계한 사람들이 만든 모든 것을 관리하는 클라우드 데이터베이스이며 AWS, Azure, GCP를 통해 배포에 관한 모든 것을 통합 관리해준다. 이번글에는 Windows 환경으로 설치하는법에 대해 정리한다. Linux나 Mac OS에서 설치하시는분들은 아래링크를 참고바란다. MongoDB install (Mac OS) MongoDB install (Linux) MongoDB install (Windows) MongoDB Atlas 접속 & 클러스터 생성 여기를 눌러 메인화면으로 이동후 Get started now 버튼을 클릭한다. 구글로그인 or 회원가입을 진행한다. 필자는 구글로그인으로 진행하니 구글로그인 버튼을 클릭한다. Build a Database를 클릭한다..
MongoDB에는 ObjectId 타입을 지원하는데 RDBMS에서 Primary Key와 같은 고유한 키를 의미한다. Collections에 데이터를 넣을때 ObjectId를 직접 넣어주지 않는 이상 자동으로 값이 부여되며 모든 Document 들은 각각의 ObjectId가 생긴다. 만약 ObjectId를 형식에 맞지않게 넣는다거나 중복된 값을 넣게될 경우 예외가 발생된다. ObjectId 위 사진은 MongoDB Client 툴인 Mongo Compass에서 Document를 조회한 사진이다. 위 사진을 보면 _id 라는 이름의 Field를 확인할 수 있는데 모든 Document의 식별자 값은 _id 라는 이름의 ObjectId 타입 Field가 생성된다. ObjectId의 구조는 밑의 사진에서 볼 수..
NoSQL NoSQL은 Not Only SQL이라는 의미인데 RDBMS가 갖고있는 특성뿐 아니라 다른 특성들을 부가적으로 지원한다는 것을 의미한다. NoSQL의 특징중 Schema-less 하다는 특징이 있는데 다음사진을 보자 위 그림처럼 Schema-less 하다는 특징을 가지고 있어서 데이터를 원하는 타입으로 자유롭게 넣을 수 있다. 그래서 불필요한 join을 최소화 시켜줍니다. NoSQL의 장점 불필요한 join의 최소화 Schema-less 구조로 설계비용 감소 분산처리 및 병렬처리 가능 이러한 NoSQL은 여러종류가 있지만 그중에 대표적으로 많이쓰이는게 Key-Value 구조인 Redis, Document 구조인 MongoDB가 있다. MongoDB MongoDB는 NoSQL의 특성을 지니고 있..
클라우드를 공부하게되면 면접에서 나올법한 질문인 Container와 VM에 대한 설명을 정리해보고자 한다. Container 애플리케이션 중심으로 설계가 되었으며 컨테이너는 별도의 OS나 드 라이버 없이 호스트를 공유하는 형태로 실행된다. VM이 서버를 여러대로 사용할 수 있게 해주었다면 컨테이너는 애플리케이션을 독립적으로 실행해주기 위해 가상 공간을 할당해준다. VM보다 작은단위이며 처리하는 일도 적기 때문에 보다 간단하고, 빠르고, 효율적으로 애플리케이션을 실행시킬 수 있다. 대표적인 컨테이너는 Docker가 있다. VM 컴퓨터 환경을 가상화하여 소프트웨어로 구현한 것이다. VM은 서버, 호스트, Hyper-v 위에 올라가고 OS, 드라이버, 메모리 등 컴퓨터 환경이 구성되기 위한 필요요소들을 갖춰진..
기존 Spring 애플리케이션 환경을 구축할 때 주로 XML파일을 기반으로 개발에 필요한 모든설정을 잡아줬다. 가령 Spring MVC로 개발환경을 구성할 때 servlet-context.xml과 root-context.xml에 세팅하는데 설정을 잘못해서 예외가 발생하면 디버깅이 힘들었고 구축하는데에도 많은시간이 걸렸다. 그리고 컨트롤러에서 View를 렌더링 하는게 아닌 JSON 데이터를 전달하려고 할 때 jackson 라이브러리를 디펜던시에 추가해줘야하고 프론트에서 텍스트데이터가 아닌 파일형식의 데이터를 받아줄 때도 Multipart 디펜던시도 추가해줘야 한다. 이처럼 개발할 때 필요한 디펜던시들을 개발자가 하나하나 직접 찾아가면서 Spring 프로젝트 버전에 호환되게 등록해줬어야 했고 이러한 개발자의..
저번장에 정리했던 Dockerfile에서 주로쓰이는 명령어 내용을 참고하여 Spring Boot 애플리케이션을 생성후 Docker 이미지로 빌드후 실행해보자 Spring Boot 애플리케이션 생성 환경은 JAVA 11, Spring Boot 2.5.5 버전이고 Web 의존성만 추가하자 포트번호를 8000으로하고 간단한 컨트롤러 클래스를 생성해보자. 근데 컨트롤러의 hello 메서드에는 docker-app 이라는 이름의 환경변수에 해당하는 값을 조회하는데 이따가 Docker 이미지를 빌드할 때 컨테이너 내부에 docker-app 이라는 환경변수를 추가해줄 것 이다. 그리고 포트번호 또한 빌드할 때 명령어로 추가해줄 것 이다. Dockerfile 작성 FROM openjdk:latest ARG port EX..
우리가 개발한 애플리케이션을 Docker image로 build하려면 "Dockerfile" 이라는 이름의 파일을 작성해주어야 하는데 이 Dockerfile에는 Docker 이미지로 build하기위해서 어떠한 명령어들을 수행해야하는지 명령어가 적힌 파일이다. 해당 명령어를 모두 처리하면 Docker 이미지로 build할 수 있다. 이제 주로 쓰이는 명령어들을 알아보자. FROM FROM 이미지명:태그명 어떤이미지를 사용할 것인지 이미지명과 태그명을 적는다. 보통 Dockerfile의 최상단에 위치하는 명령어이다. 이미지명과 태그명은 도커 헙 공식문서 에서 확인할 수 있다. 예를들어 openjdk 이미지의 최신버전을 사용하기 위해서는 FROM openjdk:latest 라고 적어주면 되고 터미널에서 실행할..
Docker 도커는 컨테이너 환경에서 독립적으로 애플리케이션을 실행할 수 있도록 컨테이너를 만들고 관리하게 해주는 컨테이너 도구입니다. 컨테이너는 하나의 운영체제 커널에서 다른 프로세스에 영향을 받지 않고 독립적으로 실행되는 프로세스를 의미합니다. Docker를 사용해야 하는 이유 예를들어 N개의 운영체제에 동일버전의 웹서버, WAS, JAVA, DB를 설치해야한다고 가정할 때 각 운영체제에 접근해서 설치를 해야하고 추후에 서버가 증설될 때도 그 서버에도 위에 설치했던것들을 해줘야하는 반복적인 작업을 해야만 했습니다. 하지만 Docker를 이용하게되면 명령어 단 몇줄로도 간편하게 서버를 구축할 수 있습니다. Docker의 장점 손쉽게 애플리케이션 환경구성을 할 수 있습니다. 운영체제 환경에 관계없이 독립..
JAVA 11이 설치된 환경에서 Maven을 설치할 때 JAVA 버전이 8로 내려가는 현상을 겪게되었다. 아래사진을 보자 JAVA 버전확인 현재 JAVA는 11이 설치되있다. 이제 Maven을 설치해보자. Maven 설치 Maven을 설치하니 3.0대 버전이 설치되었고 JAVA 버전도 8로 바뀌었다. Maven 설치할 때 JAVA 8 관련 디펜던시도 설치하는데 아마 이때 바뀐듯 모양이다. 다시 JAVA 11로 바꿔주자. alternative 명령어로 java 관련 심볼릭링크 생성된 걸 확인해보니 8과 11 두개가 생성되있고 현재 8버전으로 적용이 되있다. JAVA 11로 바꾸기 위해선 심볼릭링크에 해당하는 번호를 선택해서 위 처럼 적용해야한다. 그리고 다시 JAVA 버전을 확인해보니 11로 적용되었다. ..