반응형

스프링부트에서 메일 발송 기능 구현 중 다음과 같은 에러가 발생하였다.

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mailService': Unsatisfied dependency expressed through field 'javaMailSender'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] 
.
.
.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1646) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1166) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]

 

소스코드

기본적인 maven dependency추가 후 @Autowired했음

 

문제해결

@Bean으로 다음과 같이 protocol, host, port 지정 해줌

    @Bean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();

        javaMailSender.setProtocol("smtp");
        javaMailSender.setHost("127.0.0.1");
        javaMailSender.setPort(25);

        return javaMailSender;
    }
반응형
반응형

스프링부트 with JPA 프로젝트 작업중 신기한게 로컬환경에서는 에러가 안났는데 alpha, real환경에만 배포하면 위와 같은 에러 메세지가 나왔다....

Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Either use @Param on all parameters except Pageable and Sort typed once, or none at all!

문제의 원인이 무었이었는고 하니...

JPA 에서 매개변수 2개를 받는 메서드에 한 변수에만 @Param을 지정해서 사용하여서 발생하였다...

jobId 매개변수에도 @Param을 명시적으로 주니 정상적으로 해결 되었다.

void upsertAnalysisData(@Param("jobId") int jobId, @Param("audience") AudienceAnalysis audienceAnalysis);

혹시나 비슷한 에러가 발생한다면 JPA Repository부분에 특정 매개변수에만 @Param을 주어서 사용하진 않았는지 확인해보자!

반응형
반응형

nginx의 access log가 두 번이나 씌여지는 현상을 발견하여 포스팅 해본다.

location = '/getid'
{
     if ($scheme !~* "https") {
            return 308 https://$host$request_uri;
     } 
    access_log /home1/irteam/dmp_log_collector/nginx/logs/dmp_applog.${hostname} appmlog;
}

위와 같이 request의 scheme이 'http'가 아닌 경우 'https'로 리다이렉트 하도록 되어져 있다.

따라서 http로 요청을 하였을 때는 당연히 acces_log를 안찍을 거라고 생각을 했는데....아니였다.....

nginx는 기본적으로 요청이 들어왔을 때 현재의 스코프내에서 정의되어져 있는 access_log가 있다면 해당 경로에 access log를 남기고 그렇지 않다면 그 상위 스코프에 있는 access_log에 접근해 access log를 남긴다는 것이다. 자바스크립트의 hoisting(호이스팅)과 비슷한 느낌이다.

따라서 'http'요청일 경우 access log를 남기고 싶지 않다면 if 블럭에 'access_log off'를 주어 access log를 남기지 않도록 한다.

location = '/getid' 

     if ($scheme !~* "https") { 
            access_log off;
            return 308 https://$host$request_uri; 
     }
     access_log /home1/irteam/dmp_log_collector/nginx/logs/dmp_applog.${hostname} appmlog;
}

 

자세한 내용은 nginx의 documentation을 참고하자.

Similar to the  error_log directive, the access_log directive defined on a particular configuration level overrides the settings from the previous levels. When processing of a request is completed, the message is written to the log that is configured on the current level, or inherited from the previous levels. If one level defines multiple access logs, the message is written to all of them.

https://docs.nginx.com/nginx/admin-guide/monitoring/logging/

 

NGINX Docs | Configuring Logging

Capture detailed information about errors and request processing in log files, either locally or via syslog.

docs.nginx.com

 

반응형
반응형
Cookie cookie = new Cookie("", "");
response.addCookie(cookie);

쿠키 생성시 위와 같이 name에 빈 값을 넣어 굽게 되면 다음과 같은 에러가 발생한다.

java.lang.IllegalArgumentException: Cookie name may not be null or zero length

고로 쿠키 네임에는 null이나 length가 0인 값이 들어 갈 수 없다!

반응형
반응형

아파치 톰캣 연동 작업을 위해 필요한 톰캣 커넥터(Tomcat connector) 설치 작업 중 다음과 같은 에러가 발생했다.

톰캣 커넥터를 다운받고 tar로 압축을 푼 후 해당 폴더의 native폴더에 들어가 다음의 MakeFile을 만들기 위해 명령어를 실행

./configure --with-apxs=/usr/bin/apxs

다음과 같은 에러 발생

configure: error: in `/usr/local/src/tomcat-connectors-1.2.48-src/native':
configure: error: C compiler cannot create executables

mod_jk를 설치 하려면 gcc, gcc-c++, httpd-devel 세가지 패키지가 설치되어 있어야 한다.

다음과 같이 설치해주고 다시 실행

yum install gcc gcc-c++ httpd-devel

좀 더 자세한 설명이 필요하다면 아래의 포스팅을 확인바랍니다.

https://cionman.tistory.com/26

 

09. 리눅스(CentOS) 개발 놀이터 만들기 - Apache와 Tomcat 연동

블로그가 이전 작업 중에 있습니다.아래의 링크를 클릭하시면 동일한 내용을 보실 수 있습니다. https://suwoni-codelab.com/linux/2017/05/29/Linux-CentOS-Apache-Tomcat/ 안녕하세요~ Apache와 Tomcat의 연동..

cionman.tistory.com

 

반응형
반응형

해당 내용은 '소프트웨어 장인'이라는 책의 Chapter11장의 '잘못된 면접 방식'이라는 주제에서 와닿는 내용 몇 개만 발췌한 내용이다. 많은 분들이 공감할 거라 생각한다. 물론 아닌 분들이 계실수도 있겠지만 그 회사의 그 업무에 맞는 면접질문을 하는게 가장 좋다고 생각한다. 읽어보면서 공감가는 부분과 공감가지 않는 것에는 어떤 것이 있는지 생각해보며 읽으면 좋을 듯하다. 해당 내용들은 내게 공감이 많이 되었던 내용들만 추려 포스팅한 것이다.

1. 똑똑한 척하는 면접관을 세운다.

면접관이 지원자보다 똑똑하거나 더 우월해봉고 싶어해서는 안 된다. 면접관의 사사로운 즐거움을 위해 지원자를 힘든 상황으로 몰아붙이고, 자신의 직함, 권한, 지식같은 것들로 지원자를 압도하고 싶어 해서는 안된다. 어느 정도 경험이 있고 실력있는 개발자라면 면접관의 성향을 즉시 알아채고 같이 일하기 싫다는 생각을 할 것이다. 지원자 앞에서 겸손하고 정직해야 한다. 지원자를 프로페셔널 개발자로서 대하고, 채용을 위한 평가나 취조가 아니라 당신이 존주우하는 누군가와의 유익한 기술 토론이 되도록 면접을 이끌어야 한다. 무엇보다도, 지원자의 이야기를 경청하고 그에게 마음을 여는 것이 중요하다. 

2. 답을 모르는 질문을 한다.

면접관으로서 어떤 질문에 어떤 답변이 나와야 하는지 잘 모르겠다면 채용중인 직무와 관련해서는 그다지 중요한 질문이 아닐 가능성이 높다. 해당 직무에 대해서 잘 알고 있다면 무엇이 중요하고 무엇이 중요하지 않은지 이미 알고 있을 것이다. 엉뚱한 질문으로 지원자를 혼란스럽게 하거나 잘못 이끌지 말자. 팀 동료에게 흔히 하지 않는 질문이라면, 팀 동료가 짜증을 낼 질문이라면, 지원자에게도 삼가해야 한다.

3. 종이에 코드를 작성하게 한다.

지원자에게 종이나 화이트보드에 코드를 작성토록 하는 것은 참으로 바보 같은 면접 방법이다. 면접관 스스로도 할 수 없는 일이나 실제 업무 현장에서 부딪히지 않을 상황을 지원자에게 요구해서는 안된다. 실제 업무에서도 종이에 테스트 코드 작성, 코드 리펙토링을 하는가? 고등학교 교사가 학생들에게 알고리즘의 의사 코드를 작성하라고 하는 것과 프로페셔널 소프트웨어 개발자를 채용하는 것은 다르다. 자신의 도구와 기술을 마스터하고 테스트와 리펙토링을 통해 잘 작성된 코드를 만들 수 있는 개발자를 찾아야한다.

4. 알고리즘 문제를 낸다.

알고리즘 무누제를 코딩 면접 과제로 선택하는 면접관들이 많다. 시스템 개발에 필요한 상당수의 업무들이 알고리즘에 대한 깊은 이해를 필요로 하지 않는다. 그럼에도 불구하고 "지원자의 문제 해결 능력을 보아야 한다"라고들 이야기한다. 물론 틀린 이야기는 아니지만 알고리즘 문제 대신 회사의 실제 프로젝트와 가까운 연습문제를 통해서도 '문제 해결 능력'을 평가할 수 있다. 여러 시스템의 문제들 중 거의 대부분이 알고리즘이 어떻게 작성되었느냐와는 관계가 없었다. 테스트가 덜 되었거나 또는 좋은 테스트 방법이 준비되지 못했거나, 잘못된 설계, 떨어지는 응집성, 깊은 종속성, 새 기능 추가 시 부족했던 리팩토링, 지속적인 요구사항 변경, 도메인 모델이 꼼꼼하지 못했거나 등이 가장 흔한 문제였다. 이러한 것들이 '실전 문제'였다. 알고리즘은 절차적이고 함수적인 형태로 구현된다. 알고리즘을 만들 때 비지니스 도메인 모델이나 클래스를 만들지는 않는다.

시스템의 주요 문제가 알고리즘이 아니라면 코딩 면접 때 알고리즘 문제 대신 실제 문제와 가까운 과제를 제시해야 한다. 지원자가 비즈니스 도메인을 표현하고 솔루션을 설계할 역량이 있는지 집중해야 한다. 테스트 주도 개발이나 설계에 스킬이 뛰어난 개발자를 찾고 있다면 그 부분을 반영할 수 있는 코딩 문제를 제시해야 한다. 애플리케이션이 온통 알고리즘에 대한 것이라면 당연히 알고리즘 개발 역량을 평가해야 한다. 요지는 코딩 면접에 알고리즘 문제를 내야 하느냐의 여부가 아니라 프로젝트를 위해 실제 필요한 역량이 무엇인지, 무엇이 가장 가치 있는지를 면접용 코딩 문제에 잘 반영하고 있어야 한다는 것이다.

반응형
반응형

해당 내용은 '실무로 배우는 시스템 성능 최적화'의 내용중 일부를 발췌한 내용입니다. 웹 방화벽에 의한 성능 저하 사례로 방화벽으로 인해 이러한 문제가 발생할 수 있구나 정도로 인지하고 있다면 비슷한 이슈가 발생했을 때 보다 빠르게 대응을 할 수 있을 거라 생각되어 남겨 봅니다.

현상

전국에서 사용하는 시스템으로, 특정 지역의 윈도우7 사용자만 화면 응답시간이 급격히 느려져 1분 이상 소요되는 현상이 발생했다. 그러나 항상 느린 것은 아니고 동일한 화면도 느릴 때와 빠를 때가 있는데 대부분은 느렸다.

접근 방법

현상을 정확히 확인하기 위해 해당 기관을 방문해 직접 화면을 사용하면서 네트워크 패킷을 수집해서 분석했다. 화면이 느릴 때는 HTTP 요청에서 TCP 재전송이 발생하면서 지연되는데, 결국은 서버로부터 HTTP 요청에 대한 ACK를 받지 못하고 타임아웃인 1분에 걸려서 해당 TCP 세션을 강제로 끊고 새로운 TCP 세션을 맺어 HTTP 요청을 보내어 응답을 받음으로써 1분 이상 소요됐다.

그런데 이상한 것은 아파치 웹 서버의 Keepalive 타임아웃이 5 초인데 사용자단 브라우저 TCP 세션은 5초가 이상 지나도 계속 ESTABLISH 상태를 유지하고 있고, 느릴 때는 5초 이상 경과된 TCP 세션을 사용하고 있었다. 그러나 웹 서버에서는 Keepalive 5초가 경과해서 해당 TCP 세션을 끊기 위해 FIN을 보냈음에도 클라이언트로부터 FIN을 받지 못하고 있는 TIME_WAIT 상태였다.

따라서 클라이언트와 웹 서버 사이 어디에선가 웹 서버가 보낸 TCP 세션 종료 신호인 FIN 패킷을 삼키고 있는 것으로 판단했다. 이런 현상이 특정 기관 사용자에게서만 발생하고 있어 해당 기관 내부 네트워크 이상으로 판단했다. 그러나 웹 서비스의 대표 IP인 L4의 가상 IP 대신 실제 서버 IP를 사용해 테스트를 진행하면 웹 서버 2대 모두로부터 정상적으로 클라이언트가 FIN 패킷을 받았다. 이에 L4 가상 IP 사용과 실 서버 IP 사용 시 발생하는 차이가 웹 방화벽 경유로 기인했음을 확인하고 L4 가상 IP를 사용하더라도 웹 방화벽을 경유하지 않도록 네트워크 설정을 수정해 다시 테스트를 진행한 결과, 웹 서버가 보낸 FIN 패킷을 클라이언트가 정상적으로 받는 것이 확인됐으며, 화면 응답시간도 정상이었다.

원인

웹 서버는 Keepalive 5초가 경과한 TCP 세션을 끊고 있으나 FIN 패킷이 클라이언트에 전달되지 않아 클라이언트는 웹 서버가 close한 세션을 살아있다고 생각하고 해당 TCP 세션으로 HTTP 요청을 전송함으로써 이상을 감지하기까지 오래 걸려 화면 지연이 발생했다. 웹 방화벽에서 웹 서버가 보낸 FIN 패킷을 삼킨 것으로 테스트에서 확인했다.

반응형
반응형

DSR(Direct Server Return)

:DSR 구조는 L4가 서버들의 로드밸런싱은 하지만 리턴은 서버에서 클라이언트로 바로 리턴 되는 구조

SLB(Server Load Balancing)

:클라이언트의 request와 서버의 Responnse가 둘다 L4를 거쳐 나가는 구조.

 

반응형
반응형

가상메모리에 대해 설명하기 앞서 자바 기반 솔루션의 경우 설정한 최대 힙 메모리 이상을 사용하지 않기 때문에 최대 힙 메모리가 운영체제의 메모리를 넘기지 않도록 설정됬다면 운영체제의 메모리 부족이 발생할 가능성은 낮다. 하지만 한정된 힙 메모리 내에서 동작하기 때문에 대량의 데이터 처리와 빈번한 GC로 인한 성능 저하가 유발될 가능성이 있다. OS 메모리 용량이 많아 힙 메모리를 과하게 크게 설정한 경우에는 메모리를 청소하는 GC 작업으로 순간 순간 멈추는 시간이 길어져 서비스 안정성이 떨어질 수도 있다.

오라클 버퍼 캐시처럼 데이터베이스는 디스크에서 데이터를 읽어옮으로써 발생하는 성능 저하를 개선하기 위해 메모리에 최근에 사용한 데이터 블록을 캐시해서 재사용하는 알고리즘이 있다. 통상 이 버퍼에 대한 캐시 적중률은 90%이상 나오는 것이 일반적인데, 캐시의 메모리 크기가 너무 작게 설정된 경우 캐시 적중률이 떨어져 디스크에서 데이터 블록을 읽어와야 하는 ㅂ니도가 늘어나 성능 저하를 유발할 수도 있다. 반대로 캐시를 크게 설정해 운영체제에서 스왑이 발생하게 되면 오히려 작게 설정한 것보다 성능이 더욱 악화되어 서비스가 거의 멈추는 상태가 유발될 수도 있다.

Virtual Memory(가상메모리)

서버는 설치할 수 있는 메인 메모리 (Main memory, Physical memory)에 한계가 있고, 예상치 못하게 메모리 사용량이 크게 증가할 수도 있지만 메모리는 비싼 자원으로 언제 발생할지 모르는 상황에 대비해 메모리를 충분히 확보하기 어렵다. 그래서 운영체제는 위와 같은 제약사항을 극복하기 위해 상대적으로 값싼 디스크를 보조 메모리로 사용하는 방식을 사용하고 있다. 디스크의 일정 공간을 할당해 보조 메모리 용도로 사용하는데 이를 페이징스페이스라고 한다. 

메인 메모리(주 기억장치)와 디스크의 페이징스페이스(Pagingspace, 보조 기억장치)를 묶어 하나의 메모리처럼 동작하게 함으로써 메인 메모리 한계를 넘는 메모리 사용을 가능하게 하는 것이 가상 메모리다.

운영체제에서 관리하는 메모리 액세스 단위를 페이지(page)라고 하며 통상 4KB 단위다. 이 페이지 단위로 일부는 메인 메모리에 있을 수도 있고 또 일부는 페이징스페이스에 있을 수도 있는 것이다.

프로세스 내에서 사용 중인 가상 메모리 주소만 봐서는 해당 페이지가 메인 메모리에 있는지 페이징스페이스에 있는지 확인할 수 없다. 그렇다고 페이징스페이스가 메인 메모리와 동일한 것은 아니다. 메인 메모리의 입출력 속도가 디스크에 비해 비교가 안 될 정도로 우수하기 때문에 프로세스가 기동되면 기본적으로 메인 메모리를 사용하다가 부족해지면 페이징스페이스를 사용하게 된다. 이때도 CPU가 페이징스페이스에 있는 데이터를 메인 메모리처럼 바로 사용할 수 있는 것이 아니라 사용 빈도가 낮은 프로세스의 메인 메모리 사용 부분을 페이징스페이스 부분으로 옮겨 여유 메모리를 확보한 후 사용할 페이징스페이스 부분을 메인 메모리로 로드해서 사용하는데, 이를 스와핑이라고 한다. 그래서 CPU가 직접 접근할 수 있는 메인 메모리를 활성 가상 메모리(Active virtual memory)라 하고, 페이징스페이스를 비활성 가상 메모리(Inactive virtual memory)라고 한다. 

가상 메모리 주소는 프로세스 내에서만 유효한 주소다. 각 프로세스는 가상 메모리 주소와 실제 주소 간의 매핑 테이블 (Virtual-to-physical translation table)을 가지고 있어 가상 메모리 주소로 실제 주소를 찾아갈 수 있게 돼 있다. 실제 주소는 메인 메모리와 페이징스페이스의 주소를 가리킨다. 

 

해당 글은 '실무로 배우는 시스템 성능 최적화'의 메모리 부분에서 발췌한 내용입니다.

반응형

+ Recent posts