Redis介绍什么是NoSql为了解决高并发、高可扩展、高可用、大数据存储问题而产生的数据库解决方案,就是NoSql数据库。NoSQL,泛指 非关系型的数据库,NoSQL即Not-OnlySQL,它可以作为关系型数据库的良好补充。Nosql数据库分类键值(Key-Val ue)存储数据库相关产品:TokyoCabinet/Tyrant、Redis、Voldemort、BerkeleyDB典型应 用:内容缓存,主要用于处理大量数据的高访问负载。数据模型:一系列键值对优势:快速查询劣势:存储的数据缺少结构化列存储数据 库相关产品:Cassandra,HBase,Riak典型应用:分布式的文件系统数据模型:以列簇式存储,将同一列数据存在一起优势 :查找速度快,可扩展性强,更容易进行分布式扩展劣势:功能相对局限文档型数据库相关产品:CouchDB、MongoDB典型应用:W eb应用(与Key-Value类似,Value是结构化的)数据模型:一系列键值对优势:数据结构要求不严格劣势:查询性能不高 ,而且缺乏统一的查询语法图形(Graph)数据库相关数据库:Neo4J、InfoGrid、InfiniteGraph典型应用:社 交网络数据模型:图结构优势:利用图结构相关算法。劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。什么是RedisR edis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求, 目前为止Redis支持的键值数据类型如下:字符串类型散列类型列表类型集合类型有序集合类型。redis历史发展2008年,意大利的一 家创业公司Merzia推出了一款基于MySQL的网站实时统计系统LLOOGG,然而没过多久该公司的创始人SalvatoreSa nfilippo便对MySQL的性能感到失望,于是他决定亲自为LLOOGG量身定做一个数据库,并于2009年开发完成,这个数据库 就是Redis。不过SalvatoreSanfilippo并不满足只将Redis用于LLOOGG这一款产品,而是希望更多的人使 用它,于是在同一年SalvatoreSanfilippo将Redis开源发布,并开始和Redis的另一名主要的代码贡献者Piet erNoordhuis一起继续着Redis的开发,直到今天。SalvatoreSanfilippo自己也没有想到,短短的几年时 间,Redis就拥有了庞大的用户群体。HackerNews在2012年发布了一份数据库的使用情况调查,结果显示有近12%的公司在 使用Redis。国内如新浪微博、街旁网、知乎网,国外如GitHub、StackOverflow、Flickr等都是Redis的用 户。VMware公司从2010年开始赞助Redis的开发,SalvatoreSanfilippo和PieterNoordhu is也分别在3月和5月加入VMware,全职开发Redis。redis的应用场景缓存(数据查询、短连接、新闻内容、商品内容等等)。 (最多使用)分布式集群架构中的session分离。聊天室的在线好友列表。任务队列。(秒杀、抢购、12306等等)应用排行榜。网站访 问统计。数据过期处理(可以精确到毫秒)Redis安装配置Redis下载官网地址:http://redis.io/http://re dis.io/下载地址:http://download.redis.io/releases/redis-3.0.0.tar.gzh ttp://download.redis.io/releases/redis-3.0.0.tar.gzRedis安装Redis是C 语言开发,建议在linux上运行,本教程使用Centos6.4作为安装环境。第一步:在VMware中安装CentOS(参考Linu x教程中的安装虚拟机)第二步:在Linux下安装gcc环境(该步骤可以省略,CentOS中默认自带C环境)[root@linux0 2redis-3.0.0]#yuminstallgcc-c++第三步:将下载的Redis源码包上传到Linux服务器中【需 要切换到sftp窗口】sftp>put-r"E:\03-teach\03-讲课\0707\04-redis\res\redi s-3.0.0.tar.gz"第四步:解压缩Redis源码包[root@linux02~]#tar-zxfredis-3. 0.0.tar.gz第五步:编译redis源码[root@linux02~]#cdredis-3.0.0[root@linu x02redis-3.0.0]#make第六步:安装redis[root@linux02redis-3.0.0]#make installPREFIX=/usr/local/redis0707Redis启动前端启动启动方式:直接运行bin/redis -server将以前端模式启动。[root@linux02bin]#./redis-server启动缺点:ssh命令窗口关闭则 redis-server程序结束,不推荐使用此方法启动图例:前端启动的关闭:ctrl+c后端启动第一步:将redis源码包中的re dis.conf配置文件复制到/usr/local/redis/bin/下[root@linux02/]#cd/root/r edis-3.0.0[root@linux02redis-3.0.0]#cpredis.conf/usr/local/re dis0707/bin/第二步:修改redis.conf,将daemonize由no改为yes[root@redis01bin2 ]#vimredis.conf第三步:执行命令[root@linux02bin]#./redis-serverredis .conf后端启动的关闭方式非正常关闭(不推荐使用):[root@localhost-0723bin]#kill5528正常 关闭:[root@localhost-0723bin]#./redis-clishutdownRedis客户端Redis自带 的客户端指定主机和端口[root@localhost-0723bin]#./redis-cli-h127.0.0.1-p 6379-h:redis服务器的ip地址-p:redis实例的端口号如果不指定主机和端口也可以[root@localhost-0 723bin]#./redis-cli默认主机地址是127.0.0.1默认端口是6379图形界面客户端(了解)前提:需要安装 图形界面管理器连接超时解决远程连接redis服务,需要关闭或者修改防火墙配置。第一步:编辑iptables[root@redis0 1bin]#vim/etc/sysconfig/iptables在命令模式下,选定要复制的那一行的末尾,然后点击键盘yyp, 就完成复制,然后修改。第二步:重启防火墙[root@localhost-0723redis-3.0.0]#serviceip tablesrestartiptables:清除防火墙规则:[确定]iptables:将链设置为政策ACCEPT:filte r[确定]iptables:正在卸载模块:[确定]iptables:应用防火墙规则:[ 确定][root@localhost-0723redis-3.0.0]#注意:默认一共是16个数据库,每个数据库之间是相互隔离 。数据库的数量是在redis.conf中配置的。切换数据库使用命令:select数据库编号例如:select1Java客户端J edisjedis介绍Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、 Node.js、Go等。在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis、 等其中官方推荐使用Jedis和Redisson。在企业中用的最多的就是Jedis,下面我们就重点学习下Jedis。Jedis同 样也是托管在github上,地址:https://github.com/xetorthio/jedis添加jar包单实例连接@Te stpublicvoidtestJedis(){//创建一个Jedis的连接Jedisjedis=newJedis( "127.0.0.1",6379);//执行redis命令jedis.set("mytest","helloworld,t hisisjedisclient!");//从redis中取值Stringresult=jedis.get("myte st");//打印结果System.out.println(result);//关闭连接jedis.close();}连接池连接@ TestpublicvoidtestJedisPool(){//创建一连接池对象JedisPooljedisPool= newJedisPool("127.0.0.1",6379);//从连接池中获得连接Jedisjedis=jedisPo ol.getResource();Stringresult=jedis.get("mytest");System.out.p rintln(result);//关闭连接jedis.close();//关闭连接池jedisPool.close();}Spri ng整合jedisPool(自学)添加spring的jar包配置spring配置文件applicationContext.xml< ?xmlversion="1.0"encoding="UTF-8"?>ingframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/X MLSchema-instance"xmlns:mvc="http://www.springframework.org/sche ma/mvc"xmlns:context="http://www.springframework.org/schema/conte xt"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx ="http://www.springframework.org/schema/tx"xsi:schemaLocation="ht tp://www.springframework.org/schema/beanshttp://www.springframew ork.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframew ork.org/schema/mvchttp://www.springframework.org/schema/mvc/spri ng-mvc-3.2.xsdhttp://www.springframework.org/schema/contexthttp ://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aophttp://www.springframew ork.org/schema/aop/spring-aop-3.2.xsdhttp://www.springframework. org/schema/txhttp://www.springframework.org/schema/tx/spring-tx- 3.2.xsd">lients.jedis.JedisPoolConfig">tal"value="30"/>"10"/>"value="1024"/>nEvictionRunsMillis"value="30000"/>ame="minEvictableIdleTimeMillis"value="1800000"/>leIdleTimeMillis"value="10000"/>/>="true"/>yname="blockWhenExhausted"value="false"/>"destroy-method="close">edisPoolConfig"/>.130"/>s>测试代码@TestpublicvoidtestJedisPool(){JedisPoolpool=(JedisPo ol)applicationContext.getBean("jedisPool");Jedisjedis=null;tr y{jedis=pool.getResource();jedis.set("name","lisi");Stringna me=jedis.get("name");System.out.println(name);}catch(Exceptio nex){ex.printStackTrace();}finally{if(jedis!=null){//关闭连 接jedis.close();}}}Redis数据类型Redis中存储数据是通过key-value存储的,对于value的类型有以 下几种:字符串Hash类型ListSetSortedSet(zset)PS:在redis中的命令语句中,命令是忽略大小写的,而ke y是不忽略大小写的。String类型命令赋值语法:SETkeyvalue127.0.0.1:6379>settest12 3OK取值语法:GETkey127.0.0.1:6379>gettest"123“设置/获取多个键值语法:MSETkey value[keyvalue…]MGETkey[key…]127.0.0.1:6379>msetk1v1k2 v2k3v3OK127.0.0.1:6379>getk1"v1"127.0.0.1:6379>mgetk1k31) "v1"2)"v3"取值并赋值语法:GETSETkeyvalue127.0.0.1:6379>getsets2222 "111"127.0.0.1:6379>gets2"222"删除语法:DELkey127.0.0.1:6379>delt est(integer)1数值增减递增数字当存储的字符串是整数时,Redis提供了一个实用的命令INCR,其作用是让当前键值递 增,并返回递增后的值。语法:INCRkey127.0.0.1:6379>incrnum(integer)1127.0.0. 1:6379>incrnum(integer)2127.0.0.1:6379>incrnum(integer)3增加指 定的整数语法:INCRBYkeyincrement127.0.0.1:6379>incrbynum2(integer) 5127.0.0.1:6379>incrbynum2(integer)7127.0.0.1:6379>incrbynu m2(integer)9递减数值语法:DECRkey127.0.0.1:6379>decrnum(integer)91 27.0.0.1:6379>decrnum(integer)8减少指定的整数语法:DECRBYkeydecrement 127.0.0.1:6379>decrnum(integer)6127.0.0.1:6379>decrnum(integ er)5127.0.0.1:6379>decrbynum3(integer)2127.0.0.1:6379>decrb ynum3(integer)-1其它命令(自学)向尾部追加值APPEND的作用是向键值的末尾追加value。如果键不存在则 将该键的值设置为value,即相当于SETkeyvalue。返回值是追加后字符串的总长度。语法:APPENDkeyva lue127.0.0.1:6379>setstrhelloOK127.0.0.1:6379>appendstr"wo rld!"(integer)12127.0.0.1:6379>getstr"helloworld!"获取字符串长度ST RLEN命令返回键值的长度,如果键不存在则返回0。语法:STRLENkey127.0.0.1:6379>strlenstr (integer)0127.0.0.1:6379>setstrhelloOK127.0.0.1:6379>strlen str(integer)5应用自增主键商品编号、订单号采用string的递增数字特性生成。定义商品编号key:items:id 192.168.101.3:7003>INCRitems:id(integer)2192.168.101.3:7003>I NCRitems:id(integer)3Hash类型使用string的问题假设有User对象以JSON序列化的形式存储到Re dis中,User对象有id,username、password、age、name等属性,存储的过程如下:保存、更新:User 对象json(string)redis如果在业务上只是更新age属性,其他的属性并不做更新我应该怎么做呢?如果仍然采用 上边的方法在传输、处理时会造成资源浪费,下边讲的hash可以很好的解决这个问题。redishash介绍hash叫散列类型,它提供 了字段和字段值的映射。字段值只能是字符串类型,不支持散列类型、集合类型等其它类型。如下:命令赋值HSET命令不区分插入和更新操作, 当执行插入操作时HSET命令返回1,当执行更新操作时返回0。一次只能设置一个字段值语法:HSETkeyfieldvalue1 27.0.0.1:6379>hsetuserusernamezhangsan(integer)1一次可以设置多个字段值 语法:HMSETkeyfieldvalue[fieldvalue...]127.0.0.1:6379>hmsetu serage20usernamelisiOK当字段不存在时赋值,类似HSET,区别在于如果字段存在,该命令不执行任何操作 语法:HSETNXkeyfieldvalue127.0.0.1:6379>hsetnxuserage30如果user 中没有age字段则设置age值为30,否则不做任何操作(integer)0取值一次只能获取一个字段值语法:HGETkeyf ield127.0.0.1:6379>hgetuserusername"zhangsan“一次可以获取多个字段值语法:HMG ETkeyfield[field...]127.0.0.1:6379>hmgetuserageusername1) "20"2)"lisi"获取所有字段值语法:HGETALLkey127.0.0.1:6379>hgetalluser1) "age"2)"20"3)"username"4)"lisi"删除字段可以删除一个或多个字段,返回值是被删除的字段个数语 法:HDELkeyfield[field...]127.0.0.1:6379>hdeluserage(integer )1127.0.0.1:6379>hdeluseragename(integer)0127.0.0.1:6379>h deluserageusername(integer)1增加数字语法:HINCRBYkeyfieldincrem ent127.0.0.1:6379>hincrbyuserage2将用户的年龄加2(integer)22127.0.0. 1:6379>hgetuserage获取用户的年龄"22“其它命令(自学)判断字段是否存在语法:HEXISTSkeyfi eld127.0.0.1:6379>hexistsuserage查看user中是否有age字段(integer)1127. 0.0.1:6379>hexistsusername查看user中是否有name字段(integer)0只获取字段名或字段 值语法:HKEYSkeyHVALSkey127.0.0.1:6379>hmsetuserage20namelisi OK127.0.0.1:6379>hkeysuser1)"age"2)"name"127.0.0.1:6379>hva lsuser1)"20"2)"lisi"获取字段数量语法:HLENkey127.0.0.1:6379>hlenuse r(integer)2应用存储商品信息商品字段【商品id、商品名称、商品描述、商品库存、商品好评】定义商品信息的key商品100 1的信息在Redis中的key为:[items:1001]存储商品信息192.168.101.3:7003>HMSETite ms:1001id3nameappleprice999.9OK获取商品信息192.168.101.3:7003>HG ETitems:1001id"3"192.168.101.3:7003>HGETALLitems:10011)"id"2 )"3"3)"name"4)"apple"5)"price"6)"999.9"List类型ArrayList与Linke dList的区别ArrayList使用数组方式存储数据,所以根据索引查询数据速度快,而新增或者删除元素时需要设计到位移操作,所以比 较慢。LinkedList使用双向链表方式存储数据,每个元素都记录前后元素的指针,所以插入、删除数据时只是更改前后元素的指针指向 即可,速度非常快。然后通过下标查询元素时需要从头开始索引,所以比较慢,但是如果查询前几个元素或后几个元素速度比较快。redisl ist介绍列表类型(list)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段。列表类型内部 是使用双向链表(doublelinkedlist)实现的,所以向列表两端添加元素的时间复杂度为0(1),获取越接近两端的元素速 度就越快。这意味着即使是一个有几千万个元素的列表,获取头部或尾部的10条记录也是极快的。命令向列表两端增加元素向列表左边增加元素 语法:LPUSHkeyvalue[value...]127.0.0.1:6379>lpushlist:1123( integer)3向列表右边增加元素语法:RPUSHkeyvalue[value...]127.0.0.1:6379> rpushlist:1456(integer)3查看列表LRANGE命令是列表类型最常用的命令之一,获取列表中的某一 片段,将返回start、stop之间的所有元素(包含两端的元素),索引从0开始。索引可以是负数,如:“-1”代表最后边的一个元素。 语法:LRANGEkeystartstop127.0.0.1:6379>lrangelist:1021)"2"2) "1"3)"4"从列表两端弹出元素LPOP命令从列表左边弹出一个元素,会分两步完成:第一步是将列表左边的元素从列表中移除第二 步是返回被移除的元素值。语法:LPOPkeyRPOPkey127.0.0.1:6379>lpoplist:1"3“127. 0.0.1:6379>rpoplist:1"6“获取列表中元素的个数语法:LLENkey127.0.0.1:6379>l lenlist:1(integer)2其它命令(自学)删除列表中指定的值LREM命令会删除列表中前count个值为value 的元素,返回实际删除的元素个数。根据count值的不同,该命令的执行方式会有所不同:当count>0时,LREM会从列表左边开 始删除。当count<0时,LREM会从列表后边开始删除。当count=0时,LREM删除所有值为value的元素。语法 :LREMkeycountvalue获得/设置指定索引的元素值获得指定索引的元素值语法:LINDEXkeyindex1 27.0.0.1:6379>lindexl:list2"1"设置指定索引的元素值语法:LSETkeyindexvalu e127.0.0.1:6379>lsetl:list22OK127.0.0.1:6379>lrangel:list0 -11)"6"2)"5"3)"2"4)"2"只保留列表指定片段指定范围和LRANGE一致语法:LTRIMkeyst artstop127.0.0.1:6379>lrangel:list0-11)"6"2)"5"3)"0"4)"2 "127.0.0.1:6379>ltriml:list02OK127.0.0.1:6379>lrangel:list 0-11)"6"2)"5"3)"0"向列表中插入元素该命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个 参数是BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。语法:LINSERTkeyBEFORE|AFT ERpivotvalue127.0.0.1:6379>lrangelist0-11)"3"2)"2"3)"1"1 27.0.0.1:6379>linsertlistafter34(integer)4127.0.0.1:6379>l rangelist0-11)"3"2)"4"3)"2"4)"1"将元素从一个列表转移到另一个列表中语法:RPOPL PUSHsourcedestination127.0.0.1:6379>rpoplpushlistnewlist"1" 127.0.0.1:6379>lrangenewlist0-11)"1"127.0.0.1:6379>lrangel ist0-11)"3"2)"4"3)"2"应用商品评论列表思路:在Redis中创建商品评论列表用户发布商品评论,将评论信 息转成json存储到list中。用户在页面查询评论列表,从redis中取出json数据展示到页面。定义商品评论列表key:商品编号 为1001的商品评论key【items:comment:1001】192.168.101.3:7001>LPUSHitems :comment:1001''{"id":1,"name":"商品不错,很好!!","date":1430295077289}''S et类型redisset介绍集合中的数据是不重复且没有顺序。集合类型和列表类型的对比:集合类型的常用操作是向集合中加入或删除元素 、判断某个元素是否存在等,由于集合类型的Redis内部是使用值为空的散列表实现,所有这些操作的时间复杂度都为0(1)。Redis 还提供了多个集合之间的交集、并集、差集的运算。命令增加/删除元素语法:SADDkeymember[member...]1 27.0.0.1:6379>saddsetabc(integer)3127.0.0.1:6379>saddset a(integer)0语法:SREMkeymember[member...]127.0.0.1:6379>srems etcd(integer)1获得集合中的所有元素语法:SMEMBERSkey127.0.0.1:6379>smembe rsset1)"b"2)"a”判断元素是否在集合中语法:SISMEMBERkeymember127.0.0.1:6379 >sismemberseta(integer)1127.0.0.1:6379>sismemberseth(integ er)0运算命令集合的差集运算A-B属于A并且不属于B的元素构成的集合。语法:SDIFFkey[key...]127. 0.0.1:6379>saddsetA123(integer)3127.0.0.1:6379>saddsetB2 34(integer)3127.0.0.1:6379>sdiffsetAsetB1)"1"127.0.0.1:63 79>sdiffsetBsetA1)"4"集合的交集运算A∩B属于A且属于B的元素构成的集合。语法:SINTER key[key...]127.0.0.1:6379>sintersetAsetB1)"2"2)"3"集合的并集运 算A∪B属于A或者属于B的元素构成的集合语法:SUNIONkey[key...]127.0.0.1:6379>sun ionsetAsetB1)"1"2)"2"3)"3"4)"4"其它命令(自学)获得集合中元素的个数语法:SCARD key127.0.0.1:6379>smemberssetA1)"1"2)"2"3)"3"127.0.0.1:6379 >scardsetA(integer)3从集合中弹出一个元素注意:由于集合是无序的,所有SPOP命令会从集合中随机选择一个 元素弹出语法:SPOPkey127.0.0.1:6379>spopsetA"1“SortedSet类型zsetredi ssortedset介绍在集合类型的基础上,有序集合类型为集合中的每个元素都关联一个分数,这使得我们不仅可以完成插入、删除和判 断元素是否存在在集合中,还能够获得分数最高或最低的前N个元素、获取指定分数范围内的元素等与分数有关的操作。在某些方面有序集合和列 表类型有些相似。1、二者都是有序的。2、二者都可以获得某一范围的元素。但是,二者有着很大区别:1、列表类型是通过链表实现的 ,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会变慢。2、有序集合类型使用散列表实现,所有即使读取位于中间部分 的数据也很快。3、列表中不能简单的调整某个元素的位置,但是有序集合可以(通过更改分数实现)4、有序集合要比列表类型更耗内存。 命令增加元素向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素个 数,不包含之前已经存在的元素。语法:ZADDkeyscoremember[scoremember...]127.0. 0.1:6379>zaddscoreboard80zhangsan89lisi94wangwu(integer) 3127.0.0.1:6379>zaddscoreboard97lisi(integer)0获取元素的分数语法:Z SCOREkeymember127.0.0.1:6379>zscorescoreboardlisi"97"删除元素移除 有序集key中的一个或多个成员,不存在的成员将被忽略。当key存在但不是有序集类型时,返回一个错误。语法:ZREMkeymem ber[member...]127.0.0.1:6379>zremscoreboardlisi(integer)1获得 排名在某个范围的元素列表获得排名在某个范围的元素列表按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包含 两端的元素)语法:ZRANGEkeystartstop[WITHSCORES]127.0.0.1:6379>zrange scoreboard021)"zhangsan"2)"wangwu"3)"lisi“按照元素分数从大到小的顺序返回索引 从start到stop之间的所有元素(包含两端的元素)语法:ZREVRANGEkeystartstop[WITHSCORE S]127.0.0.1:6379>zrevrangescoreboard021)"lisi"2)"wangwu"3 )"zhangsan“如果需要获得元素的分数的可以在命令尾部加上WITHSCORES参数127.0.0.1:6379>z rangescoreboard01WITHSCORES1)"zhangsan"2)"80"3)"wangwu"4) "94"其它命令(自学)获得指定分数范围的元素语法:ZRANGEBYSCOREkeyminmax[WITHSCORES] [LIMIToffsetcount]127.0.0.1:6379>ZRANGEBYSCOREscoreboard90 97WITHSCORES1)"wangwu"2)"94"3)"lisi"4)"97"127.0.0.1:6379>ZR ANGEBYSCOREscoreboard70100limit121)"wangwu"2)"lisi"增加某个元素 的分数返回值是更改后的分数语法:ZINCRBYkeyincrementmember127.0.0.1:6379>ZIN CRBYscoreboard4lisi"101“获得集合中元素的数量语法:ZCARDkey127.0.0.1:6379 >ZCARDscoreboard(integer)3获得指定分数范围内的元素个数语法:ZCOUNTkeyminmax 127.0.0.1:6379>ZCOUNTscoreboard8090(integer)1按照排名范围删除元素语法:Z REMRANGEBYRANKkeystartstop127.0.0.1:6379>ZREMRANGEBYRANKscor eboard01(integer)2127.0.0.1:6379>ZRANGEscoreboard0-11)"l isi"按照分数范围删除元素语法:ZREMRANGEBYSCOREkeyminmax127.0.0.1:6379>zad dscoreboard84zhangsan(integer)1127.0.0.1:6379>ZREMRANGEBYSCO REscoreboard80100(integer)1获取元素的排名从小到大语法:ZRANKkeymember127 .0.0.1:6379>ZRANKscoreboardlisi(integer)0从大到小语法:ZREVRANKkey member127.0.0.1:6379>ZREVRANKscoreboardzhangsan(integer)1应用 商品销售排行榜需求:根据商品销售量对商品进行排行显示思路:定义商品销售排行榜(sortedset集合),Key为items:se llsort,分数为商品销售量。写入商品销售量:商品编号1001的销量是9,商品编号1002的销量是10192.168.101.3 :7007>ZADDitems:sellsort91001101002商品编号1001的销量加1192.168.101 .3:7001>ZINCRBYitems:sellsort11001商品销量前10名:192.168.101.3:7001 >ZRANGEitems:sellsort09withscoresKeys命令(了解)设置key的生存时间Redis在实 际使用过程中更多的用作缓存,然而缓存的数据一般都是需要设置生存时间的,即:到期后数据销毁。EXPIREkeyseconds设 置key的生存时间(单位:秒)key在多少秒后会自动删除TTLkey查看key生于的生存时间PERSISTkey清除生存时间 PEXPIREkeymilliseconds生存时间设置单位为:毫秒例子:192.168.101.3:7002>sett est1设置test的值为1OK192.168.101.3:7002>gettest获取test的值"1"192.168.1 01.3:7002>EXPIREtest5设置test的生存时间为5秒(integer)1192.168.101.3:70 02>TTLtest查看test的生于生成时间还有1秒删除(integer)1192.168.101.3:7002>TTL test(integer)-2192.168.101.3:7002>gettest获取test的值,已经删除(nil)其它 命令(自学)keys返回满足给定pattern的所有keyredis127.0.0.1:6379>keysmylist1 )"mylist"2)"mylist5"3)"mylist6"4)"mylist7"5)"mylist8"exists确 认一个key是否存在示例:从结果来看,数据库中不存在HongWan这个key,但是age这个key是存在的redis12 7.0.0.1:6379>existsHongWan(integer)0redis127.0.0.1:6379>exis tsage(integer)1redis127.0.0.1:6379>del删除一个keyredis127.0.0.1:6 379>delage(integer)1redis127.0.0.1:6379>existsage(integer) 0rename重命名key示例:age成功的被我们改名为age_new了redis127.0.0.1:6379[1]>ke ys1)"age"redis127.0.0.1:6379[1]>renameageage_newOKredis12 7.0.0.1:6379[1]>keys1)"age_new"redis127.0.0.1:6379[1]>type返回 值的类型示例:这个方法可以非常简单的判断出值的类型redis127.0.0.1:6379>typeaddrstringred is127.0.0.1:6379>typemyzset2zsetredis127.0.0.1:6379>typemyl istlistredis127.0.0.1:6379>Redis持久化方案RDB持久化RDB方式的持久化是通过快照(snapsh otting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘。RDB是Redis默认采用的持久化方式 。save9001save30010save6010000持久化条件配置在redis.conf中修改持久化快照的条件, 如下:save开头的一行就是持久化配置,可以配置多个条件(每行配置一个条件),每个条件之间是“或”的关系。“save9001 ”表示15分钟(900秒钟)内至少1个键被更改则进行快照。“save30010”表示5分钟(300秒)内至少10个键被更改则进 行快照。配置快照文件目录配置dir指定rdb快照文件的位置#Notethatyoumustspecifyadirec toryhere,notafilename.dir./配置快照文件的名称设置dbfilename指定rdb快照文件的名 称#ThefilenamewheretodumptheDBdbfilenamedump.rdbRedis启动后会读 取RDB快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将记录一千万个字符串类型键、大 小为1GB的快照文件载入到内存中需要花费20~30秒钟。问题总结通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次 快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围 。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。AOF持久化默认情况下Redis没有开启AOF(app endonlyfile)方式的持久化可以通过修改redis.conf配置文件中的appendonly参数开启appendonl yyes开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保 存位置和RDB文件的位置相同,都是通过dir参数设置的。dir./默认的文件名是appendonly.aof,可以通过appen dfilename参数修改:appendfilenameappendonly.aofRedis的主从复制什么是主从复制持久化保证 了即使redis服务重启也不会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到内存中,但是当redis服务器的硬盘损 坏了可能会导致数据丢失,如果通过redis的主从复制机制就可以避免这种单点故障,如下图:主Redis(master)从Redis 1(slave)从Redis2(slave)说明:主redis中的数据有两个副本(replication)即从redis1和从 redis2,即使一台redis服务器宕机其它两台redis服务也可以继续提供服务。主redis中的数据和从redis上的数据保持 实时同步,当主redis写入数据时通过主从复制机制会复制到两个从redis服务上。只有一个主redis,可以有多个从redis。主 从复制不会阻塞master,在同步数据时,master可以继续处理client请求一个redis可以即是主又是从,如下图:主R edis(master)从Redis1(slave)从Redis2(slave)从Redis3(slave)从Redis4 (slave)主从配置主redis配置无需特殊配置。从redis配置修改从redis服务器上的redis.conf文件#sla veofslaveof127.0.0.16379上边的配置说明当前该【从red is服务器】所对应的【主redis服务器】的IP是192.168.101.3,端口是6379。Redis集群redis-clust er架构图架构细节:(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.(2)节点 的fail是通过集群中超过半数的节点检测失效时才生效.(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集 群所有节点,连接集群中任何一个可用节点即可(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cl uster负责维护node<->slot<->valueRedis集群中内置了16384个哈希槽,当需要在Redis集 群中放置一个key-value时,redis先对key使用crc16算法算出一个结果,然后把结果对16384求余 数,这样每个key都会对应一个编号在0-16383之间的哈希槽,redis会根据节点数量大致均等的将哈希槽映射到不同的节 点示例如下:redis-cluster投票:容错(1)集群中所有master参与投票,如果半数以上master节点与其中一个mas ter节点通信超过(cluster-node-timeout),认为该master节点挂掉.(2):什么时候整个集群不可用(clu ster_state:fail)??如果集群任意master挂掉,且当前master没有slave,则集群进入fail状态。也可以 理解成集群的[0-16383]slot映射不完全时进入fail状态。如果集群超过半数以上master挂掉,无论是否有slave,集 群进入fail状态。搭建Ruby环境redis集群管理工具redis-trib.rb依赖ruby环境,首先需要安装ruby环境。安 装ruby[root@redis01bin]#yuminstallruby[root@redis01bin]#yum installrubygems使用sftp工具上传redis-3.0.0.gem至/usr/local下sftp>put-r "E:\03-teach\03-讲课\0707\04-redis\res\ruby和redis接口\redis-3.0.0.ge m"安装ruby和redis的接口程序[root@linux02local]#geminstall/usr/local/r edis-3.0.0.gem将Redis集群搭建脚本文件复制到/usr/local/redis0707目录下[root@redis 01/]#cd/root/redis-3.0.0/src/[root@redis01src]#ll.rb-rwxrw xr-x.1rootroot481414月12015redis-trib.rb[root@redis01src] #cpredis-trib.rb/usr/local/redis0707/-r集群的搭建过程第一步:创建6个redis实例 ,需要端口号7001~7006第二步:修改redis.conf配置文件,打开Cluster-enableyes第三步:启动所有的 实例第四步:创建集群[root@localhost-0723redis]#./redis-trib.rbcreate--r eplicas1127.0.0.1:7001127.0.0.1:7002127.0.0.1:7003127.0.0.1: 7004127.0.0.1:7005127.0.0.1:7006>>>CreatingclusterConnecting tonode127.0.0.1:7001:OKConnectingtonode127.0.0.1:7002:OKC onnectingtonode127.0.0.1:7003:OKConnectingtonode127.0.0.1: 7004:OKConnectingtonode127.0.0.1:7005:OKConnectingtonode1 27.0.0.1:7006:OK>>>Performinghashslotsallocationon6nodes. ..Using3masters:127.0.0.1:7001127.0.0.1:7002127.0.0.1:7003Addin greplica127.0.0.1:7004to127.0.0.1:7001Addingreplica127.0.0. 1:7005to127.0.0.1:7002Addingreplica127.0.0.1:7006to127.0.0. 1:7003M:d8f6a0e3192c905f0aad411946f3ef9305350420127.0.0.1:7001 slots:0-5460(5461slots)masterM:7a12bc730ddc939c84a156f276c446 c28acf798c127.0.0.1:7002slots:5461-10922(5462slots)masterM: 93f73d2424a796657948c660928b71edd3db881f127.0.0.1:7003slots:109 23-16383(5461slots)masterS:f79802d3da6b58ef6f9f30c903db7b2f79 664e61127.0.0.1:7004replicatesd8f6a0e3192c905f0aad411946f3ef93 05350420S:0bc78702413eb88eb6d7982833a6e040c6af05be127.0.0.1:700 5replicates7a12bc730ddc939c84a156f276c446c28acf798cS:4170a68ba 6b7757e914056e2857bb84c5e10950e127.0.0.1:7006replicates93f73d2 424a796657948c660928b71edd3db881fCanIsettheaboveconfiguratio n?(type''yes''toaccept):yes>>>Nodesconfigurationupdated>>> Assignadifferentconfigepochtoeachnode>>>SendingCLUSTERM EETmessagestojointheclusterWaitingfortheclustertojoin.. ..>>>PerformingClusterCheck(usingnode127.0.0.1:7001)M:d8f6 a0e3192c905f0aad411946f3ef9305350420127.0.0.1:7001slots:0-5460 (5461slots)masterM:7a12bc730ddc939c84a156f276c446c28acf798c12 7.0.0.1:7002slots:5461-10922(5462slots)masterM:93f73d2424a79 6657948c660928b71edd3db881f127.0.0.1:7003slots:10923-16383(546 1slots)masterM:f79802d3da6b58ef6f9f30c903db7b2f79664e61127.0. 0.1:7004slots:(0slots)masterreplicatesd8f6a0e3192c905f0aad4 11946f3ef9305350420M:0bc78702413eb88eb6d7982833a6e040c6af05be12 7.0.0.1:7005slots:(0slots)masterreplicates7a12bc730ddc939c8 4a156f276c446c28acf798cM:4170a68ba6b7757e914056e2857bb84c5e10950 e127.0.0.1:7006slots:(0slots)masterreplicates93f73d2424a79 6657948c660928b71edd3db881f[OK]Allnodesagreeaboutslotsconfi guration.>>>Checkforopenslots...>>>Checkslotscoverage...[O K]All16384slotscovered.[root@localhost-0723redis]#连接集群命令:./r edis-cli–h127.0.0.1–p7001-c[root@localhost-0723redis]#./re dis-cli-p7006-c127.0.0.1:7006>setkey1123->Redirectedtosl ot[9189]locatedat127.0.0.1:7002OK127.0.0.1:7002>查看集群的命令查看集群状态 127.0.0.1:7003>clusterinfocluster_state:okcluster_slots_assigne d:16384cluster_slots_ok:16384cluster_slots_pfail:0cluster_slots_f ail:0cluster_known_nodes:6cluster_size:3cluster_current_epoch:6cl uster_my_epoch:3cluster_stats_messages_sent:926cluster_stats_mess ages_received:926查看集群中的节点:127.0.0.1:7003>clusternodes7a12bc730d dc939c84a156f276c446c28acf798c127.0.0.1:7002master-014436017 397542connected5461-1092293f73d2424a796657948c660928b71edd3db8 81f127.0.0.1:7003myself,master-003connected10923-16383d8f 6a0e3192c905f0aad411946f3ef9305350420127.0.0.1:7001master-01 4436017412671connected0-54604170a68ba6b7757e914056e2857bb84c5e 10950e127.0.0.1:7006slave93f73d2424a796657948c660928b71edd3db8 81f014436017392506connectedf79802d3da6b58ef6f9f30c903db7b2f79 664e61127.0.0.1:7004slaved8f6a0e3192c905f0aad411946f3ef9305350 420014436017422774connected0bc78702413eb88eb6d7982833a6e040c6 af05be127.0.0.1:7005slave7a12bc730ddc939c84a156f276c446c28acf7 98c014436017402595connected127.0.0.1:7003>维护节点(自学)添加主节点集群创建成功 后可以向集群中添加节点,下面是添加一个master主节点添加7007结点作为新节点执行命令:./redis-trib.rbad d-node127.0.0.1:7007127.0.0.1:7001查看集群结点发现7007已添加到集群中hash槽重新分配添 加完主节点需要对主节点进行hash槽分配,这样该主节才可以存储数据。查看集群中槽占用情况redis集群有16384个槽,集群中的每 个结点分配自已槽,通过查看集群结点可以看到槽占用情况。给刚添加的7007结点分配槽第一步:连接上集群(连接集群中任意一个可用结点都 行)[root@redis01redis0707]#./redis-trib.rbreshard192.168.101.3 :7001第二步:输入要分配的槽数量输入:500,表示要分配500个槽第三步:输入接收槽的结点id输入:15b809eadae88 955e36bcdbb8144f61bbbaf38fbPS:这里准备给7007分配槽,通过clusternodes查看7007结 点id为:15b809eadae88955e36bcdbb8144f61bbbaf38fb第四步:输入源结点id输入:all第五步 :输入yes开始移动槽到目标结点id输入:yes添加从节点集群创建成功后可以向集群中添加节点,下面是添加一个slave从节点。添加 7008从结点,将7008作为7007的从结点命令:./redis-trib.rbadd-node--slave--mast er-id主节点id新节点的ip和端口旧节点ip和端口执行如下命令:./redis-trib.rbadd-node--s lave--master-idcad9f7413ec6842c971dbcc2c48b4ca959eb5db4192.16 8.101.3:7008192.168.101.3:7001cad9f7413ec6842c971dbcc2c48b4ca959 eb5db4是7007结点的id,可通过clusternodes查看。注意:如果原来该结点在集群中的配置信息已经生成到clu ster-config-file指定的配置文件中(如果cluster-config-file没有指定则默认为nodes.conf) ,这时可能会报错:[ERR]NodeXXXXXXisnotempty.Eitherthenodealready knowsothernodes(checkwithCLUSTERNODES)orcontainssomekey indatabase0解决方法是删除生成的配置文件nodes.conf,删除后再执行./redis-trib.rbadd- node指令查看集群中的结点,刚添加的7008为7007的从节点:删除结点命令:./redis-trib.rbdel-node 127.0.0.1:70054b45eb75c8b428fbd77ab979b85080146a9bc017删除已经占有hash 槽的结点会失败,报错如下:[ERR]Node127.0.0.1:7005isnotempty!Resharddata awayandtryagain.需要将该结点占用的hash槽分配出去(参考hash槽重新分配章节)。Jedis连接集群防火 墙配置[root@localhost-0723bin]#serviceiptablesstop-AINPUT-mst ate--stateESTABLISHED,RELATED-jACCEPT-AINPUT-picmp-jACCE PT-AINPUT-ilo-jACCEPT-AINPUT-mstate--stateNEW-mtcp-p tcp--dport22-jACCEPT-AINPUT-mstate--stateNEW-mtcp-p tcp--dport8080-jACCEPT-AINPUT-mstate--stateNEW-mtcp-p tcp--dport6379-jACCEPT-AINPUT-mstate--stateNEW-mtcp- ptcp--dport6380-jACCEPT-AINPUT-mstate--stateNEW-mtcp -ptcp--dport7001-jACCEPT-AINPUT-mstate--stateNEW-mtcp -ptcp--dport7002-jACCEPT-AINPUT-mstate--stateNEW-mtc p-ptcp--dport7003-jACCEPT-AINPUT-mstate--stateNEW-mt cp-ptcp--dport7004-jACCEPT-AINPUT-mstate--stateNEW-m tcp-ptcp--dport7005-jACCEPT-AINPUT-mstate--stateNEW-m tcp-ptcp--dport7006-jACCEPT-AINPUT-jREJECT--reject-wit hicmp-host-prohibited-AFORWARD-jREJECT--reject-withicmp-hos t-prohibitedCOMMIT~"/etc/sysconfig/iptables"22L,1079C已写入[root @localhost-0723bin]#serviceiptablesrestartiptables:应用防火墙规则:[ 确定][root@localhost-0723bin]#代码实现创建JedisCluster类连接redis集群。@Testpu blicvoidtestJedisCluster()throwsException{//创建一连接,JedisClust er对象,在系统中是单例存在Setnodes=newHashSet<>();nodes.add( newHostAndPort("127.0.0.1",7001));nodes.add(newHostAndPort("12 7.0.0.1",7002));nodes.add(newHostAndPort("127.0.0.1",7003));no des.add(newHostAndPort("127.0.0.1",7004));nodes.add(newHostAnd Port("127.0.0.1",7005));nodes.add(newHostAndPort("127.0.0.1",7 006));JedisClustercluster=newJedisCluster(nodes);//执行JedisClu ster对象中的方法,方法和redis一一对应。cluster.set("cluster-test","myjedisclu stertest");Stringresult=cluster.get("cluster-test");System.ou t.println(result);//程序结束时需要关闭JedisCluster对象cluster.close();}使用spr ing配置applicationContext.xmlg"class="redis.clients.jedis.JedisPoolConfig">pertyname="maxTotal"value="30"/>="maxIdle"value="10"/>stsPerEvictionRun"value="1024"/>name="timeBetweenEvictionRunsMillis"value="30000"/>/>e="softMinEvictableIdleTimeMillis"value="10000"/>测试代码privateApplicationContextapplicationContext;@Beforepublicvoidinit(){applicationContext=newClassPathXmlApplicationContext("classpath:applicationContext.xml");}//redis集群@TestpublicvoidtestJedisCluster(){JedisClusterjedisCluster=(JedisCluster)applicationContext.getBean("jedisCluster");jedisCluster.set("name","zhangsan");Stringvalue=jedisCluster.get("name");System.out.println(value);} |
|