再插入300万数据的时候,报错
// redis 日志文件
2670:M 13 Dec 17:30:53.061 * 10 changes in 300 seconds. Saving...
2670:M 13 Dec 17:30:53.061 # Can't save in background: fork: Cannot allocate memory
// redis-cli
127.0.0.1:6379>
127.0.0.1:6379> flushdb
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
127.0.0.1:6379
// 引用 http://www.cnblogs.com/qq78292959/p/3994341.html
在小内存的进程上做一个fork,不需要太多资源,但当这个进程的内存空间以G为单位时,fork就成为一件很恐怖的操作。何况在16G内存的主机上fork 14G内存的进程呢?肯定会报内存无法分配的。更可气的是,越是改动频繁的主机上fork也越频繁,fork操作本身的代价恐怕也不会比假死好多少。
找到原因之后,直接修改内核参数vm.overcommit_memory = 1
Linux内核会根据参数vm.overcommit_memory参数的设置决定是否放行。
1. 如果 vm.overcommit_memory = 1,直接放行
2.vm.overcommit_memory = 0:则比较 此次请求分配的虚拟内存大小和系统当前空闲的物理内存加上swap,决定是否放行。
3.vm.overcommit_memory = 2:则会比较 进程所有已分配的虚拟内存加上此次请求分配的虚拟内存和系统当前的空闲物理内存加上swap,决定是否放行。
Arch linux设置vm.overcommit_memory 方法
永久性修改内核参数
在/etc/sysctl.conf文件里面加入或者直接删除也可以,因为它缺省值就是0
vm.overcommit_memory = 0
运行使之生效
#sysctl -p
分别对redis 进行100万 200 万 300万数据量的插入,分别统计花费的时间
====================================================
---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 16:56:22---2016-12-13 16:56:44------1000000------21791------45890-----------4-----------11472--------748byte-----
---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 17:15:23---2016-12-13 17:16:07------2000000------43802------45660-----------4-----------11415--------748byte-----
---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 18:23:47---2016-12-13 18:24:57------3000000------70256------42700-----------4-----------10675--------748byte-----
--------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 18:33:53---2016-12-13 18:34:21------1000000------28133------35545-----------2-----------17772--------748byte-----
---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 18:31:34---2016-12-13 18:32:32------2000000------57970------34500-----------2-----------17250--------748byte-----
---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 18:27:37---2016-12-13 18:29:02------3000000------85097------35253-----------2-----------17626--------748byte-----
---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 18:36:01---2016-12-13 18:36:21------1000000------20085------49788-----------6-----------8298--------748byte-----
---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 18:37:43---2016-12-13 18:38:25------2000000------41571------48110-----------6-----------8018--------748byte-----
---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小
-2016-12-13 18:39:25---2016-12-13 18:40:30------3000000------65840------45565-----------6-----------7594--------748byte-----
300万条执行的效率下降,跟RDB默认策略有关系.
save 900 1
save 300 10
save 60 10000
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.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
public class RedisWriteTaskSchudler {
private static Logger logger = Logger.getLogger(RedisWriteTaskSchudler.class);
volatile boolean runState = true;
// 开启时间
long startTime = 0;
long endTime = 0;
// 工作线程
Thread[] workers = null;
// 线程数量
int threadNumber = 0;
AtomicLong writeCount = new AtomicLong(ConfigManager.redis_write_count);
// 测试完成判断
public Semaphore semaphore = new Semaphore(1);
// 定时器
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
RedisWriteTaskSchudler (int threadNumber) {
// 默认线程数量为硬件内核数的2倍
this.threadNumber = threadNumber;
workers = new Thread[threadNumber];
for (int i = 0; i < threadNumber; i++) {
workers[i] = new Thread(new RedisWriteTask(JedisManager.instance().getJedis()));
workers[i].setDaemon(true);
workers[i].setName(ConfigManager.read_thread_name + "i");
}
executorService.scheduleAtFixedRate(new PrintTimer(), 2, 15, TimeUnit.SECONDS);
}
class PrintTimer implements Runnable {
@Override
public void run() {
// 结束
if (runState == false) {
JedisManager.instance().shutdown();
executorService.shutdown();
}
}
}
/**
* 启动工作线程
* @throws InterruptedException
*/
public void start() throws InterruptedException {
for (int i = 0; i < threadNumber; i++) {
workers[i].start();
}
startTime = System.currentTimeMillis();
}
/**
* 关闭线程
*/
public void shutdown() {
runState = false;
executorService.shutdown();
}
public synchronized void log() {
if (endTime == 0) {
endTime = System.currentTimeMillis();
} else {
return;
}
StringBuilder sb = new StringBuilder();
SimpleDateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
long _count = ConfigManager.redis_write_count;
long useTime = endTime - startTime;
long throughput = ((_count * 1000) /useTime);
int strLength = ConfigManager.test_string_value.getBytes().length;
sb.append("\n======================================================\n");
sb.append("---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小\n");
sb.append("-");
sb.append(format.format(new Date(startTime)));
sb.append("---");
sb.append(format.format(new Date(endTime)));
sb.append("------");
sb.append(_count);
sb.append("------");
sb.append(useTime);
sb.append("------");
sb.append(throughput);
sb.append("-----------");
sb.append(threadNumber);
sb.append("-----------");
sb.append(throughput / threadNumber );
sb.append("--------");
sb.append(strLength);
sb.append("byte-----");
logger.error(sb.toString());
logger.error("\n");
semaphore.release();
}
class RedisWriteTask implements Runnable {
private Jedis jedis = null;
RedisWriteTask (Jedis jedis) {
this.jedis = jedis;
}
@Override
public void run() {
semaphore.tryAcquire();
while (runState) {
try {
long number = writeCount.decrementAndGet();
if (number < 0) {
runState = false;
log();
break;
}
String writeKey = ConfigManager.test_string_key + number;
jedis.set(writeKey, ConfigManager.test_string_value);
} catch (Throwable t) {
logger.error("",t);
// 连接失败
if (!jedis.isConnected()) {
//返回连接池里面
jedis.close();
// 重新获取连接
jedis = JedisManager.instance().getJedis();
}
}
}
// 返回去jedis pool 里面
jedis.close();
}
}
}
http://download.csdn.net/detail/jia281460530/9710776