`

http://itindex.net/detail/50647-redis-java-客户端

 
阅读更多
redis是一个著名的key-value存储系统,而作为其官方推荐的java版客户端jedis也非常强大和稳定,支持事务、管道及有jedis自身实现的分布式。

        在这里对jedis关于事务、管道和分布式的调用方式做一个简单的介绍和对比:

一.普通同步方式

        最简单和基础的调用方式

@Test
public void test1Normal() {
    Jedis jedis = new Jedis("localhost");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        String result = jedis.set("n" + i, "n" + i);
    }
    long end = System.currentTimeMillis();
    System.out.println("Simple SET: " + ((end - start)/1000.0) + " seconds");
    jedis.disconnect();
}
        很简单吧,每次set之后都可以返回结果,标记是否成功。



二.事务方式(Transactions)

        redis的事务很简单,他主要目的是保障,一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令。

        看下面例子:

@Test
public void test2Trans() {
    Jedis jedis = new Jedis("localhost");
    long start = System.currentTimeMillis();
    Transaction tx = jedis.multi();
    for (int i = 0; i < 100000; i++) {
        tx.set("t" + i, "t" + i);
    }
    List<Object> results = tx.exec();
    long end = System.currentTimeMillis();
    System.out.println("Transaction SET: " + ((end - start)/1000.0) + " seconds");
    jedis.disconnect();
}
        我们调用jedis.watch(…)方法来监控key,如果调用后key值发生变化,则整个事务会执行失败。另外,事务中某个操作失败,并不会回滚其他操作。这一点需要注意。还有,我们可以使用discard()方法来取消事务。



三.管道(Pipelining)

        有时,我们需要采用异步方式,一次发送多个指令,不同步等待其返回结果。这样可以取得非常好的执行效率。这就是管道,调用方法如下:

@Test
public void test3Pipelined() {
    Jedis jedis = new Jedis("localhost");
    Pipeline pipeline = jedis.pipelined();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("p" + i, "p" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
    jedis.disconnect();
}


四.管道中调用事务

        就Jedis提供的方法而言,是可以做到在管道中使用事务,其代码如下:

@Test
public void test4combPipelineTrans() {
    jedis = new Jedis("localhost");
    long start = System.currentTimeMillis();
    Pipeline pipeline = jedis.pipelined();
    pipeline.multi();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("" + i, "" + i);
    }
    pipeline.exec();
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    System.out.println("Pipelined transaction: " + ((end - start)/1000.0) + " seconds");
    jedis.disconnect();
}
        但是经测试(见本文后续部分),发现其效率和单独使用事务差不多,甚至还略微差点。



五.分布式直连同步调用

@Test
public void test5shardNormal() {
    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedis sharding = new ShardedJedis(shards);

    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        String result = sharding.set("sn" + i, "n" + i);
    }
    long end = System.currentTimeMillis();
    System.out.println("Simple@Sharing SET: " + ((end - start)/1000.0) + " seconds");

    sharding.disconnect();
}
        这个是分布式直接连接,并且是同步调用,每步执行都返回执行结果。类似地,还有异步管道调用。



六.分布式直连异步调用

@Test
public void test6shardpipelined() {
    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedis sharding = new ShardedJedis(shards);

    ShardedJedisPipeline pipeline = sharding.pipelined();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("sp" + i, "p" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    System.out.println("Pipelined@Sharing SET: " + ((end - start)/1000.0) + " seconds");

    sharding.disconnect();
}


七.分布式连接池同步调用

        如果,你的分布式调用代码是运行在线程中,那么上面两个直连调用方式就不合适了,因为直连方式是非线程安全的,这个时候,你就必须选择连接池调用。

@Test
public void test7shardSimplePool() {
    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);

    ShardedJedis one = pool.getResource();

    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        String result = one.set("spn" + i, "n" + i);
    }
    long end = System.currentTimeMillis();
    pool.returnResource(one);
    System.out.println("Simple@Pool SET: " + ((end - start)/1000.0) + " seconds");

    pool.destroy();
}
        上面是同步方式,当然还有异步方式。



八.分布式连接池异步调用

@Test
public void test8shardPipelinedPool() {
    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);

    ShardedJedis one = pool.getResource();

    ShardedJedisPipeline pipeline = one.pipelined();

    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("sppn" + i, "n" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    pool.returnResource(one);
    System.out.println("Pipelined@Pool SET: " + ((end - start)/1000.0) + " seconds");
    pool.destroy();
}


九.需要注意的地方

        事务和管道都是异步模式。在事务和管道中不能同步查询结果。比如下面两个调用,都是不允许的:

Transaction tx = jedis.multi();
for (int i = 0; i < 100000; i++) {
    tx.set("t" + i, "t" + i);
}
System.out.println(tx.get("t1000").get());  //不允许

List<Object> results = tx.exec();
Pipeline pipeline = jedis.pipelined();
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
pipeline.set("p" + i, "p" + i);
}
System.out.println(pipeline.get("p1000").get()); //不允许

List<Object> results = pipeline.syncAndReturnAll();
        事务和管道都是异步的,个人感觉,在管道中再进行事务调用,没有必要,不如直接进行事务模式。

        分布式中,连接池的性能比直连的性能略好(见后续测试部分)。

        分布式调用中不支持事务。

        因为事务是在服务器端实现,而在分布式中,每批次的调用对象都可能访问不同的机器,所以,没法进行事务。



十.测试

        运行上面的代码,进行测试,其结果如下:

Simple SET: 5.227 seconds
Transaction SET: 0.5 seconds
Pipelined SET: 0.353 seconds
Pipelined transaction: 0.509 seconds
Simple@Sharing SET: 5.289 seconds
Pipelined@Sharing SET: 0.348 seconds
Simple@Pool SET: 5.039 seconds
Pipelined@Pool SET: 0.401 seconds
        另外,经测试分布式中用到的机器越多,调用会越慢。上面是2片,下面是5片:

Simple@Sharing SET: 5.494 seconds
Pipelined@Sharing SET: 0.51 seconds
Simple@Pool SET: 5.223 seconds
Pipelined@Pool SET: 0.518 seconds
        下面是10片:

Simple@Sharing SET: 5.9 seconds
Pipelined@Sharing SET: 0.794 seconds
Simple@Pool SET: 5.624 seconds
Pipelined@Pool SET: 0.762 seconds
        下面是100片:

Simple@Sharing SET: 14.055 seconds
Pipelined@Sharing SET: 8.185 seconds
Simple@Pool SET: 13.29 seconds
Pipelined@Pool SET: 7.767 seconds
        分布式中,连接池方式调用不但线程安全外,根据上面的测试数据,也可以看出连接池比直连的效率更好。



十一.完整的测试代码

package com.bijian.study;

import java.util.Arrays;
import java.util.List;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPipeline;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.Transaction;

import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;

@SuppressWarnings("unused")
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestJedis {

private static Jedis jedis;
private static ShardedJedis sharding;
private static ShardedJedisPool pool;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
List<JedisShardInfo> shards = Arrays.asList(new JedisShardInfo("192.168.128.129", 6379), new JedisShardInfo("192.168.128.129",6379)); // 使用相同的ip:port,仅作测试

jedis = new Jedis("192.168.128.129");
sharding = new ShardedJedis(shards);

pool = new ShardedJedisPool(new JedisPoolConfig(), shards);
}

@AfterClass
public static void tearDownAfterClass() throws Exception {
jedis.disconnect();
sharding.disconnect();
pool.destroy();
}

@Test
public void test1Normal() {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
String result = jedis.set("n" + i, "n" + i);
}
long end = System.currentTimeMillis();
System.out.println("Simple SET: " + ((end - start) / 1000.0)
+ " seconds");
}

@Test
public void test2Trans() {
long start = System.currentTimeMillis();
Transaction tx = jedis.multi();
for (int i = 0; i < 100000; i++) {
tx.set("t" + i, "t" + i);
}
// System.out.println(tx.get("t1000").get());

List<Object> results = tx.exec();
long end = System.currentTimeMillis();
System.out.println("Transaction SET: " + ((end - start) / 1000.0)
+ " seconds");
}

@Test
public void test3Pipelined() {
Pipeline pipeline = jedis.pipelined();
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
pipeline.set("p" + i, "p" + i);
}
// System.out.println(pipeline.get("p1000").get());
List<Object> results = pipeline.syncAndReturnAll();
long end = System.currentTimeMillis();
System.out.println("Pipelined SET: " + ((end - start) / 1000.0)
+ " seconds");
}

@Test
public void test4combPipelineTrans() {
long start = System.currentTimeMillis();
Pipeline pipeline = jedis.pipelined();
pipeline.multi();
for (int i = 0; i < 100000; i++) {
pipeline.set("" + i, "" + i);
}
pipeline.exec();
List<Object> results = pipeline.syncAndReturnAll();
long end = System.currentTimeMillis();
System.out.println("Pipelined transaction: " + ((end - start) / 1000.0)
+ " seconds");
}

@Test
public void test5shardNormal() {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
String result = sharding.set("sn" + i, "n" + i);
}
long end = System.currentTimeMillis();
System.out.println("Simple@Sharing SET: " + ((end - start) / 1000.0)
+ " seconds");
}

@Test
public void test6shardpipelined() {
ShardedJedisPipeline pipeline = sharding.pipelined();
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
pipeline.set("sp" + i, "p" + i);
}
List<Object> results = pipeline.syncAndReturnAll();
long end = System.currentTimeMillis();
System.out.println("Pipelined@Sharing SET: " + ((end - start) / 1000.0)
+ " seconds");
}

@Test
public void test7shardSimplePool() {
ShardedJedis one = pool.getResource();

long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
String result = one.set("spn" + i, "n" + i);
}
long end = System.currentTimeMillis();
pool.returnResource(one);
System.out.println("Simple@Pool SET: " + ((end - start) / 1000.0)
+ " seconds");
}

@Test
public void test8shardPipelinedPool() {
ShardedJedis one = pool.getResource();

ShardedJedisPipeline pipeline = one.pipelined();

long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
pipeline.set("sppn" + i, "n" + i);
}
List<Object> results = pipeline.syncAndReturnAll();
long end = System.currentTimeMillis();
pool.returnResource(one);
System.out.println("Pipelined@Pool SET: " + ((end - start) / 1000.0)
+ " seconds");
}
}
运行结果:

 

Simple SET: 24.316 seconds
Transaction SET: 2.641 seconds
Pipelined SET: 1.016 seconds
Pipelined transaction: 1.484 seconds
Simple@Sharing SET: 29.287 seconds
Pipelined@Sharing SET: 1.953 seconds
Simple@Pool SET: 31.537 seconds
Pipelined@Pool SET: 1.156 seconds
直接查看redis数据库:

[root@localhost bin]# /usr/local/redis/bin/redis-cli
127.0.0.1:6379> dbsize
(integer) 800000
127.0.0.1:6379>


PS:如上实例是基于jedis-2.1.0.jar、commons-pool-1.6.jar、junit-4.11.jar、hamcrest-core-1.3.jar运行的。

http://itindex.net/detail/50647-redis-java-客户端
分享到:
评论

相关推荐

    SpringMVC-Mybatis-Shiro-redis-0.2-master

    基于SpringMVC Mybatis Shiro Redis 的权限管理系统,该系统已经部署到线上,线上访问地址:http://shiro.itboy.net,登录账号:admin 密码:sojson,,详细教程参考sojson.com/shiro

    Redis-x64-3.2.100压缩包及使用说明.rar

    主要文件包括`redis-server.exe`(服务器进程)、`redis-cli.exe`(命令行客户端)和其他配置文件如`redis.conf`。 **安装与启动Redis服务器:** 1. 将解压后的文件夹放在一个方便访问的地方,比如`C:\Redis`。 2. ...

    Redis-x64-5.0.14.1软件安装包

    Redis-x64-5.0.14.1软件安装包:windows安装包,双击安装,下一步下一步。。。。。。即可。【Redis】Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存...

    windows下 64位系统 redis的安装(附教程)

    之前用的redis总是时好时坏,遇到大量写入数据的情况,就会发生运行失灵的去情况,必须重启才行,所以重新上传这个资源 教程地址: https://blog.csdn.net/m_nanle_xiaobudiu/article/details/80448995 有问题可以在...

    Cent OS上 Redis的安装部署(最新详细教程)application

    打开另一个终端窗口,使用Redis客户端`redis-cli`进行连接: ```bash src/redis-cli ``` 输入`ping`命令,如果返回`PONG`,则表示Redis已成功安装并运行。 ### 九、防火墙配置 如果你的Cent OS启用了防火墙,记得...

    redis-5.0.4.tar.gz下载及redis安装过程

    redis-cli 客户端 redis-server 服务端 10: 启动与连接 启动redis并指定配置文件 cd /usr/local/redis ./bin/redis-server ./redis.conf #设置随机启动 vim /etc/rc.local 最后添加: /usr/local/redis/bin/...

    vue3-element-admin:vue3 + element-plus + typescript 后台管理系统

    后端是基于 Spring Boot 3.0 、Spring Security 6.0 、 JWT 、 Redis 、 Mybatis-Plus 、 Knife4j 等技术栈搭建的前后端分离开源权限管理系统。 在线预览地址:http://vue3.youlai.tech 开源仓库地址:...

    redis-7.4.0 source code (https://github.com/redis/redis/release)

    redis-7.4.0 source code (https://github.com/redis/redis/release)

    redis-desktop-manager-0.8.8.384.exe

    标题中的"redis-desktop-manager-0.8.8.384.exe"指的是该软件的一个特定版本,版本号为0.8.8.384,它是一个可执行文件,主要用于Windows操作系统。这个程序为用户提供了一个直观的界面来连接到本地或远程的Redis...

    校园疫情防控管理系统(后端实现SSM)

    校园疫情防控管理系统的设计与实现,该项目为本人毕业设计项目。 使用技术:springboot、Mybatis Plus、MySQL、...前端客户端代码:https://download.csdn.net/download/qq 需要前端代码可以在本人主页中其他资源下载

    linux redis安装(redis-2.6.14.tar.gz)

    wget http://download.redis.io/releases/redis-2.6.14.tar.gz ``` 解压下载的压缩包: ```bash tar zxf redis-2.6.14.tar.gz cd redis-2.6.14 ``` 在源码目录中,执行配置、编译和安装操作: ```bash make sudo...

    tomcat-redis-session-manager-master.rar

    1、tomcat-redis-session-manager-master见目录中的说明 2、示例程序启动顺序 启动redis,启动tomcat,启动nginx 3、访问:http://127.0.0.1 显示nginx欢迎页面 访问:http://127.0.0.1:8088/session 显示tomcat1...

    分布式session分享tomcat-redis-session-manager-master

    tomcat-redis-session-manager-master为tomcat集群分布式session分享功能,详细信息见http://blog.csdn.net/fengshizty?viewmode=list对应内容

    Jeepay基于SpringBoot2+Vue+Redis的企业级聚合支付系统

    Jeepay是一套适合互联网企业使用的开源支付系统,已实现交易、退款、转账、分账等接口,支持服务商特约商户和普通商户接口。...java客户端:https://download.csdn.net/download/hanzhuhuaa/87690135

    jedis-test.7z jedis 简单测试 项目工程

    * Jedis 的源码工程(导入 eclipse 可直接运行): http://download.csdn.net/download/tan3739/9994217 * Jedis 的源码下载(仅含源码,手动导入jar包):http://download.csdn.net/download/tan3739/9993938 * ...

    redis5离线安装文件包,包含redis-5.0.14.tar.gz和redis-4.6.0.gem

    redis-5.0.14/src/redis-cli --cluster create 192.168.129.98:7000 192.168.129.99:7003 192.168.129.99:7002 192.168.129.126:7005 192.168.129.126:7004 192.168.129.98:7001 --cluster-replicas

    redis学习视频

    要检查Redis是否运行正常,可以使用`redis-cli`客户端工具: ``` redis-cli ping ``` 如果返回"PONG",则表明Redis服务器已经正常启动。 七、守护进程模式与自启动 为了在后台运行Redis,可以在启动命令中添加`&`...

    Redis-x64-3.2.100.rar

    同时,`redis-cli.exe`是Redis的命令行客户端,用于与Redis服务器交互。 在实际应用中,Redis常被用作以下场景: - **缓存**:由于其高速的读写性能,Redis常被用来缓存数据库查询结果,减少对数据库的压力。 - **...

Global site tag (gtag.js) - Google Analytics