文档章节

Redis入门

喝醉蚊子
 喝醉蚊子
发布于 2017/01/24 10:13
字数 4094
阅读 6
收藏 0

      Redis是Remote Dictionary Server的缩写,它使用字典结构存储数据,允许其他应用通过TCP协议读写字典中的内容,字典里的内容除了字符串,还可以是其他数据类型,支持的数据类型有字符串、散列、列表、集合、有序集合。Reidis在一台普通的笔记本电脑上,一秒内能读写超过十万个键值。 

    相较于传统的关系型数据库,Redis有更好的读/写吞吐能力,能够支撑更高的并发数,而相较于其他的key-value类型的数据库,Redis能够提供更为丰富的数据类型的支持,能够更灵活地满足业务需求。Redis能够高效率地实现诸如排序取topN、访问计数器、队列系统、数据 排重等业务需求,并且通过将服务器设置为cache-only,还能够提供高性能的缓存服务。

1. Redis和Memcache的比较

1)Redis不仅仅支持简单的K/V类型的数据,同时还提供list,set,zset,hash等数据结构的存储。而memcache只支持简单数据类型,需要客户端自己处理复杂对象

2)Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用(PS:持久化在rdb、aof)。Redis借助了fork命令的copy on write机制。在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB文件。  AOF日志的全称是append only file,从名字上我们就能看出来,它是一个追加写入的日志文件。与一般数据库的binlog不同的是,AOF文件是可识别的纯文本,它的内容就是一个个 的Redis标准命令。当然,并不是发送Redis的所有命令都要记录到AOF日志里面,只有那些会导致数据发生修改的命令才会追加到AOF文件。那么每一条修改数据的命令都生成一条日志。(PS:memcache不支持数据持久存储)

3)Memcache可以使用Magent在客户端进行一致性hash做分布式。Redis支持在服务器端做分布式(PS:Twemproxy/Codis/Redis-cluster多种分布式实现方式)

4)Memcache的简单限制就是键(key)和Value的限制。最大键长为250个字符。可以接受的储存数据不能超过1MB(可修改配置文件变大),因为这是典型slab 的最大值,不适合虚拟机使用,而Redis的Key长度支持到512k。

5)Redis使用的是单线程模型,保证了数据按顺序提交。Memcache需要使用cas保证数据一致性。CAS(Check and Set)是一个确保并发一致性的机制,属于“乐观锁”范畴;原理很简单:拿版本号,操作,对比版本号,如果一致就操作,不一致就放弃任何操作。cpu利用方面,由于Redis只使用单核,而Memcache可以使用多核,所以平均每一个核上Redis在存储小数据时比Memcache性能更高。而在100k以上的数据中,Memcache性能要高于Redis 。(PS:Redis可以通过开启多个实例来提高CPU利用率,Memcache默认是单线程,需要编译指定参数才能支持多线程。由于分布式缓存是IO密集型系统,所以性能很多程度受限于网络通信,memcache使用了libevent网络库,redis自己实现了一套自己通信的库。线程也不是影响吞吐量的重要因素,一般情况下,程序处理内存数据的速度远高于网卡接收的速度。使用线程好处是可以同时处理多条连接,在极端情况下,可能会提高响应速度。但是单线程有时候比多线程或多进程更快,比需要考虑并发、锁,也不会增加上下文切换等开销,也即代码更加简洁,执行效率更高)

6)内存管理:memcache使用Slab Allocation。原理相当简单,预先分配一系列大小固定的组,然后根据数据大小选择最合适的块存储。避免了内存碎片。(缺点:不能变长,浪费了一定空间)memcache默认情况下下一个slab的最大值为前一个的1.25倍; Redis通过定义一个数组来记录所有的内存分配情况, Redis采用的是包装的malloc/free,相较于Memcache的内存 管理方法来说,要简单很多。由于malloc 首先以链表的方式搜索已管理的内存中可用的空间分配,导致内存碎片比较多。但是redis刷磁盘的话,会dump内存,内存会翻倍,如果服务器配置不使用swap的话,刷不了磁盘,linux支持swap,需要打开选项。

2. Redis安装

 在linux下还需要安装tcl脚本测试工具

2.1 tcl测试工具

cd /usr/local/src
#wget http://downloads.sourceforge.net/tcl/tcl8.6.3-src.tar.gz
tar -zxvf tcl8.6.3-src.tar.gz
cd ​tcl8.6.3/unix/
./configure
make
make install

2.2 redis安装

mkdir /usr/local/redis

cd /usr/local/src
#wget http://download.redis.io/releases/redis-2.8.19.tar.gz
tar zxvf redis-2.8.19.tar.gz
cd redis-2.8.19
make
make PREFIX=/usr/local/redis install

2.3自启动设置

自启动文件redisd

#!/bin/sh

#chkconfig: 345 86 14

#description: Startup and shutdown script for Redis

PROGDIR=/usr/local/redis/bin #安装路径

PROGNAME=redis-server

DAEMON=$PROGDIR/$PROGNAME

#CONFIG=/etc/redis/redis.conf

PIDFILE=/var/run/redis.pid

DESC="redis daemon"

SCRIPTNAME=/etc/rc.d/init.d/redisd

start()

{

         if test -x $DAEMON

         then

        echo -e "Starting $DESC: $PROGNAME"

                   if $DAEMON $CONFIG

                   then

                            echo -e "OK"

                   else

                            echo -e "failed"

                   fi

         else

                   echo -e "Couldn't find Redis Server ($DAEMON)"

         fi

}

stop()

{

         if test -e $PIDFILE

         then

                   echo -e "Stopping $DESC: $PROGNAME"

                   if kill `cat $PIDFILE`

                   then

                            echo -e "OK"

                   else

                            echo -e "failed"

                   fi

         else

                   echo -e "No Redis Server ($DAEMON) running"

         fi

}

restart()

{

    echo -e "Restarting $DESC: $PROGNAME"

    stop

         start

}

list()

{

         ps aux | grep $PROGNAME

}

case $1 in

         start)

                   start

        ;;

         stop)

        stop

        ;;

         restart)

        restart

        ;;

         list)

        list

        ;;

         *)

        echo "Usage: $SCRIPTNAME {start|stop|restart|list}" >&2

        exit 1

        ;;

esac

exit 0

自启动设置

拷贝 redisd   到  /etc/rc.d/init.d/

chmod +x /etc/rc.d/init.d/redisd
chkconfig --add redisd
chkconfig --level 345 redisd on
chkconfig --list redisd

启动和停止

service redisd start
service redisd stop

3. Redis常用操作

选择比较常用的Jedis来介绍Redis数据访问的API,

Jedis redis = new Jedis ("192.168.136.135",6379);
Redis支持丰富的数据类型,如strings、hashs、lists、sets、sorted sets等,这些数据类型都有对应的API来进行操作。

String

Redis的string类型实际上就是最基本的key-value形式的数 据,一个key对应一个value,它支持如下形式的数据访问:
redis.set("name", "chenkangxian");//设置 key-value 

redis.setex(”content”,5, "hello”);//设置 key-value 有效期为 5 秒
redis.mset(”class”,”a”,”age”,”25”); //—次设置多个 key-value

redis.append(”content”," lucy");//给字符串追加内容

String content = redis.get("content"); //根据 key 获取 value 

List<String> list = redis.mget(”class”,”age”);//-次取多个 key
通过set方法,可以给对应的key设值;通过get方法,可以获取对应key的值;

通过setex 方法可以给key-value设置有效期;

通过mset方法,一次可以设置多个key-value对;

通过mget 方法,可以一次获取多个key对应的value,这样的好处是,可以避免多次请求带来的网络开销, 提高性能;通过append方法,可以给已经存在的key对应的value后追加内容。

原生操作演示:

set www  hhh   

get www

set orderid 100    

 incr  orderid

hash

Redis的hash实际上是一个string类型的field和value的映射表,类似于Map,特别适合 存储对象。相较于将每个对象序列化后存储,一个对象使用hashs存储将会占用更少的存储空间,并且能够更为方便地存取整个对象:

redis.hset("url", "google", "www.google.cn");//给 Hash 添加 key-value 

redis.hset("url", "taobao", "www.taobao.com"); 

redis.hset("url", "sina", "www.sina.com.cn");

Map<String,String> map = new HashMap<String,String>(); 

map.put("name", "chenkangxian"); 

map.put("sex", "man");

map.put("age", "100");

redis.hmset("userinfo", map);//批量设置值

String name = redis.hget("userinfo", "name");//取 Hash 中某个 key 的值 

List<String> urllist = redis.hmget("url","google","taobao","sina");//取Hash的多个key的值

Map<String,String> userinfo = redis.hgetAll("userinfo");//取Hash的所有key的值

通过hset方法,可以给一个Hash存储结构添加key-value数据;

通过hmset方法,能够一 次性设置多个值,避免多次网络操作的开销;

使用hget方法,能够取得一个Hash结构中某个 key对应的value

使用hmget方法,则可以一次性获取得多个key对应的value;

通过hgetAll 方法,可以将Hash存储对应的所有key-value —次性取出。

原生操作演示:

hset person:001 name jack  

hset person:001 age 20  

hkeys person:001

List
Redis的list是一个链表结构,主要的功能是对元素的push和pop,以及获取某个范围内的值等。push和pop操作可以从链表的头部或者尾部插入/删除元素,这使得lists既可以作为栈 使用,又可以作为队列使用,其中,操作的key可以理解为链表的名称:

redis.lpush(”charlist”,"abc");//在 list 首部添加元素 

redis.lpush("charlist", "def");

redis.rpush("charlist", "hij");//在 list 尾部添加元素 

redis.rpush("charlist", "klm");

List<String> charlist = redis.lrange("charlist", 0, 2); 

redis.lpop("charlist");//在 list 首部删除兀素

redis.rpop("charlist");//在 list 尾部删除兀素

Long charlistSize = redis.llen("charlist");//获得 list 的大小
通过lpush和rpush方法,分别可以在list的首部和尾部添加元素;

使用lpop和rpop方法,可以在list的首部和尾部删除元素;

通过lrange方法,可以获取list指定区间的元素。

原生操作演示: lpop  lpush  rpop  rpush

lpush nums 10 20 30 40  

lpop nums

lrange nums 2 4 //下标2--4

 

Set

Redis的set与数据结构的set相似,用来存储一个没有重复元素的集合,对集合的元素可 以进行添加和删除的操作,并且能够对所有元素进行枚举:

redis.sadd("SetMem", "s1");//给 set 添加元素 

redis.sadd("SetMem", "s2"); 

redis.sadd("SetMem", "s3"); 

redis.sadd("SetMem", "s4");

redis.sadd("SetMem", "s5");

redis.srem("SetMem", "s5");//从 set 中移除元素

Set<String> set = redis.smembers("SetMem") ;//枚举出 set 的元素

tag表我们使用集合来存储数据,因为集合擅长求交集、并集

sadd tag:ruby 1

sadd tag:ruby 2

sadd tag:web 2

sadd tag:erlang 3

那么,即属于ruby又属于web的书?

inter_list = redis.sinter("tag.web", "tag:ruby")

即属于ruby,但不属于web的书?

inter_list = redis.sdiff("tag.ruby", "tag:web")

属于ruby和属于web的书的合集?

inter_list = redis.sunion("tag.ruby", "tag:web")

sadd方法用来给set添加新的元素,而srem则可以对元素进行删除,通过smembers方法,能够枚举出set中的所有元素。

原生操作演示:

sadd sz 1

sadd sz 2

smembers sz

spop sz

srem sz 2

 

有序Set

sorted set是Redis set的一个升级版本,它在sets的基础之上增加了一个排序的属性,该属性在添加元素时可以指定,sorted sets将根据该属性来进行排序,每次新元素增加后,sorted sets会重新对顺序进行调整。sorted sets不仅能够通过range正序对set取值,还能够通过range 对set进行逆序取值,极大地提高了 set操作的灵活性:

redis.zadd("SortSetMem" 1 one);//插入sort set,并指定元素的序号 "1");

//根据范围取 set

Set<String> sortset = redis.zrange("SortSetMem", 2, 4);

//根据范围反向取 set

Set<String> revsortset = redis.zrevrange("SortSetMem", 1, 2);

         通过zadd方法来给sorted sets新增元素,在新增操作的同时,需要指定该元素排序的序号, 以便进行排序。使用zrange方法可以正序对set进行范围取值,而通过zrevrange方法,则可以高效率地逆序对set进行范围取值。

原生操作演示:ZADD,ZREM,ZRANGEBYSCORE,ZRANGE

zadd fruits 3.5 apple

zadd fruits 4.1 pear

zadd fruits 9.2 nut

zadd fruits 2.8 grape

zadd fruits 5 banana

zrange fruits 0 -1 withscores //升序展示整个集合

zrevrange fruits 0 -1 withscores//按照下标展示

zrangebyscore fruits 1 4 withscores //按分数展示

zrevrangebyscore fruits 4 1 withscores

zrevrangebyscore fruits 4 1 withscores limit 0 1 //按分数展示 从0开始 展示1个

zrem fruits apple

 

Redis监控

1)开启一个monitor:

redis-cli -h 127.0.0.1 -p 6379 monitor

2)使用redis-benchmark:

redis-benchmark -h 127.0.0.1 -p 6379 -c 500 -n 200000

l redis-benchmark -h 192.168.133.226 -p 6379 -c 100 -n 100000 
100个并发连接,100000个请求,检测host为localhost 端口为6379的redis服务器性能 

l redis-benchmark -h 192.168.133.126 -p 6379 -q -d 100  

测试存取大小为100字节的数据包的性能

l redis-benchmark -t set,lpush -n 100000 -q

只测试某些操作的性能

l redis-benchmark -n 100000 -q script load "redis.call('set','foo','bar')"

只测试某些数值存取的性能

3)Info (memory clients)

4. Redis和spring的结合

这里描述最简单的一种结合方式。

JedisPoolConfig的配置

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">  

       <property name="maxTotal" value="2048" />  
       <property name="maxIdle" value="200" />  
       <property name="numTestsPerEvictionRun" value="1024"/>  
       <property name="timeBetweenEvictionRunsMillis" value="30000" />  
       <property name="minEvictableIdleTimeMillis" value="-1" />  
       <property name="softMinEvictableIdleTimeMillis" value="10000" />  
       <property name="maxWaitMillis" value="1500"/>  
       <property name="testOnBorrow" value="true" />  
       <property name="testWhileIdle" value="true"/>  
       <property name="testOnReturn" value="false"/>  
       <property name="blockWhenExhausted" value="false"/>  
   </bean>  

Java调用:

public static boolean  set(String key,String value) throws Exception{

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

jedis.set(key, value);returntrue;

} catch (Exception e) {

e.printStackTrace();returnfalse;

}finally{

jedisPool.returnResource(jedis);

}

}

放对象

public static boolean  set(String key,Object value){

Jedis jedis = null;

try {

String objectJson = JSON.toJSONString(value);

jedis = jedisPool.getResource();

jedis.set(key, objectJson);returntrue;

} catch (Exception e) {

e.printStackTrace();returnfalse;

}finally{

jedisPool.returnResource(jedis);

}

}

 

取对象

public static Object get(String key){

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

Object value = jedis.get(key);return value;

} catch (Exception e) {

e.printStackTrace();returnfalse;

}finally{

jedisPool.returnResource(jedis);

}

}

其他说明:

Jedis2高版本 的JedisPoolConfig没有maxActive,maxWait属性

更改为:maxActive,maxTotal,maxWaitMillis

 

5. 配置文件redis.config设置

daemonize:是否以后台daemon方式运行   yes 

pidfile:pid文件位置  当redis作为守护进程运行的时候,它会把 pid 默认写到 /var/run/redis.pid 文件里面,

port:监听的端口号   设为 0 ,redis 将不在 socket 上监听任何客户端连接

timeout:请求超时时间

loglevel:log信息级别    notice (适用于生产环境)

logfile:log文件位置

databases:开启数据库的数量

save * *:保存快照的频率,第一个*表示多长时间(秒级),第三个*表示执行多少次写操作。在一定时间内执行一定数量的写操作时,自动保存快照。可设置多个条件。

rdbcompression:是否使用压缩

dbfilename:数据快照文件名(只是文件名,不包括目录)

dir:数据快照的保存目录(这个是目录)

appendonly:是否开启appendonlylog,开启的话每次写操作会记一条log,这会提高数据抗风险能力,但影响效率。

appendfsync:appendonlylog如何同步到磁盘(三个选项,分别是每次写都强制调用fsync、每秒启用一次fsync、不调用fsync等待系统自己同步)

slaveof <masterip> <masterport> :主从配置,在redis-slave上配置master的ip port,即可。

 

集群设置

6. master/slave主从复制Replication

master无需设置,只需要设置slave,replication是由slave发起的。

1)建立与master的连接

   保存要连接的master信息,等待连接REDIS_REPL_CONNECT

   与master建立连接,并注册读写文件事件 REDIS_REPL_CONNECTING

2)向master发起SYNC请求

   向master发送ping命令,确认redis实例 REDIS_REPL_PONG

   收到master的ping命令回复

   向master发送SYNC命令,请求replication

   建立临时文件temp-pid.rdb 准备接收master发送过来的数据

   删除注册的文件事件,重新注册一个新的文件事件readSyncBulkPayRead

   等待发送master发送RDB数据 REDIS_REPL_TRANSFER

3)接收master发送的RDB文件

4)载入RDB数据

 RDB文件节后完毕,开始载入    REDIS_REPL_CONNECTED

7. sentinel实现主从切换

 1)进入bin目录

 cd  /usr/local/redis/bin

 2)启动主redis

   ./redis-server /etc/redis/redis.conf

 3)启动从redis

   ./redis-server /etc/redis/redis6377.conf

   ./redis-server /etc/redis/redis.6376conf

 

 4)动态增加slaves

    ./redis-cli -p 6376 slaveof 192.168.133.126 6379

./redis-cli -p 6377 slaveof 192.168.133.126 6379

5)启动redis sentinel 

     进入/usr/local/redis/bin目录

./redis-sentinel /etc/redis/sentinel.conf

 

查看集群状态

 ./redis-cli -h 192.168.133.126 -p 26379 info Sentinel

 6)手动停止主redis

    ./redis-cli -h 192.168.133.126 -p 6379 shutdown

查看集群状态

 ./redis-cli -h 192.168.133.126 -p 26379 info Sentinel (可能还是以前的,需要新开一个终端查看)

    查询slave状态

      redis-cli -h 192.168.133.126  -p 26379 sentinel slaves mymaster

 

8. 基于sentinel的java调用

Java调用时,不再连接redis而是连接sentinel

JedisPoolConfig poolConfig = new JedisPoolConfig();

String masterName = "mymaster";

Set<String> sentinels = new HashSet<String>();

sentinels.add("192.168.2.97:26379");

//sentinels.add("192.168.2.96:26379");

JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, poolConfig);

HostAndPort currentHostMaster = jedisSentinelPool.getCurrentHostMaster();

System.out.println(currentHostMaster.getHost()+"--"+currentHostMaster.getPort());

//获取主节点的信息

Jedis resource = jedisSentinelPool.getResource();

 String value = resource.get("a");

System.out.println(value);//获得键a对应的value值

resource.close();

 

 

 

 

 

 

© 著作权归作者所有

喝醉蚊子
粉丝 0
博文 1
码字总数 4094
作品 0
郑州
私信 提问
Redis 学习路线

学习和使用 Redis 一般可以分为以下四个阶段: 初学者入门 进阶实战 理解原理 贡献和开发 本文接下来将在四个小节里面分别对这四个阶段进行介绍。 初学者入门 如果你只是对 Redis 感兴趣, ...

JackFace
2016/06/17
203
0
2019最新Java实战开发今日头条资讯网站

==================课程目录===================== 第1节 开发工具和Java语言介绍 主要介绍项目所需要的开发工具,并且会简单回顾这个项目所用到的语言-java,语法基础,控制流,数据结构,面...

weixin_44240109
01/06
0
0
(五)Redis快速入门-Redis数据类型List(列表)

(五)Redis快速入门-Redis数据类型List(列表) 我的系统版本为CentOS7.5,redis版本5.0.4 List(列表) Redis 列表是简单的字符串列表,按照插入顺序排序。 列表最多可存储 232 - 1 元素 ...

Super_RD
04/25
0
0
(十)Redis快速入门-centos7下配置redis开机自启动

(十)Redis快速入门-centos7下配置redis开机自启动 我的系统版本为CentOS7.5,redis版本5.0.4 redis连接客户端和服务程序在相同目录中,运行redis-cli即可打开客户端...

Super_RD
04/30
0
0
2019最全Java实战开发今日头条资讯网站

==================课程目录===================== 第1节 开发工具和Java语言介绍 主要介绍项目所需要的开发工具,并且会简单回顾这个项目所用到的语言-java,语法基础,控制流,数据结构,面...

@只想搞钱
01/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
今天
6
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
今天
6
0
【技术分享】TestFlight测试的流程文档

上架基本需求资料 1、苹果开发者账号(如还没账号先申请-苹果开发者账号申请教程) 2、开发好的APP 通过本篇教程,可以学习到ios证书申请和打包ipa上传到appstoreconnect.apple.com进行TestF...

qtb999
今天
10
0
再见 Spring Boot 1.X,Spring Boot 2.X 走向舞台中心

2019年8月6日,Spring 官方在其博客宣布,Spring Boot 1.x 停止维护,Spring Boot 1.x 生命周期正式结束。 其实早在2018年7月30号,Spring 官方就已经在博客进行过预告,Spring Boot 1.X 将维...

Java技术剑
今天
17
0
浅谈java过滤器Filter

一、简介 Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码、做一些业务逻辑判断如是否有权限访问页面等。其工作原理是,只要你在web.xml...

青衣霓裳
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部