redis(單機讀取資料效能測試)
阿新 • • 發佈:2018-12-25
redis 測試之–讀取效能
目的
- 熟悉jedis操作redis
- 對redis效能指標有個大概認知
測試環境
- ubuntu
- 機器雙核4G記憶體普通機
- 外網流量4M
- redis版本: 3.2.6
- redis 和測試服務程式在一臺伺服器上
redis 配置
新增密碼和註釋了bind:127.0.0.1,其他均為預設配置
測試思路
- redis 儲存一個測試key( 測試key是672位元組)
- 開啟jedis執行緒池,為個工作執行緒提供一個執行緒
- 工作執行緒不斷讀取key,獲取到key後直接計數器記錄
- 開啟一個定時列印定時器,將結果輸出
測試結果
日誌記錄
=======================================================
---------開始時間--------------結束時間-------------獲取條數-----每秒吞吐量-----分鐘吞吐量-----小時吞吐量-----測試執行執行緒數量----每個訊息的大小
-2016-12-10 15:28:42---2016-12-10 17:01:44------240670794------43115---------2587857---------240670792-----------2-----------672byte-----
------- --開始時間--------------結束時間-------------獲取條數-----每秒吞吐量-----分鐘吞吐量-----小時吞吐量-----測試執行執行緒數量----每個訊息的大小
-2016-12-10 10:40:25---2016-12-10 12:55:12------457891036------56620---------3417097---------228945517-----------4-----------672byte-----
---------開始時間--------------結束時間-------------獲取條數-----每秒吞吐量-----分鐘吞吐量----- 小時吞吐量-----測試執行執行緒數量----每個訊息的大小
-2016-12-10 14:10:26---2016-12-10 15:11:28------231494306------63215---------3794988---------231494306-----------6-----------672byte-----
[framework] 2016-12-10 15:11:28,466 - com.jiazq.jizq.redis.mq.RedisReadTaskSchuder -3662056 [pool-1-thread-1] ERROR com.jiazq.jizq.redis.mq.RedisReadTaskSch
--------開始時間--------------結束時間-------------獲取條數-----每秒吞吐量-----分鐘吞吐量-----小時吞吐量-----測試執行執行緒數量----每個訊息的大小
-2016-12-10 13:00:49---2016-12-10 14:09:06------275406638------67221---------4050097---------275406638-----------8-----------672byte-----
cpu記錄
// 2 個執行緒
top - 17:02:56 up 16 days, 18:35, 2 users, load average: 1.15, 1.00, 1.02
Tasks: 116 total, 4 running, 112 sleeping, 0 stopped, 0 zombie
%Cpu(s): 18.2 us, 24.7 sy, 0.0 ni, 39.3 id, 0.0 wa, 0.0 hi, 14.6 si, 3.3 st
KiB Mem: 4046856 total, 3113916 used, 932940 free, 233184 buffers
KiB Swap: 0 total, 0 used, 0 free. 1501364 cached Mem
// 4 執行緒
top - 12:57:07 up 16 days, 14:29, 2 users, load average: 1.64, 1.85, 1.92
Tasks: 117 total, 3 running, 114 sleeping, 0 stopped, 0 zombie
%Cpu(s): 19.9 us, 30.6 sy, 0.0 ni, 21.7 id, 0.0 wa, 0.0 hi, 26.4 si, 1.4 st
KiB Mem: 4046856 total, 3125252 used, 921604 free, 233180 buffers
KiB Swap: 0 total, 0 used, 0 free. 1499612 cached Mem
// 6 執行緒
top - 14:30:01 up 16 days, 16:02, 2 users, load average: 2.21, 2.73, 2.95
Tasks: 117 total, 3 running, 114 sleeping, 0 stopped, 0 zombie
%Cpu(s): 19.8 us, 39.0 sy, 0.0 ni, 14.4 id, 0.0 wa, 0.0 hi, 26.0 si, 0.8 st
KiB Mem: 4046856 total, 3115260 used, 931596 free, 233184 buffers
KiB Swap: 0 total, 0 used, 0 free. 1500320 cached Mem
// 8 執行緒
top - 15:21:23 up 16 days, 16:53, 2 users, load average: 4.17, 3.42, 3.14
Tasks: 117 total, 3 running, 114 sleeping, 0 stopped, 0 zombie
%Cpu(s): 21.0 us, 39.1 sy, 0.0 ni, 13.2 id, 0.0 wa, 0.0 hi, 26.1 si, 0.6 st
KiB Mem: 4046856 total, 3099824 used, 947032 free, 233184 buffers
KiB Swap: 0 total, 0 used, 0 free. 1500688 cached Mem
結果分析
- 讀取執行緒數量2 的吞吐量為 4.3/S 平均每個執行緒讀取能力2.1W/S 負載1.0
- 讀取執行緒數量4(cpu核心2倍)的吞吐量為 5.6W/S 平均每個執行緒讀取能力 1.4W/S 負載 1.85
- 讀取執行緒數量6 (cpu核心3倍) 的吞吐量為 6.3W/S 平均每個執行緒讀取能力 1W/S 負載 2.73
- 讀取執行緒數量8 (cpu核心4倍) 的吞吐量為 6.7W/S 平均每個執行緒讀取能力 8300/S 負載3.42
隨著處理執行緒增加整體吞吐量也在增加,但增帳率下降,單執行緒處理能力下降,CPU使用率浮動較小,負載情況成倍增加。
結論
- 單機redis最高讀取效能,還可以更高,吞吐量還應在 7W/S以上
- 客戶端執行緒處理能力,應該在IO執行緒數量上,合理的客戶端連線數量可提高整體處理能力.
- 客戶端讀取執行緒數量 為核心個數為佳.
核心處理程式碼
工作執行緒組(RedisReadTaskSchuder)
package com.jiazq.jizq.redis.mq;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
public class RedisReadTaskSchuder {
private static Logger logger = Logger.getLogger(RedisReadTaskSchuder.class);
// 訊息計數器
AtomicLong counter = new AtomicLong(0);
// 定時器
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
volatile boolean runState = true;
// 開啟時間
long startTime = 0;
// 工作執行緒
Thread[] workers = null;
// 執行緒數量
int threadNumber = 0;
public RedisReadTaskSchuder(int threadNumber) {
// 預設執行緒數量為硬體核心數的2倍
this.threadNumber = threadNumber;
workers = new Thread[threadNumber];
for (int i = 0; i < threadNumber; i++) {
workers[i] = new Thread(new RedisReadTask(JedisManager.instance().getJedis()));
workers[i].setDaemon(true);
workers[i].setName(ConfigManager.read_thread_name + "i");
}
executorService.scheduleAtFixedRate(new PrintTimer(), 2, 15, TimeUnit.SECONDS);
}
/**
* 啟動工作執行緒
*/
public void start() {
for (int i = 0; i < threadNumber; i++) {
workers[i].start();
}
startTime = System.currentTimeMillis();
}
/**
* 計數器重置
*
*/
public void resetCount() {
this.counter.set(0);
startTime = System.currentTimeMillis();
}
public long getCount() {
return this.counter.get();
}
/**
* 關閉執行緒
*/
public void shutdown() {
runState = false;
executorService.shutdown();
}
public void printReuslt() {
logger.info("---獲取到資料數量:--" + counter.get());
}
class RedisReadTask implements Runnable {
private Jedis jedis = null;
RedisReadTask(Jedis jedis) {
this.jedis = jedis;
}
@Override
public void run() {
while (runState) {
try {
byte[] str = jedis.get(Main.testKey.getBytes());
if (null != str) {
counter.incrementAndGet();
}
} catch (Throwable t) {
logger.error("",t);
// 連線失敗
if (!jedis.isConnected()) {
//返回連線池裡面
jedis.close();
// 重新獲取連線
jedis = JedisManager.instance().getJedis();
}
}
}
// 返回去jedis pool 裡面
jedis.close();
}
}
class PrintTimer implements Runnable {
@Override
public void run() {
try {
StringBuilder sb = new StringBuilder();
SimpleDateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
long _count = counter.get();
long _endTime = System.currentTimeMillis();
long throughput_s = ( _count * 1000) / (_endTime - startTime);
long minTime = (_endTime - startTime) /(1000 * 60);
long hourTime = (_endTime - startTime) /(1000 * 60 * 60);
long throughput_m = (minTime != 0) ? _count /minTime : 0;
long throughput_h = (hourTime != 0) ? _count /hourTime : 0;
sb.append("\n======================================================\n");
sb.append("---------開始時間--------------結束時間-------------獲取條數-----每秒吞吐量-----分鐘吞吐量-----小時吞吐量-----測試執行執行緒數量----每個訊息的大小\n");
sb.append("-");
sb.append(format.format(new Date(startTime)));
sb.append("---");
sb.append(format.format(new Date()));
sb.append("------");
sb.append(counter.get());
sb.append("------");
sb.append(throughput_s);
sb.append("---------");
sb.append(throughput_m);
sb.append("---------");
sb.append(throughput_h);
sb.append("-----------");
sb.append(threadNumber);
sb.append("-----------");
sb.append("672byte");
sb.append("-----");
logger.error(sb.toString());
logger.error("\n");
} catch (Throwable t) {
logger.error("",t);
}
}
}
}
jedis執行緒池
package com.jiazq.jizq.redis.mq;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class JedisManager {
private static Logger logger = Logger.getLogger(JedisManager.class);
private static JedisManager instance = null;
private JedisPool jedisPool = null;
private JedisManager () {
}
public static synchronized JedisManager instance() {
if (null == instance) {
instance = new JedisManager();
instance.init();
}
return instance;
}
public void init() {
logger.info("------init redis start------");
GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig();
jedisPoolConfig.setMaxTotal(ConfigManager.redis_pool_maxTotal);
jedisPoolConfig.setMaxIdle(ConfigManager.redis_pool_maxIdle);
jedisPoolConfig.setTestOnBorrow(true);
jedisPoolConfig.setMaxWaitMillis(ConfigManager.redis_pool_maxWait);
jedisPool = new JedisPool(jedisPoolConfig,
ConfigManager.redis_host,
ConfigManager.redis_port,
ConfigManager.redis_pool_timeOut,
ConfigManager.redis_auth,
ConfigManager.redis_pool_database);
logger.info("------init redis end------");
}
public Jedis getJedis() {
return jedisPool.getResource();
}
public void rebackPool(Jedis jedis) {
jedis.close();
}
public String getString(String key) {
Jedis jedis = getJedis();
String result = jedis.get(key);
jedis.close();
return result;
}
public void set(String key, String value) {
Jedis jedis = getJedis();
jedis.set(key, value);
jedis.close();
}
public void shutdown() {
logger.info("---redis close--" + jedisPool.getNumActive());
jedisPool.close();
}
}
主函式Main
package com.jiazq.jizq.redis.mq;
import org.apache.log4j.Logger;
public class Main {
private static Logger logger = Logger.getLogger(Main.class);
static String testStr = "{.....}";
static String testKey = "testkey676K";
// 執行時間
static int exetime = 1;
public static void main(String[] args) throws InterruptedException {
logger.info("----start-testServer----start--");
// 初始化redis連線池
JedisManager.instance();
// 建立執行緒排程
RedisReadTaskSchuder schuder = new RedisReadTaskSchuder(ConfigManager.read_thread_number);
// 執行緒啟動
schuder.start();
logger.info("----start-testServer----end--");
}
public void testNative() throws InterruptedException {
// 初始化redis連線池
JedisManager.instance();
// 建立執行緒排程
RedisReadTaskSchuder schuder = new RedisReadTaskSchuder(ConfigManager.read_thread_number);
// 執行緒啟動
schuder.start();
//預熱一秒
Thread.sleep(1000);
// 計數器重置
schuder.resetCount();
// 執行五秒
Thread.sleep(60000 * exetime);
schuder.shutdown();
JedisManager.instance().shutdown();
schuder.printReuslt();
logger.info(schuder.getCount() / (60 * exetime));
}
}