eying 发表于 2016-2-17 14:28:45

Redis入门1--入门篇

问题导读:





1.什么是Redis?
2.Redis如何安装?
3.Redis客户端有哪些?





static/image/hrline/4.gif


一、Redis简介:

Redis(http://redis.io)是一款开源的、高性能的键-值存储(key-value store),它是用ANSI C来编写。Redis的项目名是Remote Dictionary Server的缩写,但它常被称作是一款数据结构服务器(data structureserver)。Redis的键值可以包括字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)和 有序集合(sorted sets)等数据类型。 对于这些数据类型,你可以执行原子操作。例如:对字符串进行附加操作(append);递增哈希中的值;向列表中增加元素;计算集合的交集、并集与差集等。

为了获得优异的性能,Redis采用了内存中(in-memory)数据集(dataset)的方式。根据使用场景的不同,你可以每隔一段时间将数据集转存到磁盘上来持久化数据,或者在日志尾部追加每一条操作命令。

Redis同样支持主从复制(master-slave replication),并且具有非常快速的非阻塞首次同步(non-blockingfirst synchronization)、网络断开自动重连等功能。同时Redis还具有其它一些特性,其中包括简单的check-and-set机制、pub/sub和配置设置等,以便使得Redis能够表现得更像缓存(cache)。
Redis还提供了丰富的客户端,以便支持现阶段流行的大多数编程语言。

二、Redis安装:

2.4.15目前是最新稳定版。下载地址:http://redis.googlecode.com/files/redis-2.4.15.tar.gz

linux下运行如下命令进行安装(linux上已经安装好了gcc):
$ tar xzf redis-2.4.15.tar.gz
$ cd redis-2.4.15
$ makemake完后 redis-2.4.15/src目录下会出现编译后的redis服务程序redis-server,还有用于测试的客户端程序redis-cli。

下面启动redis服务:
$./redis-server这种方式启动redis 使用的是默认配置。也可以通过启动参数告诉redis使用指定配置文件使用下面命令启动:
$./redis-server ../redis.conf在redis-2.4.15目录下的redis.conf是一个默认的配置文件。我们可以根据需要使用自己的配置文件。

启动redis服务进程后,就可以使用测试客户端程序redis-cli和redis服务交互了:
$ ./redis-cli
redis 127.0.0.1:6379> set foo bar
OK
redis 127.0.0.1:6379> get foo
"bar"
上面演示了get和set命令操作简单类型value的例子。foo是key ,bar是个string类型的value。

停止Redis命令:

./redis-cli-p 6379 shutdown   其中6379是redis的端口号

三、Redis客户端:

Redis的客户端有很多,有C、C++、C#、Java、PHP、Perl、Python、Ruby等等,支持现阶段流行的大多数编程语言,详情请看redis官网:http://redis.io/clients

下面是Java版的Redis客户端示例:

客户端jar包地址https://github.com/xetorthio/jedis/downloads
package com.jd.redis.client;

import redis.clients.jedis.Jedis;

publicclass App {
    publicstaticvoid main(String[] args) {
      Jedis jr = null;
      try {
            //redis服务地址和端口号
            jr = new Jedis("192.168.157.128", 6379);
            String key = "mkey";
            jr.set(key,"hello,redis!");
            String v = jr.get(key);
            String k2 = "count";
            jr.incr(k2);
            jr.incr(k2);
            System.out.println(v);
            System.out.println(jr.get(k2));
      } catch (Exception e) {
            e.printStackTrace();
      }
      finally{
            if(jr!=null){
                jr.disconnect();
            }
      }
    }
}
Jedis客户端支持对象池,可以通过JedisPool.getResource方法从池中获取Jedis客户端对象,通过JedisPool.returnResource方法释放Jedis对象到池中,用对象池我们可以节省很多重新连接Redis Server的建议连接的时间,下面就是不用Jedis对象池与用Jedis对象池的一个性能对比:

测试方法:分别用直接new Jedis和从池中获取Jedis对象的方法,起200个并发,生个并发循环1000次。每个并发线程用一个Jedis对象。

测试代码如下:

package com.jd.redis.client;

import java.util.concurrent.CountDownLatch;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

publicclass JedisPoolTest {

    privatestatic JedisPoolConfigconfig;//Jedis客户端池配置
    privatestatic JedisPoolpool;//Jedis客户端池
   
    static{
      config =new JedisPoolConfig();
      config.setMaxActive(60000);
          config.setMaxIdle(1000);
          config.setMaxWait(10000);
          config.setTestOnBorrow(true);
          pool =new JedisPool(config,"192.168.157.128", 6380);
    }
   
    /**
   * 单笔测试(不用池)
   * @param count
   */
    publicstaticvoid testNoPool(int count){
      for(int i=0;i<count;i++){
            Jedis jr = null;
            try {
                jr = new Jedis("10.10.224.44", 6379);
                testOnce(jr);
            } catch (Exception e) {
                e.printStackTrace();
            }
            finally{
                if(jr!=null)jr.disconnect();
            }
      }
    }
   
    /**
   * 单笔测试(用池)
   * @param count
   */
    publicstaticvoid testWithPool(int count){
      for(int i=0;i<count;i++){
            Jedis jr = null;
            try {
                jr = pool.getResource();
                testOnce(jr);
            } catch (Exception e) {
                e.printStackTrace();
            }
            finally{
                if(jr!=null)pool.returnResource(jr);
            }
      }
    }
   
    /**
   * 并发测试(不用池)
   * @param paiallel并发量
   * @param count每个并发循环次数
   */
    publicstaticvoid paiallelTestNoPool(int paiallel, int count){
      
      Thread[] ts = new Thread;
      
      //用该对象保证所线程都完成主线程才退出
      CountDownLatch cd = new CountDownLatch(paiallel);
      
      long start = System.currentTimeMillis();
      for(int i=0; i < paiallel; i++){
            ts = new Thread(new WorkerNoPool(cd, count));
            ts.start();
      }
      
      try {
            cd.await();//等待所有子线程完成
      } catch (InterruptedException e) {
            e.printStackTrace();
      }
      System.out.println("NoPool useTime:"+ (System.currentTimeMillis() - start));
    }
   
    /**
   * 并发测试(用池)
   * @param paiallel并发量
   * @param count每个并发循环次数
   */
    publicstaticvoid paiallelTestWithPool(int paiallel, int count){
      
      //用该对象保证所线程都完成主线程才退出
      CountDownLatch cd = new CountDownLatch(paiallel);
      
      long start = System.currentTimeMillis();
      Thread[] ts = new Thread;
      for(int i=0; i < paiallel; i++){
            ts = new Thread(new WorkerWithPool(cd, count));
            ts.start();
      }
      try {
            cd.await();//等待所有子线程完成
      } catch (InterruptedException e) {
            e.printStackTrace();
      }
      System.out.println("Pool useTime:"+ (System.currentTimeMillis() - start));
      pool.destroy();
    }
   
    privatestaticvoid testOnce(Jedis jr){
      System.out.println(jr.incr("incrTest"));
    }
   
    publicstaticclass WorkerNoPoolimplements Runnable{
      private CountDownLatchcd;
      privateintcount;
      
      public WorkerNoPool(CountDownLatch cd,int count){
            this.cd = cd;
            this.count = count;
      }
      
      publicvoid run() {
            try {
                testNoPool(this.count);
            } catch (Exception e) {
                e.printStackTrace();
            }
            finally{
                cd.countDown();
            }
      }
    }
   
    publicstaticclass WorkerWithPoolimplements Runnable{
      
      private CountDownLatchcd;
      privateintcount;
      
      public WorkerWithPool(CountDownLatch cd,int count){
            this.cd = cd;
            this.count = count;
      }
      
      publicvoid run() {
            try {
                testWithPool(this.count);
            } catch (Exception e) {
                e.printStackTrace();
            }
            finally{
                cd.countDown();
            }
      }
    }
   
    publicstaticvoid main(String[] args) {
      paiallelTestNoPool(100, 1000);
      //paiallelTestWithPool(100, 1000);
    }

}测试输出:
NoPool useTime:43863 //没用对象池的输出
Pool useTime:12101    //用了对象池的输出

从测试结果看没用对象池的时间要比用了对象池的时间多出31762毫秒,同时没有用对象池的还出现了很多超时情况,用了对象池的都成功了,运行10000次,我们姑且可以认为平均每次请求可以节约3.1762(31762/10000)毫秒连接时间。我用的是Win7中的Jedis Java客户端程序连接局域网的Linux虚拟机上的Redis Server。

各种客户端实际是对Redis Protocol的封装,方便我们使用,了解Redis Protocol后我们也可以自己实现客户端。


相关文章




Redis入门1--入门篇
http://www.aboutyun.com/thread-17346-1-1.html


Redis入门2--Redis数据类型及相关命令
http://www.aboutyun.com/thread-17347-1-1.html



Redis入门3--Redis键值设计和Redis数据存储优化机制
http://www.aboutyun.com/thread-17361-1-1.html



Redis入门4--Redis排序
http://www.aboutyun.com/thread-17377-1-1.html


Redis入门5--Redis事务与Redis管道(pipeline)
http://www.aboutyun.com/thread-17378-1-1.html


Redis入门6--Redis发布/订阅
http://www.aboutyun.com/thread-17384-1-1.html



Redis入门7--Redis持久化
http://www.aboutyun.com/thread-17388-1-1.html


Redis入门8--Redis主从复制与分布式
http://www.aboutyun.com/thread-17401-1-1.html





Data 发表于 2016-2-18 11:21:21

感谢分享

a530491093 发表于 2016-2-18 14:23:42

感谢分享!
页: [1]
查看完整版本: Redis入门1--入门篇