
가장 접근하기 쉽고, 안전한 방법이지만, 라이브러리를 사용하여 하나씩 순차적으로 입력하는 방법은 데이터 입력에 걸리는 시간이 다른 방법에 비하여 현저하게 느림
파이프라인을 사용하면 데이터를 한 건씩 전송하는 것이 아니라 한 번에 모든 데이터를 전송하기 때문에 단일 데이터 입력 처리에 비하여 더 빠르게 대량의 데이터를 입력할 수 있음
스냅 샷 파일에 대량의 데이터를 기록하고 나서 레디스 서버를 재시작하여 적용하는 방법이기에 운영 측면에서는 권장하지 않음
https://github.com/redis/jedis
제디스(Java + Redis): Redis용 Java 클라이언트
MacBook Air (M1, 2020), RAM 16GB

package me.jincrates.redis.example;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
//천만 건의 데이터를 전송하는 예제
public class RedisInsertTest {
//전체 데이터 건수
private static final float TOTAL_OP = 10000000f;
public static void main(String[] args) {
JedisPool pool = new JedisPool("127.0.0.1", 6379);
Jedis jedis = pool.getResource();
String key, value;
long start = now();
for (int i = 1; i <= TOTAL_OP; i++) {
//레디스에 저장할 키와 값을 12자리로 고정하기 위해 아래와 같이 설정
key = value = String.valueOf("key" + (100000000 + i));
jedis.set(key, value);
}
long elapsed = now() - start;
System.out.println("초당 처리 건수 " + (TOTAL_OP / elapsed * 1000f));
System.out.println("소요 시간 " + (elapsed / 1000f) + "초");
jedis.disconnect();
}
private static long now() {
return System.currentTimeMillis();
}
}

package me.jincrates.redis.example;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Map;
//천만 건의 데이터를 다중 스레드로 전송하는 예제
public class JedisThreadTest {
//전체 데이터 건수
private static final float TOTAL_OP = 10000000f;
private static final float THREAD = 50; //프로그램 실행시 시작할 스레드 개수를 지정
public static void main(String[] args) {
GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig();
jedisPoolConfig.setMaxTotal(500); //poll에서 할당 할 수 있는 최대 연결 수
JedisPool pool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379, 10000);
final long start = now();
//자바 프로그램이 종료될 때 실행되는 이벤트 스레드를 등록
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
long elapsed = now() - start;
//전체 실행시간과 초당 전송 건소를 출력
System.out.println("스레드 개수 " + THREAD + "개");
System.out.println("초당 처리 건수 " + (TOTAL_OP / elapsed * 1000f) + "개");
System.out.println("소요 시간 " + (elapsed / 1000f) + "초");
}
});
JedisThreadTest test = new JedisThreadTest();
for (int i = 0; i < THREAD; i++) {
//지정된 스레드 개수만큼 스레드를 생성한다. 생성하는 스레드에 연결 출과 인덱스를 인자로 지정
test.makeWorker(pool, i).start();
}
}
private Thread makeWorker(final JedisPool pool, final int idx) {
//실제 데이터를 전송할 스레드를 생성
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
String key, value;
Jedis jedis = pool.getResource();
//지정된 스레드 인덱스에 해당하는 키를 생성하고 아니면 실행하지 않음
//이 부분은 각 스레드가 천만 개의 요청을 공평하게 나누어 전송하게 한다.
for (int i = 1; i <= TOTAL_OP; i++) {
if (i % THREAD == idx) {
key = value = String.valueOf("key" + (100000000 + i));
jedis.set(key, value);
}
}
pool.close();
}
});
return thread;
}
private static long now() {
return System.currentTimeMillis();
}
}

단일 스레드에 비해 멀티 스레드를 사용하는 것이 성능이 더 향상됐다.
스레드의 개수가 증가하면서 성능이 지속적으로 증가하다가 50개를 정점으로 성능이 하락한다.
즉, 무조건 스레드가 많다고 좋은 것은 아니며, 멀티 스레드에 대한 임계치가 존재한다는 것을 알 수 있다.
| 스레드 개수 | 초당 처리 건수 | 소요 시간 |
|---|---|---|
| 1 | 47095.617 | 212.334 |
| 5 | 103389.71 | 96.713 |
| 50 | 116319.17 | 85.977 |
| 100 | 109738.164 | 91.126 |
| 500 | 80028.164 | 124.956 |


제디스의 단일 명령 전송 부분을 제디스의 파이프라인 클래스를 사용하도록 변경한 예제
package me.jincrates.redis.example;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
//제디스와 파이프라인
public class PipelineDataJedis {
//작성할 데이터 건수: 천만 건
private static final int TOTAL_OPERATIONS = 10000000;
public static void main(String[] args) throws IOException {
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.connect();
long start = System.currentTimeMillis();
String key, value;
//제디스가 제공하는 파이프라인 객체를 생성
Pipeline p = jedis.pipelined();
for (int i = 0; i <= TOTAL_OPERATIONS; i++) {
key = value = String.valueOf("key" + (100000000 + i));
p.set(key, value);
}
//파이프라인의 응답을 서버로부터 모두 수신하여 제디스의 응답 객체로 변환
p.sync();
jedis.disconnect();
long elapsed = now() - start;
System.out.println("초당 처리 건수 " + (TOTAL_OPERATIONS / elapsed * 1000f));
System.out.println("소요 시간 " + (elapsed / 1000f) + "초");
}
private static long now() {
return System.currentTimeMillis();
}
}

11초....?
정경석, 이것이 레디스다 (한빛미디어, 2015), 174-186.