전에는 Guava cache, Ehcache등을 많이 사용했는데, 최근에는 Caffeine가 권장되고 있음

 

  1. Java 8 이상에서만 사용 가능
  2. Spring에서도 지원하는 구현체가 추가되었고 5.0에서는 Guava Cache 지원이 없어짐
  3. Guava cache 개발자가 다시 만든 라이브러리
  4. 앞으로 발전 가능성도 높은편

 

추후 여유되면 

 

1. maven 디펜더시 추가

<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.0</version>
</dependency>

 

2. 샘플 소스

import okhttp3.*;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * OKHttp를 이용한 요청 샘플
 * 
 * @author 엄승하
 */
public class OkHttpSample {

	static String reqUrl = "https://www.naver.com";

	//OkHttp를 사용하기 위한 client 생성(기본적으로 new시 커넥션풀 셋팅됨), 1개를 재 사용해야함

	// @formatter:off
	static OkHttpClient client = new OkHttpClient.Builder()
		//default timeout for client annotated requests
		.readTimeout(1000, TimeUnit.MILLISECONDS).connectTimeout(200, TimeUnit.MILLISECONDS).writeTimeout(500, TimeUnit.MILLISECONDS)
		//.addInterceptor(new TimeoutInterceptor())
		.build();

	// @formatter:on

	public static void main(String[] args) {

		reqGetSample();
		reqGetExtendTimeout();
		reqPostSample();

	}

	/**
	 * HTTP Get요청 샘플
	 */
	public static void reqGetSample() {

		try {

			//Request request = new Request.Builder().addHeader("X-ReqSvcCd", "TESTER").addHeader("CloudFront-Viewer-Country", "DE").url(reqUrl).build();
			Request request = new Request.Builder().addHeader("X-ReqSvcCd", "TESTER").url(reqUrl).build();
			Response response = client.newCall(request).execute();
			responseProcess(response);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 타임아웃을 늘린 요청(기본 클라이언트는 존재하지만 타임아웃값만 확장)
	 */
	public static void reqGetExtendTimeout() {

		try {
			OkHttpClient extendedTimeoutClient = client.newBuilder().readTimeout(1200, TimeUnit.MILLISECONDS).build(); //해당 요청만 타임아웃 늘림

			Request request = new Request.Builder().addHeader("X-ReqSvcCd", "TESTER").addHeader("CloudFront-Viewer-Country", "DE").url(reqUrl).build();
			Response response = extendedTimeoutClient.newCall(request).execute();
			responseProcess(response);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * HTTP POST 요청 샘플
	 */
	public static void reqPostSample() {

		try {
			RequestBody formBody = new FormBody.Builder().add("user", "tester").build(); //FormBody사용시 content-type는 application/x-www-form-urlencoded
			Request request = new Request.Builder().addHeader("X-ReqSvcCd", "TESTER").url(reqUrl).post(formBody).build();

			Response response = client.newCall(request).execute();
			responseProcess(response);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void responseProcess(Response response) throws IOException {

		if (response.isSuccessful()) {
			String rtnMsg = response.body().string();
			System.out.println(String.format("성공. 응답 msg => '%s", rtnMsg));
		} else {
			System.out.println(String.format("응답에러(200이 아님). 응답 code:'%s'\n errMsg:'%s'", response.code(), response.body().string()));
		}

		System.out.println("\n");
	}
}
  1. 필요 플러그인
    1. build user vars(링크)
  2. 사용 방법
    1. 빌드 환경에서 "Set jenkins user build variables" 활성화
    2. 이후 변수 접근해서 사용 가능
    3. 예)

 

 

 

 

 

 

 

spring webflux의 websocket관련 소스 분석

 

 

 

  1. WebSocketSession

    1. 인터페이스

    2. 용도/목적

  2. WebSocketHandler

 

 

netty 스레드 확인

 

 

  1. 구성 후 서버(netty)를 시작 후 thread를 확인해보면 reactor-http-nio-x 스레드를 확인할 수 있음

    1. netty 기본 설정에 의해 스레드 갯수는 CPU코어 갯수만큼 생김

    2. 아래 그림은 JMC(Oracle Java Mission Control)로 확인한 내용

       

 

 

  1. 아래 그림은 로컬PC 의 CPU 코어 갯수

 

 

 

주변분이 추천해주셔서 사용 중인 화면 캡쳐 프로그램인데 매우 만족.
 - getsharex.com/

ShareX - Screen capture, file sharing and productivity tool

ShareX is a free and open source program that lets you capture or record any area of your screen and share it with a single press of a key. It also allows uploading images, text or other types of files to many supported destinations you can choose from.

getsharex.com

 
 

참고

 - https://aws.amazon.com/ko/blogs/database/optimize-redis-client-performance-for-amazon-elasticache/

 - https://aws.amazon.com/ko/blogs/database/best-practices-redis-clients-and-amazon-elasticache-for-redis/

 

 - https://github.com/lettuce-io/lettuce-core/wiki/Connection-Pooling

 - https://lettuce.io/core/release/reference/#connection-pooling.is-connection-pooling-necessary

  1. 필요 라이브러리
    1. maven dependency 추가
<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>5.3.3.RELEASE</version>
</dependency>


<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.8.1</version>
</dependency>

 

2. 샘플 소스 - java

 - async command 등 참고 링크

import io.lettuce.core.ClientOptions;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisConnectionException;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

/**
 * redis 커넥션풀 기반 연결 샘플
 *
 * @author 
 */
public class ConnectionSampleWithPool {

	private static final String REDIS_CON_URL = "redis://192.168.56.1:6379/0"; //로컬 redis 0번 사용
	public static GenericObjectPool<StatefulRedisConnection<String, String>> pool = null; //sync & 비 클러스터모드 커넥션풀

	public static void main(String[] args) throws InterruptedException {

		pool = nonClusterPoolUsage();
		//pool = useClusterPoolUsage(); //클러스터모드일때

		testSetValue("key-pool-test-1", "key-pool-test-1");
		testSetValue("key-pool-test-2", "key-pool-test-2");
		testSetValue("key-pool-test-3", "key-pool-test-3");

		Thread.sleep(10 * 1000); //커넥션풀 close 전에 대기 후, redis-cli(서버)에서 client list 명령어로 현재 연결된 클라이언트 리스트를 확인해보면 됨

		pool.close();
		System.out.println("finish");
	}

	/**
	 * set value 테스트
	 *
	 * @param key
	 * @param value
	 */
	private static void testSetValue(String key, String value) {

		try (StatefulRedisConnection<String, String> connection = pool.borrowObject()) { //pool을 이용해서 커맨드 실행
			connection.sync().set(key, value);
			value = connection.sync().get(key);
			System.out.println(value);
		} catch (RedisConnectionException e) {
			System.out.println(String.format("Failed to connect to Redis server: %s", e));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 비 클러스터 모드일때 커넥션풀 셋팅
	 *
	 * @return
	 */
	private static GenericObjectPool<StatefulRedisConnection<String, String>> nonClusterPoolUsage() {

		RedisClient client = RedisClient.create(REDIS_CON_URL);
		client.setOptions(ClientOptions.builder().autoReconnect(true).build());

		return ConnectionPoolSupport.createGenericObjectPool(() -> client.connect(), createPoolConfig());
	}

	/**
	 * 클러스터모드일때 커넥션 풀 셋팅
	 *  - 참고: https://github.com/Azure/azure-redis-cache-samples/blob/master/Java/ClientSamples/src/main/java/lettuce/PoolUsage.java
	 *
	 * @return
	 */
	private static GenericObjectPool<StatefulRedisClusterConnection<String, String>> useClusterPoolUsage() {

		RedisClusterClient clusterClient = RedisClusterClient.create(REDIS_CON_URL);
		clusterClient.setOptions(ClusterClientOptions.builder().autoReconnect(true).build());

		return ConnectionPoolSupport.createGenericObjectPool(() -> clusterClient.connect(), createPoolConfig());
	}

	/**
	 * 커넥션풀 설정 생성
	 *
	 * @return
	 */
	private static GenericObjectPoolConfig createPoolConfig() {

		GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

		poolConfig.setMaxTotal(20);
		poolConfig.setMaxIdle(10);

		// "true" will result better behavior when unexpected load hits in production
		// "false" makes it easier to debug when your maxTotal/minIdle/etc settings need adjusting.
		poolConfig.setBlockWhenExhausted(true);
		poolConfig.setMaxWaitMillis(1000);
		poolConfig.setMinIdle(5);

		return poolConfig;
	}

}

java 로컬캐시

 -Guava cache보다 좋음

- https://github.com/ben-manes/caffeine

+ Recent posts