非关系型数据库(NoSQL = Not Only SQL)的产品非常多,常见的有Memcached、Redis、MongoDB等优秀开源项目,相关概念和资料网上也非常丰富,不再重复描述,本文主要引入Memcached和Redis与淘宝开源Tair分布式存储进行对比测试,由于各自适用场景不同,且每个产品的可配置参数繁多,涉及缓存策略、分布算法、序列化方式、数据压缩技术、通信方式、并发、超时等诸多方面因素,都会对测试结果产生影响,单纯的性能对比存在非常多的局限性和不合理性,所以不能作为任何评估依据,仅供参考,加深对各自产品的理解。以下是一些基本认识:
1、尽管 Memcached 和 Redis 都标识为Distribute,但从Server端本身而言它们并不提供分布式的解决方案,需要Client端实现一定的分布算法将数据存储到各个节点,从而实现分布式存储,两者都提供了Replication功能(Master-Slave)保障可靠性。
2、Tair 则本身包含 Config Server 和 Data Server 采用一致性哈希算法分布数据存储,由ConfigSever来管理所有数据节点,理论上服务器端节点的维护对前端应用不会产生任何影响,同时数据能按指定复制到不同的DataServer保障可靠性,从Cluster角度来看属于一个整体Solution,组件图参照上一篇博文(http://www.cnblogs.com/lengfo/p/4171655.html)。
基于此,本文设定了实验环境都使用同一台机器进行 Memcached、Redis 和 Tair 的单Server部署测试。
二、前置条件
1、虚拟机环境(OS:CentOS6.5,CPU:2 Core,Memory:4G)
2、软件环境
| Sever | Client | |
| Memcached | Memcached 1.4.21 | Xmemcached 2.0.0 |
| Redis | Redis 2.8.19 | Jedis 2.8.5 |
| Tair | Tair 2.3 | Tair Client 2.3.1 |
3、服务器配置,单一服务器通过配置尽可能让资源分配一致(由于各个产品服务器端的配置相对复杂,不再单独列出,以下仅描述内存、连接等基本配置)
| IP_Port | Memory_Size | Max_Connection | 备注 | |
| Memcached | 10.129.221.70:12000 | 1024MB | 2048 | |
| Redis | 10.129.221.70:6379 | 1gb(1000000000byte) | 10000(默认) | |
| Tair Config Server | 10.129.221.70:5198 | |||
| Tair Data Server | 10.129.221.70:5191 | 1024MB | 使用mdb存储引擎 |
三、用例场景,分别使用单线程和多线程进行测试
1、从数据库读取一组数据缓存(SET)到每个缓存服务器,其中对于每个Server的写入数据是完全一致的,不设置过期时间,进行如下测试。
1)单线程进行1次写入
2)单线程进行500次写入
3)单线程进行2000次写入
4)并行500个线程,每个线程进行1次写入
5)并行500个线程,每个线程进行5次写入
6)并行2000个线程,每个线程进行1次写入
2、分别从每个缓存服务器读取(GET)数据,其中对于每个Server的读取数据大小是完全一致的,进行如下测试。
1)单线程进行1次读取
2)单线程进行500次读取
3)单线程进行2000次读取
4)并行500个线程,每个线程进行1次读取
5)并行500个线程,每个线程进行5次读取
6)并行2000个线程,每个线程进行1次读取
四、单线程测试
1、缓存Model对象(OrderInfo)的定义参照tbOrder表(包括单据号、制单日期、商品、数量等字段)
2、单线程的读写操作对于代码的要求相对较低,不需要考虑Pool,主要代码如下:
1)Memcached单线程读写,使用二进制方式序列化,不启用压缩。
1 public static void putItems2Memcache(List<OrderInfo> orders) throws Exception { 2 MemcachedClient memcachedClient = null; 3 try { 4 MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("10.129.221.70:12000")); 5 builder.setCommandFactory(new BinaryCommandFactory()); 6 memcachedClient = builder.build(); 7 8 for (OrderInfo order : orders) { 9 boolean isSuccess = memcachedClient.set("order_" + order.BillNumber, 0, order); 10 if (!isSuccess) { 11 System.out.println("put: order_" + order.BillNumber + " " + isSuccess); 12 } 13 } 14 } catch (Exception ex) { 15 ex.printStackTrace(); 16 } finally { 17 memcachedClient.shutdown(); 18 } 19 } 20 21 public static void getItemsFromMemcache(List<String> billNumbers) throws Exception { 22 MemcachedClient memcachedClient = null; 23 try { 24 MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("10.129.221.70:12000")); 25 builder.setCommandFactory(new BinaryCommandFactory()); 26 memcachedClient = builder.build(); 27 28 for (String billnumber : billNumbers) { 29 OrderInfo result = memcachedClient.get(billnumber); 30 31 if (result == null) { 32 System.out.println(" get failed : " + billnumber + " not exist "); 33 } 34 } 35 } catch (Exception ex) { 36 ex.printStackTrace(); 37 } finally { 38 memcachedClient.shutdown(); 39 } 40 }