redis 总结

redis:

遇到什么问题?

当我们的系统引入了传统的缓存框架,比如(ehcache),因为ehcache等框架只是一个内置的缓存框架,所以前端的缓存和后台的(每一个webserver)的缓存都是独立存在的,加入一个缓存的数据发生了更新,其他缓存是不可能知道的,正阳对于乐观锁,总会提示失败;

 

在分布式环境下,缓存不能同步;

解决方案?

让缓存集中处理(大家使用同一个缓存服务),我们需要一个类似于MYSQL这样可以通过服务来提供第三方的缓存工具(缓存服务器),流行的第三方缓存服务器有:memcache、redis

 

理解:

redis可以堪称一个Map(key-value),在redis中,所有的key都可以理解为byte[](string),

VALUE?在memcache中,value也只能是byte[](string); ---------------->  Map<String,String> 。

      在redis中,value的可选类型很多,string,list,set,orderset,hash,Map<String,String>,Map<String,Set>,Map<String,String>,Map<String,Map<>>

 

redis的优势:

性能极高 ---- Redis能支持超过10w美妙的读写频率

丰富的数据类型 ---- Redis支持二进制案例的Strings,Lists,Hashes,Sets及OrderedSets数据类型操作。

原子 ---- Redis的所有操作都是原子性的,同事Redis还支持对几个操作合并后的源自性执行(简单的事务)。

丰富的特性 ---- Redis还支持publish/subscribe(发布/订阅),通知,key过期等等特性。

 

Redis的理念:

我们常用的数据库:关系型数据库,面向对象数据库,NoSQL(Not only SQL) --> (key-value)内存数据库;

redis是一个key-value的内存存储应用(使用redis主要还是吧数据存在内存中,这个可以最大的使用redis的性能优势);

redis可以把数据存储在内存中,也可以持久化到磁盘上;

redis不是一个适用于任何场景的存储应用;

redis不光可以作为一个缓存,还是一个搞笑的额内存数据库;可以在某些情况下,高效的替换到传统的关系型数据库,非常好的处理高并发高请求的场景;

 

学redis:

redis在线入门:http://try.redis.io/

redis中文资料站:http://www.redis.cn

redis命令手册:http://www.redisdoc.com

 

redis入门

两个最基本的redis命令:

  SET KEY VALUE : 把VALUE保存到redis中KEY对应的值;

  GET KEY : 取出redis中KEY对应的值。

 

关于redis中的key:

在示例中,key的值为server:name  ,代表server的name,这是redis中key取名的一个规范;

我们之前说到redis不光是一个缓存,还可以看作一个数据库,这种数据库和传统的关系型数据库最大的区别就在于,传统的关系型数据库,再保存数据库之前,都已经有一个固定的schema;内容是保存在一个schema中不同行的数据;所欲的数据都存在一张指定的表中,所有的内容都对应表里的一个指定行,每一个行都有固定的数据类型;

所以,当我们在使用关系型数据表表现一个对象(数据结构的时候),我们能够事前通过schema规范好这个对象的结构;

比如,要表现User这个对象,只需要创建一个user表,在表里面创建id、name、password桑额咧,在保存数据时。就是直接把数据保存到这个表中对应的列中,要查询id为1的user,可以通过select语句去表的内容中进行结构化的筛选;

但是,对于redis来说,整个数据库就是一个Map,没有任何结构而言,所有通过set等方法扔到redis中的数据,可以简单理解为就是所有的数据乱七八糟的放在一个map中;

问题:在redis中,怎么存储一个user?怎么检索?(Map能不能通过value查询???不能,换那句话说,在redis中,要能够支持查询的属性,都必须反映在key上)

redis的作用:1、反映数据的结构;2、反映查询的内容。

 

redis的版本

目前稳定的最新版时3.2;

redis时*Unix的一个用,我们在开发中使用的windows版本不是官方的,时微软开源提供的,每一个版本都对应一个linux版本的redis;

注意32位和64位版本的区别。

 

redis的基本概念

1、redis也有数据库的概念,一个数据库中可以保存一组数据;

2、哥哥数据之间时相互隔离的,当然也可以在不同数据库之间复制数据

3、一般一个应用会单独使用一个数据库;

4、每一个数据库都有一个id号,默认的数据id为0;

5、可以使用select命令选择当前使用的数据库;

6、redis 默认为我们创建16个数据库,这个参数可以在redis配置文件中使用databases来修改.

 

Command(命令)

1、redis中提供了非常大量和的命令来方便二点操作数据库中的数据,还可以使用redis中的一些特性;

2、redis的命令可以简单理解为mysql的SQL命令;

3、redis命令分为

  • 数据库的操作;
  • 发布/订阅相关操作;
  • 失误操作;
  • 脚本命令;
  • 连接服务器命令;
  • 数据库服务相关命令;

 

KEY-VALUE

1、key用来标记一个数据;一般在key中需要尽量标明数据的名字(还可以用key来表明数据所属类型),比如用于标示一个对象的额时候,可以使用user:1000来作为key,代表id为1000的用过户对象;

2、value用来表示一个key对应的值;在redis中,数据可以是任何内容,redis把所有的value都作为byte来处理;所以可以用来保存任何内容;

例子:像redis中存储一个json字符串;

  set user:1'{"id":1,"name":"stef","age":18}'

获得这个值:

  get user:1

3、redis最突出的特点是提供了5中常用的数据存储类型(value的类型),深刻理解这5种数据结构和各自的使用场景,对redis的使用有很大帮助;

 

Query(检索)

1、在redis中,不支持对value进行任何形式的查询;

例如:保存一个user:

  set user:1'{name:"hello",id:1}'

是无法通过redis去查询name为hello的user要查询的内容,只能反映在key值上,所以如果要按照用户的name查询,只能再添加一条数据;

set user:name:stef 1

2、redis不是一个适用于任何场景的存储方案,考虑使用redis需要对业务进行考评,用redis的思想去重新涉及数据结构;

 

存储

1、redis可以作为内存数据库,也可以把数据持久化到磁盘上;大部分情况下,都是把redis作为内存数据库。

2、默认情况下,redis每60秒/1000数据修改或者15分钟/9个以下key修改;

在redis配置文件中:

save 500 1

save 300 10

save 60 10000

3、数据默认存储在安装目录下,rdb文件中(可以在配置文件中dbfilenamedump.rdb配置);

4、redis也可以设置为append模式,每次key的修改都会append到文件中,这种方式有可能丢失60秒的数据;

  • 通过配置:appendonly yes 开启
  • appendfilename "appendonlyaof"设置append文件;
  • 可以设置append模式(类似于mysql的事务文件同步机制);
    • appendfsync always:每次更新key及时同步到append文件;
      •   appendfsync everysec:每一秒同步一次jkey的更新
    • appendfsync no:不管理append文件的更新,根据操作系统去定。

 

 redis中的数据结构:

redis中丰富的数据机构是redis区别memecache等其他NOSQL的一个重要优势;学习redis中的5种数据结构对使用redis有非常大的帮助;

怎么学习redis中的数据结构和相关的额操作;

1、熟悉数据结构的意义,最简单的方法和c++/java的数据类型对比;

2、了解数据结构常用的一些命令(看文档,学会看懂文档中命令的意思和使用方式)

3、尝试使用这些命令,做简单的实验(可以不需要场景,就只是看结果);

4、了解该数据结构的使用场景(文档/网上资料),设计一个具体的场景,使用有效的命令完成场景操作;

5、了解该数据结构的实现原理,了解二数据结构的执行效率(进阶)

 

Redis中的string:

1、redis中最常见的数据类型;内容可以是任何值(因为string对应着byte[]);

2、可以通过set key value添加一个值;

3、常见的字符串操作:

  • strlen key: : 返回key的value的值长度;
  • getrange key X Y : 返回key对应value的一个子字符串,位置从x到y;
  • append key value : 给key对应的value追加值,如果key不存在,相当于set一个新的值;

4、如果字符串的内容是数值(integer,在redis中,数值也是string)

  • incr key : 给定key的value上增加1;(常用于id);redis中的一个源自操作,支持并发;如果key不存在,则相当于设置1;
  • incrby key value:给定key的value上增加value值;相当于key=key.value+value;也是一个原子操作;
  • decr : 给定key的value上减1;
  • decrby key value : 给定key的value上减value值;

 

5、string最常见的使用场景:

存储json类型对象 

incr user:id

set user:1 {id:1,name:alex}

incr user:id

set user:2 {id:2,name:cthon}

作为计数器,

  incr count;

优酷视频点赞

  incr vedio:100:goodcount  (id为100的视频点赞数加1)

  decr vedio:100:goodcount(id为100的视频点赞数减1)

 

redis中的list

1、redi的list结构,是一个双向链表,可以用来存储一组数据;从这个列表的前端和后端取数据效率非常高;

2、list的常用操作:

  • RPUSH:在一个list最后面添加一个元素
    • RPUSH friends "stef"
  • LPUSH:在一个list最前面添加一个元素
    • LPUSH friends "stea"
  • LTRIM key start stop:剪裁一个列表,剩下的内容从start到stop;
    • LTRIM friends 0,3 => 只剩下前4个数据
  • LRANGE :获取列表中的一部分数据,两个参数,第一个参数代表第一个获取元素的位置<0>开始,第二个值代表截至的元素位置,如果第二个参数为-1,戒指到列表尾部;
    • LRANGE friends 0 -1
  • LLEN:返回一个列表当前长度
    • LLEN friends
  • LPOP:移除list中第一个元素,并返回这个元素
    • LPOP friends
  • RPOP:移除list中最后一个元素,并返回这个元素
    • RPOP friends

 3、list使用场景

场景一:可以使用list模拟队列,堆,栈

场景二:微博/微信朋友圈点赞

  规定:朋友圈内容的格式

    1、内容:user:x:post:x content 来存储

    2、点赞:post:x:good list 来存储

  • 创建一条微博内容:set user:1:post:91 "hello redis"
  • 点赞:
    • lpush post:91:good '{id:1,name:stef,img:xxx.jpg}'
    • lpush post:91:good '{id:1,name:x1,img:xxx.jpg}'

    • lpush post:91:good '{id:1,name:xm,img:xxx.jpg}'
  • 查看有多少人点赞:llen post:91:good
  • 查看有哪些人点赞:lrange post:91:good 0 -1

思考:如果用数据库实现这个功能,SQL会多复杂?

场景三:回帖

  • 创建一个帖子:set user:1:post:90 'wohenshuai'
  • 创建一个回帖:set postreply:1 'nonono'
  • 把回帖和帖子关联:lpush post:90:replies 1
  • 再来一条回帖:set postreply:2 'hehe'
      • lpush post:90:replies 2
  • 查询帖子的回帖:lrange post:90:replies 0 -1
      • get postreply:1

 

redis中的set

1、结构和java中差不多,数据没有顺序,并且每一个值不能重复;

2、set结构的常见操作:

  • SADD:给set添加一个元素
    • SADD language 'java'
  • SREM:从set中移除一个给定元素
    • SREM language 'php'
  • SISMEMBER:怕那段给定的一个元素是否在set中,如果存在,返回1,如果不存在,返回0;
    • sismember language 'php'
  • SMEMBERS:返回指定set内所有的元素,以一个list形式返回
    • smembers language
  • SCARD:返回set的元素个数
    • scard language
  • SRANDMEMBER key count:返回指定set中随机的count个元素
    • srandmember friends 3 //随机推荐3个用户(典型场景,抽奖)
  • SUNION:综合多个set的内容,并返回一个list的列表,包含综合后的所有元素;
    • safdd language 'php'
    • sadd pg 'c'
    • sadd pg 'c++'
    • sadd pgs 'java'
    • sadd pgs 'swift'
    • sunion language pg pgs
  • SINTER key [key ...]:获取多个key对应的key之间的交集
    • SINTER friends:user:100 friends:user:1001 friends:user:1002 => 获取1000,1001,1002三个用户的共同好友列表;
  • SINTERSTORE destination key [key ... ] :获取多个key对应的set之间的交集,并保存为新的key值;目标也是一个set;
    • SINTER groupfriends friends:user:1000 friends:user:1001 friends:user:1002 => 获取三个用户共同的好友列表并保持存为组好友列表;

3、set的使用场景

  • 去重
  • 抽奖
    • 准备一个抽奖池:
      • sadd luckdraws 1 2 3 4 5 6 7 8 9 10 11 12 13
    • 抽三个三等奖:
      • srandmember luckdraws 3
      • srem luckdraws 11 1 10
    • 抽2个二等奖:
  • 做set运算(好友推荐)
    • 初始化好友圈
      • sadd user:1:friends 'user:2' 'user:3' 'user:5'
      • sadd user:2:friends 'user:1' 'user:3' 'user:6'
      • sadd user:3:friends 'user:1' 'user:7' 'user:8'
    • 把user:1的好友的好友集合做并集;
      • user:1 user:3 user:6 user :7 user:8 
      • sunionstore user:1:maybe:group user:2:friends user:3:friends
      • smembers user:1:maybe:group
    • 让这个并集和user:1的好友集合和这个并集做差集;
      • user:1 user:6 user:7 user:8
      • sdiffstore user:1:maybe:group user:1:maybe:group user:1:friends
        • smembers user:1:maybe:group
    • 从差集中去掉自己
      • user:6 user:7 user:8
      • srem user:1:maybe:group user:1
    • 随机选取推荐好友
      •  srandmember user:1:maybe:group 2

 

redis中的sorted-set(又叫zset)

1、set是一种非常方便的结构,但是数据无序,redis提供了一个sorted set,每一个添加的值都有一个对应的分数,可以通过这个分数进行排序

2、sortedset的常用操作:

  • ZADD:添加一个带分数的元素,也可以同事添加多个:
    • ZADD hackers 1940 "Alan Kay"
    • ZADD hackers 1906 "Grace Hopper"
    • ZADD hackers 1969 “Linux Torvalds”
    • ZADDhackers 1940 "Alan kay" 1960 "Grace Hopper" 1969 "Linux Torvalds"
  • ZCOUNT key min max : 给定范围分数的元素个数
    • ZCOUNT hackers 1940 1960 => 1940到1960的hacker个数
  • ZRANK key member : 查询指定元素的分数在整个列表中的排名(从0开始)
    • ZRANK hackers “Alan Kay" => alan kay 的年龄在所有hacker中的排名;
  • zrange hacke 0 -1 =>
    • "Grace Hopper"
    • "Alan Kay"
    • "Linus Torvald"
  • ZREVERANGE key start stop :按照分数从小到大排序

3、sorted set 的使用场景:sorted set算是redis中最有用的一种结构,非常适合用于做海量数据的排行(比如一个巨型游戏的用户排名);sorted set中所有的方法都建议学一下;sortedset的速度非常快;

示例1:

  • 天梯排名:
    • 添加初始排名和分数;
    • 查询fat在当前adder中的排名;
    • 查询ladder中的前3名;
    • steb增加了20ladder score;

示例2:FIFO LIFO

  • LRU淘汰最长时间没使用;
  • LFU淘汰最低使用频率;

 

redis中的hash

1、hashes可以理解为一个map,这个map有一对一对的字段和值组成,所以,可以用hashes来保存一个对象;

2、hashes的常见操作:

  • HSET : 给一个hasheds添加一个field和value;
    • HSET user:1000 name "John Smith"
    • HSET user:1000 email "john.smith@example.com"
    • HSET user:1000 password "s3cret"
  • HGET : 可以得到一个hashes中的某一个属性的值;
    • HGET user:1000 password "s3cret"
  • HGETALL : 一次性取出一个hashes中所有的field和value,使用list输出,一个filed,一个calue有序输出;
    • HGETALL user:1000 =>
      • "name"
      • "John Smith"
      • "email"
      • "john.smith@example.com"
      • "password"
      • "s3cret"
  • HMSET : 一次习惯的设置多个值(hashes multiple set)
    • HMSET user:1001 name "Mary Hones" password "hidden"  email "mjones@example.com"
  • HMGET : 一次性得到多个字段值(hashes multiple get),列表形式返回;
    • HMGET user:1001 name email =>
      • "Mary Jones"
      • "mjones@example.com"
  • HINCRBY : 给hashes的一个field的value值增加一个值(integer),这个增加操作时原子操作
    • HSET user:1000 visits 10
    • HINCRBY user:1000 visits 1 =>11
    • HINCRBY user:1000 visits 10 => 21
  • HKEYS : 得到一个key的所有fields字段,以list返回:
    • "name"
    • "password"
    • "email"
  • HDEL : 删除hashes一个指定的field;
    • HDEL user:1000 visits

 

 hash的使用场景:

1、使用hash来保存一个对象更直观;(建议不适用hash来保存)

2、分组

  • set user:id 1
  • set dept:id 1
  • HMSET ids user:id 1 dept:id 1 orderbill:id 1
  • HINCRBY ids user:id
  • HINCRBY ids dept:id
  • HMSET users user:1 "{id:1,name:xx}" user:2"{id:2,name:xx}"

 

JAVA中对redis进行操作----jedis

 

posted @ 2018-09-30 10:46  CTHON  阅读(276)  评论(0编辑  收藏  举报