redis

课程目标

  1. 掌握Redis的安装、配置
  2. 了解Redis的优缺点
  3. 掌握Redis的使用方法

课程体系

  1. Redis介绍
  2. Redis安装启动及关闭
  3. Redis与Memcached比较
  4. Redis各种数据类型的操作
  5. Redis常用命令
  6. 简单应用
  7. Redis拓展功能

8. 代码实现

9. 应用场景

10.话术

  1. Redis介绍

1.1什么是Redis

Redis全称是REmote DIctionary Server(远程字典服务器)。

Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。

Redis是一个由Salvatore Sanfilippo写的key-value存储系统。

1.2 Redis的特点

相比于其他 key-value 缓存产品,Redis具有以下特点:

    Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。

    Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。

    Redis支持数据的备份,即master-slave模式的数据备份。

1.3 Redis的特性

1.多种数据类型存储

字符串类型、哈希类型、列表类型、集合类型、有序集合类型

2.内存存储与持久化

内存的读写速度远快于硬盘

自身提供了持久化功能(RDB(默认)、AOF)

3.功能丰富

可用作缓存、队列、消息订阅/发布

支持键的生存时间

按照一定规则删除相应的键

4.简单稳定

相比SQL而言更加简单

不同语言的客户端丰富

基于C语言开发,代码量只有3万多行

1.4 Redis与其他数据库比较

 

redis

mysql

mongodb

有无库

表结构

集合(与redis不同,类似于mysql的表)

 

行跟列

字段,行跟列

Redis优缺点:

优点:对数据高并发读写,对数据的可扩展性和高可用性

缺点:redis无法做到太复杂的关系型数据库模型对海量数据的高效率存储和访问 而且对一些较为重要的信息不会使用redis,比如银行金融系统,钱,还有商城订单。

 

1.5 Redis数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

1.6 Redis的多数据库

Redis默认支持16个数据库,对外都是以一个从0开始的递增数字命名,可以通过参数databases来修改默认数据库个数。客户端连接Redis服务后会自动选择0号数据库,可以通过SELECT命令更换数据库.

Redis不支持自定义数据库名称。

Redis不支持为每个数据库设置访问密码

Redis的多个数据库之间不是完全隔离的,FLUSHALL命令会清空所有数据库的数据。

配置数据库数量

  1. Redis安装启动及关闭

2.1 Redis安装

2.1.1 Redis在windows下安装过程

一、下载windows版本的Redis

下载地址:https://github.com/MSOpenTech/redis/releases

根据系统选择Redis32位或者Redis64位。

 

 

二、安装Redis

1、解压安装包,到你需要安装的目录。例如:

2、启动命令:redis-server redis.windows.conf

三、设置Redis服务

上面虽然启动了redis,但是只要一关闭cmd窗口,redis就会消失。

1、设置服务命令

redis-server --service-install redis.windows-service.conf --loglevel verbose

输入命令之后没有报错,表示成功了,刷新服务,会看到多了一个redis服务。

卸载:sc delete 服务名称 //来卸载服务

2、常用的redis服务命令。

      卸载服务:redis-server --service-uninstall

开启服务:redis-server --service-start

停止服务:redis-server --service-stop

3、启动服务

4、测试Redis

2.1.2 Redis在Linux下安装过程

Redis官网地址:https://redis.io

最新版本:4.0.1

注:需要先安装gcc

//yum –y install gcc

//yum –y install gcc-c++

Linux安装reids步骤:

1.将下载好的tar.gz文件导入到linux系统下的opt目录下

解压:tar xzf redis-4.0.1.tar.gz

进入安装目录:cd redis-4.0.1

安装 make

2.make后,将四个执行文件拷贝到一个目录下

cp redis-server /usr/redis

cp redis-benchmark /usr/redis

cp redis-cli /usr/redis

cp redis.conf /usr/redis

cd /usr/redis

3.启动redis服务   默认端口6379

./redis-server redis.conf

通过修改redis.conf,修改端口号

4.客户端测试

redis-cli

redis>set userinfo tom

OK

redis>get userinfo

“tom”

2.2启动多个redis进程

方法一:

在redis启动时,指定端口

./redis-server ./redis.conf –port 6380

方法二(推荐):

创建多个redis目录,可以按照端口号命名。例如:6380、6381

将redis安装文件bin和conf复制到这两个目录下

分别修改6380、6381目录下的redis.conf,将端口分别改为6380、6381

分别启动6380、6381下的redis-server

./redis-server ./redis.conf

2.3客户端连接redis服务端

默认连接本机的redis,命令如下:

./redis-cli

连接指定redis服务的ip和端口,命令如下:

./redis-cli –h 127.0.0.1 –p 6379

2.4 Redis停止

强行停止redis进程可能会导致redis持久化数据丢失。

正确的停止方法为:

./redis-cli shutdown

  1. Redis与Memcached比较

3.1数据类型支持不同

    与memcached仅支持简单的key-value结构的数据记录不同,redis支持的数据类型要丰富得多,如:String,Hash,List,Set和Sorted Set

3.2集群管理的不同(重要)

    Memcached本身并不支持分布式,因此只能在客户端通过像一致性这样的分布式算法来实现memcached的分布式储存,相对于它呢,redis更偏向与在服务器端构建分布式存储.为了保证单点故障下的数据可用性.redis cluster 映入了master节点和slave节点.在redis cluster 中,每个master节点都会有对应的两个用于冗余的slave节点.这样在整个集群中,任意两个节点的宕点都不会导致数据的不可用,当master节点退出后,集群会自动选择一个slave节点成为新的master节点

3.3内存管理机制不同

Memcached默认使用slab allocation机制管理内存,其主要思想是按照预先规定的大小,将分配的内存分割成特定长度的块以存储对应长度的key-value数据记录,以完全解决内存碎片问题.memcached的内存管理制效率高,而且不会造成内存碎片,但是他最大的缺点就是会导致空间浪费

Redis的内存管理主要通过源码中zmalloc.h和zmalloc.c两个文件来实现的.redis为了方便内存的管理,在分配一块内存之后,会将这内存的大小存入内存的头部.总的来说,redis采用的是包装的mallc/free ,相较于memcached的内存管理方法来说,要简单很多

3.4数据持久化支持

    Redis虽然是基于内存的存储系统,但是它本身是支持内存数据的持久化的,而且提供两种主要的持久化策略:RDB快照和AOF日志.而memcached是不支持数据持久化操作的.对于一般性的业务雪球,建议使用RDB的方式进行持久化.原因是rdb的开销相比于AOF日志要低很多,对于那些无法忍受数据丢失的应用,建议使用AOF日志

  1. Redis各种数据类型的操作

4.1数据类型--String

4.1.1 String介绍

String是redis最基本的类型,可以理解成与Memcached一样,一个key对应一个value。

String类型是二进制安全的。

String类型是redis最基本的数据类型,一个键最大能存储512MB。

4.1.2命令

1)赋值

set key value

例:127.0.0.1:6379>set userinfo tom

OK

2)取值

当键不存在时返回空结果

get key

例:127.0.0.1:6379>get userinfo

    “tom”

3)删除

del key

例:127.0.0.1:6379>del userinfo

    (integer)1

4)数值增减

1)递增数字 incr key

让当前键值递增,并返回递增后的值

例:127.0.0.1:6379>incr num

    (integer)1

    127.0.0.1:6379>incr num

    (integer)2

    127.0.0.1:6379>incr num

    (integer)3

2)增加指定的整数 incrby key increment

例:127.0.0.1:6379>incrby num 2

    (integer)5

   127.0.0.1:6379>incrby num 2

    (integer)7

    127.0.0.1:6379>incrby num 2

    (integer)9

3)递减数值 decr key

例:127.0.0.1:6379>decr num

    (integer)8

    127.0.0.1:6379>decr num

    (integer)7

5)其他命令

1)减少指定的整数 decrby key decrement

例:127.0.0.1:6379>decr num

    (integer)6

    127.0.0.1:6379>decr num

    (integer)5

127.0.0.1:6379>decrby num 3

    (integer)2

127.0.0.1:6379> decrby num 3

    (integer)-1

2)向尾部追加值 append key value

append的作用是向键值的末尾追加value。如果键不存在则将该键的值设置为value,即相当于set key value。返回值是追加后字符串的总长度。

例:127.0.0.1:6379>set str hello

    OK

127.0.0.1:6379>append str “world!”

(integer)12

127.0.0.1:6379>get str

“hello world!”

3)获取字符串长度 strlen key

strlen命令返回键值的长度,如果键不存在则返回0。

例:127.0.0.1:6379>strlen str

    (integer)0

127.0.0.1:6379>set str hello

OK

127.0.0.1:6379>strlen str

(integer)5

4)同时设置/获取多个键值

mset key value [key value …]

mget key [key …]

例:127.0.0.1:6379>mset k1 v1 k2 v2 k3 v3

OK

127.0.0.1:6379>get k1

“v1”

127.0.0.1:6379>mget k1 k3

“v1”

“v3”

4.1.3应用

商品编号、订单号采用string的递增数字特性生成。

定义商品编号key:items:id

192.168.101.3:7003>incr items:id

(integer)2

192.168.101.3:7003>incr items:id

(integer)3

 

4.2数据类型--hash

4.2.1 Hash介绍

Hash是一个键名对集合。

Hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

4.2.2命令

1)赋值

hset key field value 一次只能设置一个字段值

例:127.0.0.1:6379>hset user username zhangsan

    (integer)1

hmset key field value [field value …] 一次可以设置多个字段值

例:127.0.0.1:6379>hmset user age 20 username lisi

    OK

2)取值

hget key field 一次只能获取一个字段值

例:127.0.0.1:6379>hget user username

    “zhangsan”

hmget key field [field …] 一次可以获取多个字段值

例:127.0.0.1:6379>hmget user age username

    “20”

    “lisi”

hgetall key 获取所有的字段值

例:127.0.0.1:6379>hgetall user

“age”

“20”

“username”

“lisi”

hset命令不区分插入和更新操作,当执行插入操作时hset命令返回1,当执行更新操作时返回0

3)删除

可以删除一个或多个字段,返回值是被删除的字段个数

hdel key field [field …]

例:127.0.0.1:6379>hdel user age

    (integer)1

127.0.0.1:6379>hdel user age name

    (integer)0

127.0.0.1:6379>hdel user age username

    (integer)1

4)增加数值

hincrby key field increment

例:127.0.0.1:6379> hincrby user age 2 //将用户的年龄加2

(integer)22

例:127.0.0.1:6379> hget user age //获取用户的年龄

“22”

5)其他命令

1)判断字段是否存在 hexists key field

例:127.0.0.1:6379>hexists user age //查看user中是否有age字段

    (integer)1

    127.0.0.1:6379>hexists user name //查看user中是否有name字段

    (integer)0

hsetnx key field value

当字段不存在时赋值,类似hset。注:如字段已存在,该命令不执行。

例:127.0.0.1:6379>hsetnx user age 30  //如user中无age字段则赋值,反之,不执行

(integer)0

2)只获取字段名或字段值 hkeys key、hvals key

例:127.0.0.1:6379>hmset user age 20 name lisi

    OK

    127.0.0.1:6379>hkeys user

    “age”

    “name”

    127.0.0.1:6379>hvals user

    “20”

    “lisi”

3)获取字段数量 hlen key

例:127.0.0.1:6379>hlen user

    (integer)2

4.2.3应用

商品id、商品名称、商品描述、商品库存、商品好评

定义商品信息的key:

商品1001的信息在redis中的key为:items:1001

存储商品信息:

192.168.101.3:7003>hmset items:1001 id 3 name apple price 999.9

OK

获取商品信息:

192.168.101.3:7003>hget items:1001 id

“3”

192.168.101.3:7003>hgetall items:1001

“id”

“3”

“name”

“apple”

“price”

“999.9”

4.3数据类型--List

4.3.1 List介绍

列表类型(list)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段。

4.3.2命令

1)向列表两端增加元素

lpush key value [value …] //向列表左侧增加元素

例:127.0.0.1:6379>lpush list:1 1 2 3

    (integer)3

rpush key value [value …] //向列表右侧增加元素

例:127.0.0.1:6379>rpush list:1 4 5 6

    (integer)3

2)查看列表

lrange key start stop

lrange命令是列表类型最常用的命令之一,获取列表中的某一片段,将返回start、stop之间的所有元素(包含两端的元素),索引从0开始。

索引可以是负数,如“-1”代表最后边的一个元素。

例:127.0.0.1:6379>lrange list:1 0 2

    “2”

    “1”

    “4”

3)从列表两端弹出元素

lpop key、rpop key

lpop命令从列表左侧弹出一个元素,分为两部:

第一步:将列表左边的元素从列表中移除

第二部:返回被移除的元素值

例:127.0.0.1:6379>lpop list:1

    “3”

127.0.0.1:6379>rpop list:1

    “6”

4)获取列表中元素的个数

llen key

例:127.0.0.1:6379>llen list:1

    (integer)2

5)其他命令

1)删除列表中指定的值 lrem key count value

LREM命令会删除列表中前count个值为value的元素,返回实际删除的元素个数。根据count值的不同,该命令的执行方式会有所不同:

当count>0时, LREM会从列表左边开始删除。

当count<0时, LREM会从列表后边开始删除。

当count=0时, LREM删除所有值为value的元素

2)获得/设置指定索引的元素值

LINDEX key index、LSET key index value

例:127.0.0.1:6379> lindex l:list 2

"1"

127.0.0.1:6379> lset l:list 2 2

OK

127.0.0.1:6379> lrange l:list 0 -1

"6"

"5"

"2"

"2"

3)只保留列表指定片段,指定范围和LRANGE一致 LTRIM key start stop

例:127.0.0.1:6379> lrange l:list 0 -1

"6"

"5"

"0"

"2"

127.0.0.1:6379> ltrim l:list 0 2

OK

127.0.0.1:6379> lrange l:list 0 -1

"6"

"5"

"0"

4)向列表中插入元素

    LINSERT key BEFORE|AFTER pivot value

该命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。

例:127.0.0.1:6379> lrange list 0 -1

"3"

"2"

"1"

127.0.0.1:6379> linsert list after 3 4

(integer) 4

127.0.0.1:6379> lrange list 0 -1

"3"

"4"

"2"

"1"

5)将元素从一个列表转移到另一个列表中

RPOPLPUSH source destination

例:127.0.0.1:6379> rpoplpush list newlist

"1"

127.0.0.1:6379> lrange newlist 0 -1

"1"

127.0.0.1:6379> lrange list 0 -1

"3"

"4"

"2"

4.3.3应用

商品评论列表:

在redis中创建商品评论列表

用户发布商品评论,将评论信息转成json存储到list中。

用户在页面查询评论列表,从redis中取出json数据展示到页面。

 

定义商品评论列表key:

商品编号为1001的商品评论key:items:comment:1001

例:192.168.101.3:7001> LPUSH items:comment:1001 '{"id":1,"name":"商品不错,很好!!","date":1430295077289}'

4.4数据类型--Set

4.4.1 Set介绍

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

Redis中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

4.4.2命令

1)增加/删除元素

SADD key member [member ...]

SREM key member [member ...]

例:127.0.0.1:6379> sadd set a b c

(integer) 3

127.0.0.1:6379> sadd set a

(integer) 0

127.0.0.1:6379> srem set c d

(integer) 1

2)获得集合中的所有元素

SMEMBERS key

例:127.0.0.1:6379> smembers set

"b"

"a”

判断元素是否在集合中,无论集合中有多少元素都可以极速的返回结果。

SISMEMBER key member

例:127.0.0.1:6379> sismember set a

(integer) 1

127.0.0.1:6379> sismember set h

(integer) 0

3)集合的差集运算A-B

属于A并且不属于B的元素构成的集合。

     

SDIFF key [key ...]

例:127.0.0.1:6379> sadd setA 1 2 3

(integer) 3

127.0.0.1:6379> sadd setB 2 3 4

(integer) 3

127.0.0.1:6379> sdiff setA setB

"1"

127.0.0.1:6379> sdiff setB setA

"4"

4) 集合的交集运算A∩B

属于A且属于B的元素构成的集合。

SINTER key [key ...]

例:127.0.0.1:6379> sinter setA setB

"2"

"3"

5)集合的并集运算A∪B

属于A或者属于B的元素构成的集合

SUNION key [key ...]

例:127.0.0.1:6379> sunion setA setB

"1"

"2"

"3"

"4"

6)其他命令

1)获得集合中元素的个数 SCARD key

例:127.0.0.1:6379> smembers setA

    “1”

    “2”

    “3”

    127.0.0.1:6379>scard seta

    (integer)3

4.5数据类型--sorted set

4.5.1 sorted set介绍

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

有序集合与列表类型的区别:

1、列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会变慢。

2、有序集合类型使用散列表实现,所有即使读取位于中间部分的数据也很快。

3、列表中不能简单的调整某个元素的位置,但是有序集合可以(通过更改分数实现)

4、有序集合要比列表类型更耗内存。

4.5.2命令

1)增加元素

向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素个数,不包含之前已经存在的元素。

ZADD key score member [score member ...]

例:127.0.0.1:6379> zadd scoreboard 80 zhangsan 89 lisi 94 wangwu

(integer) 3

127.0.0.1:6379> zadd scoreboard 97 lisi

(integer) 0

获取元素的分数 ZSCORE key member

例:127.0.0.1:6379> zscore scoreboard lisi

"97"

2)删除元素

    移除有序集key中的一个或多个成员,不存在的成员将被忽略。

当key存在但不是有序集类型时,返回一个错误。

ZREM key member [member ...]

例:127.0.0.1:6379> zrem scoreboard lisi

(integer) 1

3)获得排名在某个范围的元素列表

获得排名在某个范围的元素列表

ZRANGE key start stop [WITHSCORES]

//按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包含两端)

例:127.0.0.1:6379> zrange scoreboard 0 2

"zhangsan"

"wangwu"

"lisi“

    ZREVRANGE key start stop [WITHSCORES]

//照元素分数从大到小的顺序返回索引从start到stop之间的所有元素(包含两端)

例:127.0.0.1:6379> zrevrange scoreboard 0 2

"lisi"

"wangwu"

"zhangsan"

    如果需要获得元素的分数的可以在命令尾部加上WITHSCORES参数

例:127.0.0.1:6379>zrange scoreboard 0 1 WITHSCORES

"zhangsan"

"80"

"wangwu"

"94"

4)其他命令

1)获得指定分数范围的元素

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

例:127.0.0.1:6379> ZRANGEBYSCORE scoreboard 90 97 WITHSCORES

"wangwu"

"94"

"lisi"

"97"

127.0.0.1:6379> ZRANGEBYSCORE scoreboard 70 100 limit 1 2

"wangwu"

"lisi"

    2)增加某个元素的分数,返回值是更改后的分数。

ZINCRBY key increment member //给lisi加4分

例:127.0.0.1:6379> ZINCRBY scoreboard  4 lisi

"101“

    3)获得集合中元素的数量

ZCARD key

例:127.0.0.1:6379> ZCARD scoreboard

(integer) 3

4)获得指定分数范围内的元素个数

ZCOUNT key min max

例:127.0.0.1:6379> ZCOUNT scoreboard 80 90

(integer) 1

5)按照排名范围删除元素

ZREMRANGEBYRANK key start stop

例:127.0.0.1:6379> ZREMRANGEBYRANK scoreboard 0 1

(integer) 2

127.0.0.1:6379> ZRANGE scoreboard 0 -1

"lisi"

ZREMRANGEBYSCORE key min max //按照分数范围删除元素

例:127.0.0.1:6379> zadd scoreboard 84 zhangsan

(integer) 1

127.0.0.1:6379> ZREMRANGEBYSCORE scoreboard 80 100

(integer) 1

6)获取元素的排名

ZRANK key member、ZREVRANK key member

从小到大

例:127.0.0.1:6379> ZRANK scoreboard lisi

(integer) 0

从大到小

例:127.0.0.1:6379> ZREVRANK scoreboard zhangsan

(integer) 1

4.5.3应用

商品销售排行榜:

根据商品销售量对商品进行排行显示,定义sorted set集合,商品销售量为元素的分数。

定义商品销售排行榜key:items:sellsort

写入商品销售量:

商品编号1001的销量是9,商品编号1002的销量是10

例:192.168.101.3:7007> ZADD items:sellsort 9 1001 10 1002

商品编号1001的销量加1

例:192.168.101.3:7001> ZINCRBY items:sellsort 1 1001

商品销量前10名:

例:192.168.101.3:7001> ZRANGE items:sellsort 0 9 withscores

4.6Redis之生存时间

4.6.1设置生存时间

 

TTL返回值:

大于0的数字:剩余生存时间,单位为秒

-1 : 没有生存时间,永久存储

-2 : 数据已经被删除

4.6.2清除生存时间

4.6.3设置单位为毫秒

  1. Redis常用命令

5.1 keys命令

5.1.1设置key的生存时间

Redis在实际使用过程中更多的用作缓存,然而缓存的数据一般都是需要设置生存时间的。即:到期后数据销毁。

EXPIRE key seconds //设置key的生存时间(单位:秒)key在多少秒后会自动删除

TTL key //查看key生于的生存时间

PERSIST key //清除生存时间

PEXPIRE key milliseconds //生存时间设置单位为:毫秒

例:192.168.101.3:7002> set test 1 //设置test的值为1

OK

192.168.101.3:7002> get test //获取test的值

"1"

192.168.101.3:7002> EXPIRE test 5 //设置test的生存时间为5秒

(integer) 1

192.168.101.3:7002> TTL test //查看test的生于生成时间还有1秒删除

(integer) 1

192.168.101.3:7002> TTL test

(integer) -2

192.168.101.3:7002> get test //获取test的值,已经删除

(nil)

5.1.2其他命令

1)keys

返回满足给定pattern 的所有key

例:127.0.0.1:6379> keys mylist*

"mylist"

"mylist5"

"mylist6"

"mylist7"

"mylist8"

2)exists

确认一个key 是否存在

例:127.0.0.1:6379> exists HongWan

(integer) 0

127.0.0.1:6379> exists age

(integer) 1

从结果来数据库中不存在HongWan 这个key,但是age 这个key 是存在的

3)del

删除一个key

例:127.0.0.1:6379> del age

(integer) 1

127.0.0.1:6379> exists age

(integer) 0

4)rename

重命名key

例:127.0.0.1:6379[1]> keys *

"age"

127.0.0.1:6379[1]> rename age age_new

OK

127.0.0.1:6379[1]> keys *

"age_new"

age成功的被我们改名为age_new了

5)type

返回值的类型

例:127.0.0.1:6379> type addr

string

127.0.0.1:6379> type myzset2

zset

127.0.0.1:6379> type mylist

list

这个方法可以非常简单的判断出值的类型

5.2服务器命令

5.2.1 ping

测试连接是否存活

例:127.0.0.1:6379> ping

PONG

//执行下面命令之前,我们停止redis 服务器

例:127.0.0.1:6379> ping

Could not connect to Redis at 127.0.0.1:6379: Connection refused

//执行下面命令之前,我们启动redis 服务器

例:127.0.0.1:6379> ping

PONG

结果:

第一个ping 时,说明此连接正常

第二个ping 之前,我们将redis 服务器停止,那么ping 是失败的

第三个ping 之前,我们将redis 服务器启动,那么ping 是成功的

5.2.2 echo

在命令行打印一些内容

例:127.0.0.1:6379> echo HongWan

"HongWan"

5.2.3 select

选择数据库。Redis数据库编号从0~15,我们可选择任意一个数据库来进行数据的存储。

例:127.0.0.1:6379> select 1

OK

127.0.0.1:6379> select 16

(error) ERR invalid DB index

当选择16 时,报错,说明没有编号为16 的这个数据库

5.2.4 quit

退出连接。

例:127.0.0.1:6379> quit

5.2.5 dbsize

返回当前数据库中key的数目。

例:127.0.0.1:6379> dbsize

(integer) 18

结果说明此库中有18个key

5.2.6 info

获取服务器的信息和统计。

例:127.0.0.1:6379> info

redis_version:2.2.12

redis_git_sha1:00000000

redis_git_dirty:0

arch_bits:32

multiplexing_api:epoll

process_id:28480

uptime_in_seconds:2515

uptime_in_days:0

。。。

5.2.7 flushdb

删除当前选择数据库中的所有key。

例:127.0.0.1:6379> dbsize

(integer) 18

127.0.0.1:6379> flushdb

OK

127.0.0.1:6379> dbsize

(integer) 0

例中我们将0 号数据库中的key 都清除了。

5.2.8 flushall

删除所有数据库中的所有key。

例:127.0.0.1:6379[1]> dbsize

(integer) 1

127.0.0.1:6379[1]> select 0

OK

127.0.0.1:6379> flushall

OK

127.0.0.1:6379> select 1

OK

127.0.0.1:6379[1]> dbsize

(integer) 0

例中我们先查看了一个1 号数据库中有一个key,然后我切换到0 号库执行flushall 命令,结果1 号库中的key 也被清除了,说是此命令工作正常

  1. 简单应用(没必要,代码一般都通过spring整合使用)

需要下载驱动包:jedis-2.9.0.jar

建立一个web项目,导入redis架包

6.1连接到redis服务

实例:

import redis.clients.jedis.Jedis;

public class Test1 {

public static void main(String[] args) {

Jedis jedis=new Jedis("localhost"); //连接本地的redis服务

System.out.println("连接成功");

System.out.println("服务正在运行:"+jedis.ping()); //查看服务是否运行

    }

}

结果:连接成功 服务正在运行:PONG //PONG代表成功

    1. 字符串(String)实例

实例:

import redis.clients.jedis.Jedis;

public class Test2 {

public static void main(String[] args) {

Jedis jedis=new Jedis("localhost"); //连接本地的redis服务

System.out.println("连接成功");

jedis.set("tomcat", "localhost:8080"); //添加redis字符串数据

System.out.println("redis存储的字符串为:"+jedis.get("tomcat"));

        //获取键为tomcat的存储数据并打印输出

    }

}

结果:连接成功 redis存储的字符串为:localhost:8080

6.3列表实例(List)

实例:

import java.util.List;

import redis.clients.jedis.Jedis;

public class Test3 {

public static void main(String[] args) {

Jedis jedis=new Jedis("localhost"); //连接本地的redis服务

System.out.println("连接成功");

//将数据存储到shop-list列表中

jedis.lpush("shop-list", "Jingdao"); 

jedis.lpush("shop-list", "Taobao");

jedis.lpush("shop-list", "Alibaba");

        获取shop-list列表存储的数据并输出

List<String> list = jedis.lrange("shop-list", 0, 2);

for (String l : list) {

System.out.println("列表元素为:"+l);

    }

    }

}

结果:连接成功 列表元素为:Alibaba 列表元素为:Taobao 列表元素为:Jingdao

6.4 Keys实例

实例:

import java.util.Iterator;

import java.util.Set;

import redis.clients.jedis.Jedis;

public class Test4 {

public static void main(String[] args) {

Jedis jedis=new Jedis("localhost"); //连接本地的redis服务

System.out.println("连接成功");

        //获取redis中所有的key并输出

Set<String> keys = jedis.keys("*");

Iterator<String> iterator = keys.iterator();

while(iterator.hasNext()){

String key = iterator.next();

System.out.println(key);

    }

    }

}

结果:连接成功 tomcat shop-list

  1. Redis拓展功能

7.1 Redis主从复制

7.1.1概述

Redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。

通过redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力。主数据库主要进行写操作,而从数据库负责读操作。

7.1.2主从复制过程

过程:

    当一个从数据库启动时,会向主数据库发送sync命令,

主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并将保存期间接收到的命令缓存起来

当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。

从数据库收到后,会载入快照文件并执行收到的缓存的命令。

注:

redis2.8之前的版本:当主从数据库同步的时候从数据库因为网络原因断开重连后会重新执行上述操作,不支持断点续传。

redis2.8之后支持断点续传。

7.1.3配置

1)windows下redis主从复制

Redis拥有非常强大的主从复制功能,而且还支持一个master可以拥有多个slave,而一个slave又可以拥有多个slave,从而形成强大的多级服务器集群架构。

1.当前已安装并启动了主服务器,复制两份主服务的解压目录分别命名为Redis-salve1Redis-salve2.如下图:

2.配置从服务器

分别配置两个配置文件(两个文件需要配置的内容相同,以redis.windows.conf为例):

当前两个从服务的配置与主服务器的配置文件相同都是:

其中Redis-slave1改为:

其中Redis-slave2改为:

3.启动两个从服务

切换到各自目录下,输入命令:redis-server --service-install redis.windows.conf --loglevel verbose  --service-name 服务名称

4.打开服务,启动两个从服务并设置为自动启动

    注:redis-server redis.windows.conf

    

5.测试

在主服务下,用server-cli(客户端)输入set a test,回车。

用RedisDesktopManager可视化工具查看结果验证,三个服务器同步成功。

2)linux下redis主从复制

redis主从结构支持一主多从:注:所有从节点的配置都一样

主节点:192.168.33.130

从节点:192.168.33.131

方式1:修改配置文件

    修改从节点中redis的配置文件中的slaveof属性

方式2:动态设置

通过redis-cli 连接到从节点服务器,执行下面命令即可:

slaveof 192.168.33.130 6379

7.2哨兵模式

7.2.1简介

sentinel是redis高可用的解决方案,sentinel系统(N个sentinel实例,N >= 1)可以监视一个或者多个redis master服务,以及这些master服务的所有从服务;当某个master服务下线(宕机)时,自动将该master下的某个从服务升级为master服务替代已下线的master服务继续处理请求。

7.2.2哨兵功能

1、不时地监控redis是否按照预期良好地运行;
2、如果发现某个redis节点运行出现状况,能够通知另外一个进程(例如它的客户端);
3、能够进行自动切换。当一个master节点不可用时,能够选举出master的多个slave(如果有超过一个slave的话)中的一个来作为新的master,其它的slave节点会将它所追随的master的地址改为被提升为master的slave的新地址。
4、哨兵为客户端提供服务发现,客户端链接哨兵,哨兵提供当前master的地址然后提供服务,如果出现切换,也就是master挂了,哨兵会提供客户端一个新地址。

7.2.3哨兵原理

Redis提供了sentinel(哨兵)机制,通过sentinel模式启动redis后,自动监控master/slave的运行状态,基本原理是:心跳机制+投票裁决

每个sentinel会向其它sentinal、master、slave定时发送消息,以确认对方是否“活”着,如果发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的“主观认为宕机” Subjective Down,简称SDOWN)。

若“哨兵群”中的多数sentinel,都报告某一master没响应,系统才认为该master"彻底死亡"(即:客观上的真正down机,Objective Down,简称ODOWN),通过一定的vote算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置。

7.2.4配置

1)简单配置

第一行:指定sentinel使用的端口,不能冲突

第三行:指定工作目录

第五行:显示监控的master节点10.6.114.155,7030为master使用的端口,1代表“投票”的人数,mymaster为名字,自定义

第六行:5000为5秒,如果5s内mymaster没响应,认为SDOWN

第八行:如果15秒后,无反应,启动fallover,从剩下的slave中选一个升级为master

第七行:代表新的master选出来后,其它slave节点能同时并行从新master同步缓存的台数有多少个

注:一个sentinal可同时监控多个master,只要把5-8行重复多段,加以修改即可

2)使用步骤

备注:约定7030是redis-server端口,7031是redis-sentinel端口,且master、slave上的redis-server均已正常启动

1、先在redis根目录下创建conf子目录,新建配置文件sentinel.conf,内容参考前面的内容(master和slave上都做相同的配置)

2、./redis-sentinel ../conf/sentinel.conf 即可(master和slave上都启用sentinel,即最终有二个哨兵)

3、./redis-cli -p 7031 sentinel masters 可通过该命令查看当前的master节点情况(注,这里一定要带sentinel的端口)

4、在master上,./redis-cli -p 7030 shutdown ,手动把master停掉,观察sentinel的输出

[17569] 21 Nov 11:06:56.277 # +odown master mymaster 10.6.144.155 7030 #quorum 1/1
[17569] 21 Nov 11:06:56.277 # Next failover delay: I will not start a failover before Fri Nov 21 11:07:26 2014
[17569] 21 Nov 11:06:57.389 # +config-update-from sentinel 10.6.144.156:7031 10.6.144.156 7031 @ mymaster 10.6.144.155 7030
[17569] 21 Nov 11:06:57.389 # +switch-master mymaster 10.6.144.155 7030 10.6.144.156 7030
[17569] 21 Nov 11:06:57.389 * +slave slave 10.6.53.131:7030 10.6.53.131 7030 @ mymaster 10.6.144.156 7030

从红线部分可以看出,master发生了迁移,等刚才停掉的master再重启后,可以观察到它将被当作slave加入,类似以下输出:

[36444] 21 Nov 11:11:14.540 * +convert-to-slave slave 10.6.144.155:7030 10.6.144.155 7030 @ mymaster 10.6.144.156 7030

注意:发生master迁移后,如果遇到运维需要,想重启所有redis,必须最先重启“新的”master节点,否则sentinel会一直找不到master。

最后,如果想停止sentinel,可输入命令./redis-cli -p 7031 shutdown

 

7.3集群搭建

7.3.1集群架构(redis cluster)

架构细节:

  (1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.

  (2)节点的fail是通过集群中超过半数的节点检测失效时才生效.

  (3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

  (4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value

7.3.2集群选举:容错

  (1)领着选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.

  (2):什么时候整个集群不可用(cluster_state:fail),当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误

    a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.

    b:如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态.

7.3.3集群搭建

1.创建redis节点

例:选择2台服务器,分别为192.168.1.237,192.168.1.238,每个服务器下有3个节点。

192.168.1.237下创建3个节点:

    

分别对7000、7001、7002文件夹中的3个文件修改对应的配置

同理:在192.168.1.238创建3个节点:对应的端口改为7003,7004,7005.配置对应的改一下就可以了。

2. 两台机启动各节点(两台服务器方式一样)

3.创建集群

1)安装ruby

    yum -y install ruby ruby-devel rubygems rpm-build

2)安装 redis接口 //gem是ruby的一个工具包.

    gem install redis

3)运行redis-trib.rb

    

4)create创建(以192.168.1.237为例)

//--replicas 1 表示:自动为每一个master节点分配一个slave节点

//上面有6个节点,程序会按照一定规则生成3个master(主)3个slave(从)

注:防火墙一定要开放监听的端口,否则会创建失败。

 

注意:

提示Can I set the above configuration? (type 'yes' to accept): yes //输入yes

提示 Waiting for the cluster to join..........   //需要跑到Server2上做操作:分别进入redis各节点的客户端命令窗口,依次输入cluster meet 192.168.1.238 7000……

5)成功查看

回到Server1,已经创建完毕了。

查看一下 /usr/local/redis/src/redis-trib.rb check 192.168.1.237:7000

遇到的问题及解决办法:

解决办法:

GCC没有安装或版本不对,安装一下

yum install gcc

 

 

 

 

7.3redis分片

 

  1. 代码实现

8.1 jedis介绍

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

8.2实例连接

    1.pom坐标:

<dependency>

<groupId>redis.clients</groupId>

<artifactId>jedis</artifactId>

<version>2.8.0</version>

</dependency>

2.配置web.xml文件

 

    

    3.编写spring-redis.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"

    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd

        http://www.springframework.org/schema/mvc

        http://www.springframework.org/schema/mvc/spring-mvc.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 连接池配置 -->

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

        <!-- 最大连接数 -->

        <property name="maxTotal" value="30" />

        <!-- 最大空闲连接数 -->

        <property name="maxIdle" value="10" />

        <!-- 每次释放连接的最大数目 -->

        <property name="numTestsPerEvictionRun" value="1024" />

        <!-- 释放连接的扫描间隔(毫秒) -->

        <property name="timeBetweenEvictionRunsMillis" value="30000" />

        <!-- 连接最小空闲时间 -->

        <property name="minEvictableIdleTimeMillis" value="1800000" />

        <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->

        <property name="softMinEvictableIdleTimeMillis" value="10000" />

        <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->

        <property name="maxWaitMillis" value="1500" />

        <!-- 在获取连接的时候检查有效性, 默认false -->

        <property name="testOnBorrow" value="true" />

        <!-- 在空闲时检查有效性, 默认false -->

        <property name="testWhileIdle" value="true" />

        <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->

        <property name="blockWhenExhausted" value="false" />

    </bean>

    <!-- jedis客户端单机版 -->

    <bean id="redisClient" class="redis.clients.jedis.JedisPool">

        <constructor-arg name="host" value="127.0.0.1"></constructor-arg>

        <constructor-arg name="port" value="6379"></constructor-arg>

        <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>

    </bean> 

    <!-- jedis集群版配置

    <bean id="redisClient" class="redis.clients.jedis.JedisCluster">

        <constructor-arg name="nodes">

            <set>

                <bean class="redis.clients.jedis.HostAndPort">

                    <constructor-arg name="host" value="192.168.209.129"></constructor-arg>

                    <constructor-arg name="port" value="7001"></constructor-arg>

                </bean>

                <bean class="redis.clients.jedis.HostAndPort">

                    <constructor-arg name="host" value="192.168.209.129"></constructor-arg>

                    <constructor-arg name="port" value="7002"></constructor-arg>

                </bean>

                <bean class="redis.clients.jedis.HostAndPort">

                    <constructor-arg name="host" value="192.168.209.129"></constructor-arg>

                    <constructor-arg name="port" value="7003"></constructor-arg>

                </bean>

                <bean class="redis.clients.jedis.HostAndPort">

                    <constructor-arg name="host" value="192.168.209.129"></constructor-arg>

                    <constructor-arg name="port" value="7004"></constructor-arg>

                </bean>

                <bean class="redis.clients.jedis.HostAndPort">

                    <constructor-arg name="host" value="192.168.209.129"></constructor-arg>

                    <constructor-arg name="port" value="7005"></constructor-arg>

                </bean>

                <bean class="redis.clients.jedis.HostAndPort">

                    <constructor-arg name="host" value="192.168.209.129"></constructor-arg>

                    <constructor-arg name="port" value="7006"></constructor-arg>

                </bean>

            </set>

        </constructor-arg>

        <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>

    </bean>-->

</beans>

    4.工具类(通过注解调用)

package com.k1507.service;

import java.util.Map;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

 

@Component

public class RedisService {

// 操作redis客户端

private static Jedis jedis;

@Autowired   

    private JedisPool jedisPool;

/**

 * 获取一个jedis 客户端

 *

 * @return

 */

private Jedis getJedis() {

if (jedis == null) {

jedis = jedisPool.getResource();

}

return jedis;

}

/**

 * 检查是否连接成功

 * string、hash、set、list<String>zset

 * @return

 */

public String ping() {

return this.getJedis().ping();

}

 

/**

 * 通过key删除

 *

 * @param key

 */

public void del(String key) {

this.getJedis().del(key);

}

/**

 * 添加key value 并且设置存活时间

 *

 * @param key

 * @param value

 * @param liveTime

 */

public void set(String key, String value, int liveTime) {

this.set(key, value);

this.getJedis().expire(key, liveTime);

}

/**

 * 添加key value

 *

 * @param key

 * @param value

 */

public void set(String key, String value) {

this.getJedis().set(key, value);

}

/**

 * 获取redis value (String)

 *

 * @param key

 * @return

 */

public String get(String key) {

String value = this.getJedis().get(key);

return value;

}

/**

 * 通过正则匹配keys

 *

 * @param pattern

 * @return

 */

public Set<String> keys(String pattern) {

return this.getJedis().keys(pattern+"*");

}

/**

 * 检查key是否已经存在

 *

 * @param key

 * @return

 */

public boolean exists(String key) {

return this.getJedis().exists(key);

}

/**

 * 清空redis 所有数据

 *

 * @return

 */

public String flushDB() {

return this.getJedis().flushDB();

}

/**

 * 保存hashmap类型数据

 * @param key

 * @param field

 * @param value

 * @return

 */

public long hset(String key,String field,String value) {

return this.getJedis().hset(key, field, value);

}

/**

 * 获取hashmap所有数据

 * @param key

 * @param field

 * @return

 */

public Map<String,String> hgetAll(String key) {

return this.getJedis().hgetAll(key);

}

/**

 * 获取hashmap类型数据

 * @param key

 * @param field

 * @return

 */

public String hget(String key,String field) {

return this.getJedis().hget(key, field);

}

/**

 * 查看redis里有多少数据

 */

public long dbSize() {

return this.getJedis().dbSize();

}

}

 

    5.测试类测试

网址:localhost:9090/spring-redis/test.action

 

package com.k1507.service;

import java.util.Iterator;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

 

@Controller

public class Test {

@Autowired

private RedisService service;

 

@RequestMapping("test")

public void test(){

String ping = service.ping();

System.out.println(ping);//测试连接,PONG为成功

 

         //获取redis里的所有键,并遍历输出

Set<String> keys = service.keys("*");

Iterator<String> it = keys.iterator();

while(it.hasNext()){

String key = it.next();

System.out.println(key);

}

         //获取键为name的数据

System.out.println(service.get("name"));

 

         //向redis存储hash类型的数据

long hset = service.hset("user", "name", "zhangsan");

System.out.println(hset); //0失败,1成功

         //输入键为user,field为name的数据

String hget = service.hget("user", "name");

System.out.println(hget);

}

}

 

 

9.应用场景

缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用)

分布式集群架构中的session分离。

聊天室的在线好友列表。

任务队列。(秒杀、抢购、12306等等)

应用排行榜。

网站访问统计。

数据过期处理(可以精确到毫秒)

10.话术

redis介绍

redis是Nosql数据库中使用较为广泛的非关系型内存数据库,redis内部是一个key-value存储系统。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型,类似于Java中的map)。Redis基于内存运行并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一,也被人们称为数据结构服务器。 

redis的优点

 

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

 

我们都知道,在日常的应用中,数据库瓶颈是最容易出现的。数据量太大和频繁的查询,由于磁盘IO性能的局限性,导致项目的性能越来越低。

这时候,基于内存的缓存框架,就能解决我们很多问题。例如Memcache,Redis等。将一些频繁使用的数据放入缓存读取,大大降低了数据库的负担。提升了系统的性能。其实,对于hibernate以及Mybatis的二级缓存,是同样的道理。利用内存高速的读写速度,来解决硬盘的瓶颈。

 

Redis的优点

异常快

Redis非常快,每秒可执行大约110000次的设置(SET)操作,每秒大约可执行81000次的读取/获取(GET)操作。

支持丰富的数据类型

Redis支持开发人员常用的大多数数据类型,例如列表,集合,排序集和散列等等。这使得Redis很容易被用来解决各种问题,因为我们知道哪些问题可以更好使用地哪些数据类型来处理解决。

操作具有原子性

所有Redis操作都是原子操作,这确保如果两个客户端并发访问,Redis服务器能接收更新的值。

多实用工具

Redis是一个多实用工具,可用于多种用例,如:缓存,消息队列(Redis本地支持发布/订阅),应用程序中的任何短期数据,例如,web应用程序中的会话,网页命中计数等。

如何容灾

redis提供了主从热备机制,主服务器的数据同步到从服务器,通过哨兵实时监控主服务器状态并负责选举主服务器。当发现主服务器异常时根据一定的算法重新选举主服务器并将问题服务器从可用列表中去除,最后通知客户端。主从是一对多的树型结构。

 

缓存穿透

什么是缓存穿透?

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

 

如何避免?

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

 

缓存雪崩

什么是缓存雪崩?

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

 

如何避免?

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

2:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

3:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

项目中使用

在我做的项目里面,我将一些热数据存放到Redis缓存里面,这样可以减轻数据库的压力,加快用户的访问速度,使用户对我们的产品提升好感.

我在之前的公司做过一个电商项目,这个电商项目,我们将Redis技术用到了商品这一模块,我们将用户查看的商品放入redis缓存中,等用户下次访问就会比第一次访问的速度更快,当然这样也会出现问题,会给redis缓存增加压力,数据会越来越多,这一问题我们是这样的解决的,当用户点击某一个商品,我们将这一个商品放入redis缓存中,在放入缓存中我们给这件商品设置一个过期时间,当这件商品或者某一件商品达到了我们设置的这个过期时间的时候,就将它从redis缓存中删除,这样就不会使那些点击次数少的数据一直存放在redis缓存中.

其他的还有首页里面一些不经常变动的数据我也会将它放入redis缓存里面,如果有需要变动的我们可以将数据库和redis进行同步将改变的数据同步带缓存里

 

 

 

 

推荐网址:

http://www.cnblogs.com/wangyuyu/p/3786236.html

http://www.iigrowing.cn/redis-huan-cun-ji-shu-xue-xi.html

http://bigdata.51cto.com/art/201705/539015.htm

https://www.2cto.com/kf/201605/512599.html

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值