Java Singleton Class

2019/03/11 21:45
일반적으로, 메모리에 하나의 Instance만 로딩되도록 해야 하는 경우 Singleton Pattern을 적용한 Singleton Class를 사용한다.

하지만, 대용량의 트래픽이 발생하는 Concurrent Request 환경에서는 하나의 Request가 곧 하나의 Thread를 실행하게 된다. 그런 경우, Singleton Class는 Thread-Safe하지 않게 될 수 있다.

원치 않게 각 요청에 따른 올바른 Response를 주지 못하고, 데이터가 꼬여 다른 결과를 리턴하게 되는 치명적인 결과가 초래될 수 있다.

모든 경우와 같이, Singleton Class를 제공하는 경우에도 다음과 같은 고려가 필요하다.

- 동시에 여러 개의 요청이 오더라도 순서대로 처리할 수 있어야 한다.
- 최대한의 성능을 고려해야 한다.
- 여러 요청으로 인해 병목이 발생하더라도 다른 작업을 처리하고 있는 Thread에 영향을 최소화해야 하고, 프로그램이 종료되지 않아야 한다.

Singleton Class 구현 방법은 다음과 같은 방법으로 생각해 볼 수 있다.

<1> Eager Initialization
package com.dev.sample

public class EagerInitSingleton {

private static final EagerInitSingleton = new EagerInitSingleton();
private EagerInitSingleton () {}

public static EagerInitSingleton getInstance() {
return instance;
}
}
Class Loading 시점에 Singleton Class Instance가 생성된다. 가장 쉽게 Signleton Class를 생성하는 방법이지만, Client에서 요청이 없을 때에도 항상 생성되므로 불필요한 리소스를 사용하게 된다. 또한 대부분 파일 시스템이나 데이터베이스에 접속하는 경우 Singleton Class를 사용하는데 Exception을 처리할 수 없다.

<2> Static Block Initialization
package com.dev.sample

public class StaticBlockSingleton {

private static StaticBlockSingleton instance;

private StaticBlockSingleton () {}

static {
try {
instance = new StaticBlockSingleton();
}
catch (Exception e) {
throw new RuntimeException(e.printStackTrace());
}
}

public static StaticBlockSingleton getInstance() {
return instance;
}
}
Static Block은 Eager Initialization Singleton과 비슷하게 Class Loading 시점에 Static Block 안에서 Singleton 객체가 생성되지만, Exception을 처리할 수 있다. 하지만, 동일한 단점을 가지고 있다.

<3> Lazy Initialization
package com.dev.sample

public class LazyInitSingleton {

private static LazyInitSingleton instance;

private LazyInitSingleton() {}

public static LazyInitSingleton getInstance() {

if (instance == null) {
instance = new LazyInitSingleton();
}

return instance;
}
}
Single Thread 환경에서 잘 동작한다. 하지만, 동시에 여러 개의 Thread가 접근할 경우 여러 개의 Instance가 생성될 수 있다. 그런 경우 Singleton Pattern이 깨지고, 서로 다른 Singleton Instance를 사용하게 될 수 있다.

<4> Thread-Safe Singleton
package com.dev.sample

public class ThreadSafeSingleton {

private static ThreadSafeSingleton instance;

private ThreadSafeSingleton() {}

public static synchronized ThreadSafeSinfleton getInstance() {

if (instance == null) {
instance = new ThreadSafeSingleton();
}

return instance;
}
}
synchronized 키워드를 사용하여 한번에 하나의 Thread만 호출할 수 있도록 만들 수 있다. 하지만 모든 Thread의 요청에 대해 synchronized를 실행하므로 성능상 오버헤드가 발생한다.

<5> Double Checked Thread-Safe Singleton
package com.dev.sample

public class DoubleCheckThreadSafeSingleton {

private static DoubleCheckThreadSafeSingleton instance;

private DoubleCheckThreadSafeSingleton() {}

public static DoubleCheckThreadSafeSingleton getInstance() {

if(instance == null) {
synchronized (DoubleCheckThreadSafeSingleton.class) {
if (instance == null) {
instance = new DoubleCheckThreadSafeSingleton();
}
}
}

return instance;
}
}
위와 같은 Double Checked Locking 원리를 이용하면, 조건을 만족시키는 경우 (instance == null) 한 번만 synchronized block이 실행되므로 하나의 Singleton Class Instance만 생성된다. synchronized로 인한 성능 이슈를 해소할 수 있다.

<6> On-demand Holder Idiom에 따른 Inner Class(holder or helper class)를 이용한 Singleton
package com.dev.sample

public class HelperSingleton {

private HelperSingleton() {}

private static class SingletonHelper {
private static final HelperSingleton instance = new HelperSingleton();
}

public static HelperSingleton getInstance() {
return SingletonHelper.instance;
}
}
getInstance() method를 호출 할 때, SingletonHelper 클래스가 생성되고 Singleton intance는 static final 키워드로 인해 한번만 생성된다. 대부분 <6>번의 경우를 많이 사용한다.







CentOS 7.5 Java Home 설정

2019/03/07 21:55
JAVA_HOME 설정

01. 설치 가능한 JDK 버전 확인
yum list java*jdk-devel
02. 설치 가능한 모든 JDK 설치 (6, 7, 8, 11)
sudo yum install -y java*jdk-devel
03. 기본 Java 버전 설정
alternatives --config java
04. Java Home이 설정되어 있는지 확인
echo $JAVA_HOME
05. 없으면 javac 명령어가 지정하는 위치 확인
which javac -> /usr/bin/javac
06. java 명령어가 지정하는 위치는 Symbolic link 이므로 원본 위치 확인
readlink -f /usr/bin/javac -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.201.b09-2.el7_6.x86_64/bin/javac
07. Java Home 설정
echo "export JAVA_HOME='/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.201.b09-2.el7_6.x86_64'" >> ~/.bashrc
source ~/.bashrc

08. Java Home 설정 확인
echo $JAVA_HOME
09. Java Home을 이용한 javac 버전 확인
$JAVA_HOME/bin/javac -version

TAG ,

CentOS 7.5에 tomcat 8 설치하기

2019/03/07 20:59
Java Virtual Machine 설치

01. 현재 로컬에 설치되어 있는 JDK 확인
sudo yum list installed | grep java
02. 설치되어 있는 경우 Java 버전 확인
java -version
03. 설치된 JDK가 없는 경우 OpenJDK 설치
sudo yum install java-1.*-openjdk*
04. 여러 버전의 JDK가 설치되어 있는 경우
alternatives --config java

Pre-Built Packages 이용하여 설치하는 경우


01. 현재 설치되어 있는 tomcat 조회
sudo yum list installed | grep tomcat
02. 설치할 수 있는 tomcat 패키지 조회
sudo yum list tomcat*
03. 최신 버전의 tomcat 패키지 설치
sudo yum install tomcat
04. 설치되었는지 확인
sudo yum list installed | grep tomcat

05. 8080포트 방화벽 설정
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
06. 부팅 시 자동 시작하도록 설정
sudo systemctl enable tomcat
07. tomcat 시작
sudo systemctl start tomcat
08. 프로세스 확인
ps -ef | grep tomcat
압축 파일(tomcat 8)  다운로드하여 설치하기

01. 압축 파일 다운로드
wget http://mirror.navercorp.com/apache/tomcat/tomcat-8/v8.5.38/bin/apache-tomcat-8.5.38.tar.gz
02. 압축 해제
tar -zxpvf apache-tomcat-8.5.38.tar.gz

03. Tomcat Home 설정
mv apache-tomcat-8.5.38 tomcat
echo "export CATALINA_HOME='$HOME/tomcat'" >> ~/.bashrc
source ~/.bashrc
04. 방화벽 오픈
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --reload
05. tomcat 실행
cd tomcat/bin
./startup.sh
06. 확인
브라우저에서 localhost:8080
07. tomcat 종료
./shutdown.sh

CentOS 7.5에 nginx 최신 버전(1.14.2) 설치

2019/03/07 16:52
Pre-Built Package를 이용하여 설치하는 경우

01. Install the prerequisites
sudo yum install yum-utils

02. Repository 생성
vi /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
03. Default로는 stable 버전으로 설정되어 있으나 mainline을 사용하고자 할 경우
sudo yum-config-manager --enable nginx-mainline

04. nginx 설치
sudo yum install nginx

소스코드로부터 설치하는 경우

01. Nginx 다운로드
wget https://nginx.org/download/nginx-1.14.2.tar.gz
02. 압축풀기
tar -xvf nginx-1.14.2.tar.gz
03. 의존성 라이브러리 설치
sudo yum -y install gcc gcc-c++ make zlib-devel pcre-devel openssl-devel

04. nginx 폴더 생성
mkdir nginx
mkdir log run sbin
05. Configuration Option 설정

./configure \
--user=nginx                          \
--group=nginx                         \
--prefix=$HOME/nginx                   \
--sbin-path=$HOME/nginx/sbin           \
--conf-path=$HOME/nginx/nginx.conf     \
--pid-path=$HOME/nginx/run/nginx.pid         \
--lock-path=$HOME/nginx/run/nginx.lock       \
--error-log-path=$HOME/nginx/log/error.log \
--http-log-path=$HOME/nginx/log/access.log \
--with-http_gzip_static_module        \
--with-http_stub_status_module        \
--with-http_ssl_module                \
--with-pcre                           \
--with-file-aio                       \
--with-http_realip_module             \
--without-http_scgi_module            \
--without-http_uwsgi_module           \
--without-http_fastcgi_module

06. Compile the nginx source

make
make install
07. nginx configuration 변경
기본적으로 80 포트는 root 계정으로 실행해야 하므로 nginx.conf 파일에서 listen 8080으로 변경.
vi nginx.conf
08. nginx oepration shell script 생성
[nginx 시작]
vi start.sh
#!/bin/bash
./sbin/nginx
[nginx 종료]
vi stop.sh
#!/bin/bash
./sbin/nginx -s stop

[nginx 재시작]
vi restart.sh
#!/bin/bash
./sbin/nginx -s reload

[nginx 설정 파일 확인]
vi check.sh
#!/bin/bash
./sbin/nginx -t

09. 확인
시작 : sh start.sh &
브라우저에서 localhost:8080 호출하여 [Welcome to nginx!] 내용 확인
종료 : sh stop.sh

kong API Gateway 설치

2019/03/04 14:40

<CentOS 7에 PostgreSQL 설치 (10버전)>

https://www.postgresql.org/download/linux/redhat/ 참고

1. RPM Repository 설치

yum install https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm

2. 설치 가능한 패키지 검색

yum list postgres*

3. packages 설치

yum install postgresql10-server postgresql10

4. Database 초기화

/usr/pgsql-10/bin/postgresql-10-setup initdb

5. 부팅 시 자동 시작 등록

systemctl enable postgresql-10

6. Database 서버 시작

systemctl start postgresql-10

7. 설정 파일 수정

vi /var/lib/pgsql/10/data/postgresql.conf

listen_addresses = '*'          # what IP address(es) to listen on;

vi /var/lib/pgsql/10/data/pg_hba.conf

# IPv4 local connections:

 host    all             all             127.0.0.1/32            trust

8. Database 서버 재시작

systemctl restart postgresql-10

<설치한 PostgresSQL 10 Database에 kong 계정 설정>

1. PostgreSQL 로그인

su - postgres

2. SQL Client 실행

bash-4.2 $ psql

3. User 생성 SQL 입력

CREATE USER kong;

4. Database 생성 SQL 입력

CREATE DATABASE kong owner kong;

5. 권한 부여

grant all privileges on database kong to kong;

6. SQL Client - psql 종료

\q

7. PostgreSQL 로그아웃

exit

8. PostgreSQL 버전 확인

/usr/pgsql-10/bin/postgres --version

<kong Gateway 설치>

1. Package 다운로드 및 파일 이름 변경

wget https://bintray.com/kong/kong-community-edition-rpm/download_file?file_path=centos/7/kong-community-edition-1.0.3.el7.noarch.rpm

mv download_file\?file_path\=centos%2F7%2Fkong-community-edition-1.0.3.el7.noarch.rpm kong-community-edition-1.0.3.el7.noarch.rpm

2. CentOS Repository 다운로드 및 이동

wget https://bintray.com/kong/kong-community-edition-rpm/rpm -O bintray-kong-kong-community-edition-rpm.repo

mv bintray-kong-kong-community-edition-rpm.repo /etc/yum.repos.d/

3. Repository 파일 수정

vi /etc/yum.repos.d/bintray-kong-kong-community-edition-rpm.repo

baseurl을 다음과 같이 수정

baseurl=https://kong.bintray.com/kong-community-edition-rpm

-> baseurl=https://kong.bintray.com/kong-community-edition-rpm/centos/7

4. Package 설치

yum install epel-release

yum install kong-community-edition-1.0.3.*.noarch.rpm --nogpgcheck

5. 설치된 kong 버전 확인

kong version

6. kong 설정 파일 복사

cp /etc/kong/kong.conf.default /etc/kong/kong.conf

7. Database Migration

kong migrations bootstrap

8. kong 시작

kong start

9. kong 확인

curl -i http://localhost:8001/