Redis如何能支持上百万的快速并发数据及导入百万数据

       Redis作为号称读写性能百万每秒的nosql数据库,但是我们在实际使用的过程中却是无法达到这个效果的,那是什么原因呢?都有哪些因素影响了Redis的性能呢?

       1.从机器性能上来看,CPU、网卡、磁盘等都会影响到读写的性能,就从网卡来说,你用100M的网卡去支持Redis200M/s的读写,这个肯定是会严重的影响到Redis性能的。

       2.从网络来看,如果你的网络经过很多次跳转才能最终到达Redis服务器,那么网络跳转产生的时间也会产生数据的延迟,因此也可以被看作是影响Redis性能的原因。

       3.从Redis的RESP协议来看,RESP协议定义的非常高效且可人读,因此这个提升了Redis的读写性能。

       针对上面的一些影响因素,在官网提供了一些测试数据:

Intel(R) Xeon(R) CPU E5520 @ 2.27GHz (with pipelining)

$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -P 16 -q
SET: 552028.75 requests per second
GET: 707463.75 requests per second
LPUSH: 767459.75 requests per second
LPOP: 770119.38 requests per second

Intel(R) Xeon(R) CPU E5520 @ 2.27GHz (without pipelining)

$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q
SET: 122556.53 requests per second
GET: 123601.76 requests per second
LPUSH: 136752.14 requests per second
LPOP: 132424.03 requests per second

Linode 2048 instance (with pipelining)

$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q -P 16
SET: 195503.42 requests per second
GET: 250187.64 requests per second
LPUSH: 230547.55 requests per second
LPOP: 250815.16 requests per second

Linode 2048 instance (without pipelining)

$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q
SET: 35001.75 requests per second
GET: 37481.26 requests per second
LPUSH: 36968.58 requests per second
LPOP: 35186.49 requests per second

      通过上面的测试分别在物理机和云上以及是否使用pipeline机制的时候,读写数据在性能上的差距是很大的(更多的测试数据可以看https://redis.io/topics/benchmarks),因此我们也可以看出如果针对大量的高并发读写,我们采用pipeline的机制在性能上面更好。在代码上看下实现方式

@Autowired
    private StringRedisTemplate stringRedisTemplate;
	
	
	/**
	 * 使用pipeline的方式
	 * @param batchSize
	 */
	public void pipeline(int batchSize) {
		List<Object> results = stringRedisTemplate.executePipelined(
		  new RedisCallback<Object>() {
		    public Object doInRedis(RedisConnection connection) throws DataAccessException {
		      StringRedisConnection stringRedisConn = (StringRedisConnection)connection;
		      for(int i=0; i< batchSize; i++) {
		    	// set key1 value2
		    	// set key2 value2
		        stringRedisConn.set("pipeline"+i, "xxx"+i);
		      }
		    return null;
		  }
		});
		System.out.println("pipeline over. results: "+results);
	}
public void pipeline(int batchSize) {
		Jedis jedis = new Jedis("192.168.1.5", 6379);
		Pipeline p = jedis.pipelined();
		List<Response<?>> list = new ArrayList<Response<?>>();
		long s = System.currentTimeMillis();
		for(int i=0; i< batchSize; i++) {
			Response<?> r = p.get("pipeline"+i);
			list.add(r);
		}
		System.out.println("write cost:"+(System.currentTimeMillis() - s));
		p.sync();
		list.forEach((e)->{
			System.out.println(e.get());
		});
		System.out.println("read cost:"+(System.currentTimeMillis() - s));
		try {
			p.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		jedis.close();
	}

 

       在使用Redis的时候假如我们已经有100W的数据产生,这个时候需要把这些大量的数据导入。那我们有哪些方法呢?

       1.打开一个txt文档,通过下面这种方式把要导入的数据写入txt文档

SET Key0 Value0
SET Key1 Value1
...
SET KeyN ValueN

       然后通过下面命令进行导入

(cat data.txt; sleep 10) | nc localhost 6379 > /dev/null

       但是这种方法不好的是它并不能确定数据是否已经完全导入,并且是否有错误产生。

       2.仍然通过第一种的txt文档内容方式,但是采用下面这种命令

cat data.txt | redis-cli --pipe

       通过pipe的方式会解决掉第一种方式的不足。

       3.通过Redis的RESP协议内容的方式进行数据组装,如下所示

"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"

       或通过格式化的方式看起来好看些

*3\r\n
$3\r\n
SET\r\n
$3\r\n
key\r\n
$5\r\n
value\r\n

       如果是新的Redis服务器,则可以直接通过以aof文件的方式读取到Redis中,否则可以通过代码的方式进行读取。

       4.ruby的方式

def gen_redis_proto(*cmd)
    proto = ""
    proto << "*"+cmd.length.to_s+"\r\n"
    cmd.each{|arg|
        proto << "$"+arg.to_s.bytesize.to_s+"\r\n"
        proto << arg.to_s+"\r\n"
    }
    proto
end

puts gen_redis_proto("SET","mykey","Hello World!").inspect
(0...1000).each{|n|
    STDOUT.write(gen_redis_proto("SET","Key#{n}","Value#{n}"))
}

       或者通过命令行方式执行ruby

$ ruby proto.rb | redis-cli --pipe

       5.lua脚本,具体参考https://redis.io/commands/eval

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于导入百万数据量的需求,可以采取以下方案来满足要求: a. 当服务器内存仅有500M的情况下,导入300M大的数据量,不能扩容: - 使用分批导入的方式,将大文件切割成小块逐个导入,这样可以减少内存的占用。可以使用类似于流式读取的方式,一次只读取一个小块的数据进行处理导入。 - 可以使用数据库的批量插入功能,将数据分批次插入数据库表中,而不是一次性插入。这样可以减少内存的使用。 b. 如何花更短时间导入,并且不会出现OOM: - 使用多线程或并发处理的方式,可以同时处理多个数据块的导入操作,提高导入速度。 - 合理调整数据库的参数设置,例如增大数据库的缓冲区大小、调整提交频率等,以提高导入效率。 - 优化数据导入过程中的逻辑和算法,减少不必要的计算和内存占用。 c. 自己设计数据库: - 首先确定数据的结构和关系,设计合理的表结构以满足数据存储和查询的需求。 - 根据数据量和访问模式选择适当的数据库引擎,如关系型数据库(如MySQL、Oracle)、非关系型数据库(如MongoDB、Redis)等。 - 针对具体的业务需求,进行数据库的优化设计,包括索引的创建、表的分区、数据的分片等。 - 考虑数据安全性和可靠性,设置合理的备份和恢复策略。 以上是一些通用的建议和方案,具体实施还需要根据实际情况进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值