再使用redis的过程中,发现使用缓存尽管好,可是有些地方还是比較难权衡,缓存对象大了,存储对象时的序列化工作非常繁重,消耗大量cpu;那么切分成非常小的部分吧,存取的次数变多了,redisclient的交互次数上不去,这是一个矛盾。要是有一个client能支持很多其它的交互次数,那么在完毕既定指标的前提下,岂不是能够让我们的建模工作变的更宽松一些?

于是參照redis协议,花了5天时间,做了一个具备基本功能的redisclient。它的特性:

1.支持异步调用,在getA之后不用等结果,能继续getB,getC,等等。等要做的redis操作都做完了,再来检查结果。

2.单连接,支持断线重连。client和随意一个redisserver仅仅建立一个连接。由于是异步调用,不是必需建立很多其它连接。

3.底层支持pipeline,不管是异步调用,还是堵塞调用,底层使用的都有概率使用到pipeline。对pipeline的支持是在通信层做的,所以不管哪种调用都是隐性的使用pipeline。可是,连续的异步操作,本线程内的操作就有可能使用pipeline。而同步调用,则通常是线程之间的操作使用pipeline。更重要的是,这一切都是在底层完毕的,我们在调用redis api的时候根本不用管这些,仅仅管调用就可以。仅仅只是是建议採用连续的异步操作,由于这样效率最高。

4.支持shard模式。採用一致性算法的分片。

5.shard模式下仍然支持pipeline。由于对pipeline的支持是做在通信层的,所以,在不论什么模式下都支持pipeline。

最后看一下,在我机器上跑的结果吧:

机器配置:双核cpu,主频2GHz,8g内存,mac osx

redis执行在本机的虚拟机上,虚拟机单核单线程,2G内存,ubuntu server。

測试场景1(模拟堵塞调用的场景):

80个线程,进行简单的get、set,

每秒运行的get和set总数为:130000次以上。

public class ShardClientTest {

	public static void main(String[] args) throws IOException,
InterruptedException {
final int T = 80;
final int CONTINUOUS = 1;
final int N = 20000000; EzSelector selector = new EzSelector();
List<BiTuple<String, Integer>> list = new ArrayList<>();
list.add(new BiTuple<>("10.211.55.5", 6379)); final ShardClient conn = new ShardClient(selector, list); final AtomicLong count = new AtomicLong();
for (int n = 0; n < T; n++) {
Thread t = new Thread() {
public void run() {
try {
for (int i = 0; i < N; i++) {
try {
Result ret = null;
for (int cc = 0; cc < CONTINUOUS; cc++) {
ret = conn.asyncSet(i + "", i + ":" + cc);
// System.out.println(ret.get());
}
ret.get(); Result ret6 = null;
for (int cc = 0; cc < CONTINUOUS; cc++) {
ret6 = conn.asyncGet(i + "");
// System.out.println(ret6.get());
}
ret6.get(); count.addAndGet(CONTINUOUS * 2);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
} catch (Exception e) {
e.printStackTrace();
}
};
};
t.start();
} while (true) {
long start = count.get();
Thread.sleep(1000);
System.out.println(count.get() - start);
}
} }

測试场景2(模拟异步调用,连续5次get和set):

每秒可运行的get和set总数是330000次左右

package zhmt.ezredis;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong; import zhmt.eznet.EzSelector;
import zhmt.eznet.EzSocketOption;
import zhmt.eznet.SharedRpcConnection.Result;
import zhmt.ezredis.AsyncClient; public class RedisClientTest {
public static void main(String[] args) throws IOException,
InterruptedException {
final int T = 100;
final int CONTINUOUS = 5;
final int N = 20000000; EzSelector selector = new EzSelector();
final RedisClient conn = new AsyncClient(selector,
new EzSocketOption("10.211.55.5", 6379)); final AtomicLong count = new AtomicLong();
for (int n = 0; n < T; n++) {
Thread t = new Thread() {
public void run() {
try {
for (int i = 0; i < N; i++) {
try {
Result ret = null;
for (int cc = 0; cc < CONTINUOUS; cc++) {
ret = conn.asyncSet(i + "", i + ":" + cc);
// System.out.println(ret.get());
}
ret.get(); Result ret6 = null;
for (int cc = 0; cc < CONTINUOUS; cc++) {
ret6 = conn.asyncGet(i + "");
// System.out.println(ret6.get());
}
ret6.get(); count.addAndGet(CONTINUOUS * 2);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
} catch (Exception e) {
e.printStackTrace();
}
};
};
t.start();
} while (true) {
long start = count.get();
Thread.sleep(1000);
System.out.println(count.get() - start);
}
}
}

到眼下为止,仅仅实现了十几命令。

接下来,准备优先实现用户自己定义shard key。使数据依照用户的意图去分片。以最大化pipeline的使用。

其次,继续实现经常使用命令。

源代码:

https://github.com/zhmt/ezredis

JAVA实现的异步redisclient的更多相关文章

  1. Java多线程实现异步调用

    在Java平台,实现异步调用的角色有如下三个角色:调用者. 提货单 .真实数据,一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单 .然后在过一断时间后凭提货单来获取真正的数据.去蛋糕店买 ...

  2. java网络通信:异步非阻塞I/O (NIO)

    转: java网络通信:异步非阻塞I/O (NIO) 首先是channel,是一个双向的全双工的通道,可同时读写,而输入输出流都是单工的,要么读要么写.Channel分为两大类,分别是用于网络数据的S ...

  3. Java回调实现异步 (转)

    出处: Java回调实现异步 在正常的业务中使用同步线程,如果服务器每处理一个请求,就创建一个线程的话,会对服务器的资源造成浪费.因为这些线程可能会浪费时间在等待网络传输,等待数据库连接等其他事情上, ...

  4. 深入浅出: Java回调机制(异步)

    一.什么是回调 回调,回调.要先有调用,才有调用者和被调用者之间的回调.所以在百度百科中是这样的: 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用.回调和异步调用. 回调 ...

  5. java 中的异步回调

    异步回调,本来在c#中是一件极为简单和优雅的事情,想不到在java的世界里,却如此烦琐,先看下类图: 先定义了一个CallBackTask,做为外层的面子工程,其主要工作为start 开始一个异步操作 ...

  6. 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor

    开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...

  7. wemall app商城源码中基于JAVA的Android异步加载图片管理器代码

    wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...

  8. Java中的异步通知

    在我们的日常开发中,经常会遇到这样的问题--"我让你做一件事情,但是你做得很慢,并不能够立马返回给我结果,害我一直在那儿等着你给我返回结果,什么都做不了". 程序是自上而下顺序执行 ...

  9. java CountDownLatch 控制异步和同步

    应用场景举例: 执行A项目的方法,需要调用B项目.C项目.D项目的接口方法. 需求: 异步调用B.C.D项目的接口方法,且每个接口都调用结束后,A项目的方法才可以结束. 注:如果需要获取接口返回结果, ...

随机推荐

  1. [转] LCA与Tarjan

    转载:http://m.blog.csdn.net/blog/u013076044/41875009# 在线算法与离线算法的定义 在计算机科学中,一个在线算法是指它可以以序列化的方式一个个的处理输入, ...

  2. 解决angular的post请求后SpringMVC后台接收不到参数值问题的方法

    这是我后台SpringMVC控制器接收isform参数的方法,只是简单的打出它的值: @RequestMapping(method = RequestMethod.POST) @ResponseBod ...

  3. poj 3279 Fliptile

    题意:一个n * m的棋盘,0或1,每次改变一个格子时同时改变上下左右的格子,问用最少次数将棋盘全变成0的策略. 题解:用二进制压缩第一行更改的状态,之后遍历棋盘,如果当前格子为1则改变下方的格子,记 ...

  4. Delphi 打印

    procedure TForm1.PrinterSetupExecute(Sender: TObject);begin PrinterSetupDialog1.Execute;end; procedu ...

  5. FZU 2105-Digits Count(线段树延时标记)

    题意: 每次操作区间每个数进行一种(&或|.或^ )给定的一个数,到sum时统计给定区间的和. 分析: 这个题让我觉得我的思维很不活跃,对懒惰标记理解,还远远不够,通过这道题我对懒惰标记加深了 ...

  6. e2e 自动化集成测试 架构 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step (二) 图片验证码的识别

    上一篇文章讲了“e2e 自动化集成测试 架构 京东 商品搜索 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step 一 京东 商品搜索 ...

  7. Java WebService简单使用

    一直在写java但从来没有使用webservice,在网上查了下资料写个简单的使用放这里做备份 具体步骤: 1.新建一个java工程在里面写一个类(服务端)如下: package com.webser ...

  8. NOIP2008 双栈队列

    1.      双栈排序 (twostack.pas/c/cpp) Tom 最近在研究一个有趣的排序问题.如图所示,通过 2 个栈 S1 和 S2,Tom 希望借助 以下 4 种操作实现将输入序列升序 ...

  9. Cppcheck代码分析(1)

    一.检查点 1.自动变量检查: 返回自动变量(局部变量)指针 2.越界检查: 数组越界返回自动变量(局部变量)指针 3.类检查: 构造函数初始化 4.内存泄露检查: 5.空指针检查: 6.废弃函数检查 ...

  10. 字符串旋转(str.find()---KMP)

    此题旋转带有技巧性,问题转化为常见的问题,熟练STL可以直接用str.find()函数,其是主要想用KMP算法实现字符串的查找算法... //如果对于一个字符串A,将A的前面任意一部分挪到后边去形成的 ...