Redis

Redis

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件,它是一个key-value存储系统,它支持存储的value类型相对更多,包括string(字符串)、list(链表)
set(集合)、zset(sorted set 有序集合)和hash(哈希类型)。
这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。
在此基础上,redis支持各种不同的方式排序。与memcaced一样,为了保证效率,数据都是缓存在内存中。
区别是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

一、使用redis有哪些好处?

1. 速度快,因为数据存在内存中,类时于hashMap,hashMap的优势就是查找和操作的时间复杂度都是0(1)

2. 支持丰富的数据类型,支持string,list,set,sorted set,hash(字典)

3. 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行

4. 丰富的特性: 可用于缓存,消息,按key设置过期时间,过期后将会自动删除

二、redis相比memcached有哪些优势?

1. memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型

2. redis的速度比memcached快很多

3. redis可以持久化其数据

三、redis常见性能问题和解决方案?

1. master 最好不要做任何持久化工作,如rdb内存快照和aof日志文件

2. 如果数据比较重要,某个slave开启aof备份数据,策略设置为每秒同步一次

3. 为了主从复制的速度和连接稳定性,master和slave最好在同一个局域网内

4. 尽量避免在压力很大的主库上增加从库

5. 主从复制不要用图状结构,用单向链表结构更为稳定,即:master < slave1 < slave2……

这样的结构方便解决单点故障问题,实现slave对master的替换,如果master挂了,可以立即启用slave1做master,其它不变。

四、Mysql里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据

相关知识:

redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

redis提供6种数据淘汰策略:

voltile-lru: 从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-tt1:从已设置过期时间的数据集,中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集,任意选择数据淘汰

allkeys-lru: 从数据集中挑选最近最少使用的数据淘汰

allkeys-random:从数据集中任意选择数据淘汰

no-enviction(驱逐):禁止驱逐数据

五、memcache和redis的区别都有哪些?

1. 存储方式

memecache把数据全部存在内存之中,断电后会全挂掉,数据不能超过内存大小。

redis有部分存在硬盘上,这样能保证数据的持久性

2. 数据支持类型

memcache仅支持字符串,对数据类型支持相对简单。

redis支持更多更复杂的数据类型。

3. value大小

redis最大可以达到1GB,而memcache只有1MB

六、redis常见的性能问题都有哪些?如何解决?

1. master写内存快照,save命令调度rdbsave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以master最好不要写内存快照。

2. master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,aof文件过大会影响master重启的恢复速度。master最好不要做任何持久化工作,包括内存快照和aof日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个slave开启aof备份数据,策略为每秒同步一次。

3. master调用bgrewriteaof重写aof文件,aof在重写的时候会占大量的cpu和内存资源,导致服务load过高,出现短暂服务暂停现象。

4. redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,slave和master最好在同一个局域网内

七、redis最适合的场景

redis最适合所有数据in-momory的场景,虽然redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差别,那么可能大家就会有疑问,似乎redis更像一个加强版的memcached,那么何时使用memcached,何时使用redis呢?

如果简单的比较redis与memcached的区别,大致如下:

1. redis 不仅仅支持简单key/value类型的数据,同时还提供list,set,zset,hase等数据结构存储

2. redis支持数据的备份,即master-slave模式的数据备份。

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

- 会话缓存

最常见的一种使用redis的情景是会话缓存,用redis缓存会话比其它存储(如memcached)的优势在于,redis提供持久化,当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?幸运的是,随着redis这些年的改进,很容易找到怎么恰当的使用redis来缓存会话的文档。甚至广为认值的商业平台magento也提供redis插件。

- 全页缓存(FPC)

除基本的会话token之外,redis还提供很简便的FPC平台,回到一致性问题,即使重启了redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进。

再次以magento为例,其提供一个插件来使用redis作为全页缓存后端。

此外,对wordpress的用户来说,pantheon有一个非常好的插件,wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

- 队列

redis在内存存储引擎领域的一大优点是提供list和set操作,这使得redis能作为一个很好的消息队列平台来使用。redis作为队列使用的操作,就类似于本地程序语言python对list的push/pop操作。

如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。
View Code

- 排行榜/计数器

redis在内存中对数字进行递增或递减的操作实现的非常好。集合和有序集合也使得我们在执行这些操作的时候变的非常简单,redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户-我们称之为“user_scores” ,我们只需要像下面一样执行即可:

当然,这是假定你是根据你用户的分数做递增的排序,如果你想返回用户及用户的分数,你需要这样执行:

ZRANGE user_scores 0 10  WITHSCORES

- 发布/订阅

redis的发布和订阅功能,使用场景确实非常多,如社交网络连接中使用,还可以作为基于发布/订阅的脚本触发器,甚至用redis的发布/订阅功能来建立聊天系统。

yum安装redis

1.yum安装

#前提得配置好阿里云yum源,epel源
#查看是否有redis包
yum list redis
#安装redis
yum install redis -y
#安装好,启动redis
systemctl start redis

2.检测redis是否工作

redis-cli    #redis 客户端工具
#进入交互式环境后,执行ping,返回pong表示安装成功
127.0.0.1:6379> ping
PONG

源码安装redis,编译安装

大家用过yum,是相当省事好用吧,为什么还要学习源码安装?

有人说编译安装性能好?错

编译安装的优势是:

  • 编译安装时可以指定扩展的module(模块),php、apache、nginx都是一样有很多第三方扩展模块,如mysql,编译安装时候,如果需要就定制存储引擎(innodb,还是MyIASM)
  • 编译安装可以统一安装路径,linux软件约定安装目录在/opt/下面
  • 软件仓库版本一般比较低,编译源码安装可以根据需求,安装最新的版本
1.下载redis源码
wget http://download.redis.io/releases/redis-4.0.10.tar.gz
2.解压缩
tar -zxf redis-4.0.10.tar.gz
3.切换redis源码目录
cd redis-4.0.10.tar.gz
4.编译源文件
make
5.编译好后,src/目录下有编译好的redis指令
6.make install 安装到指定目录,默认在/usr/local/bin

注:redis没有confiure文件,所以直接make&&make install ,默认安装在当前目录
更全面的安装见:https://www.cnblogs.com/stulzq/p/9288401.html
简单
配置:https://blog.csdn.net/a_liuge/article/details/79758135

redis可执行文件

./redis-benchmark //用于进行redis性能测试的工具
./redis-check-dump //用于修复出问题的dump.rdb文件
./redis-cli //redis的客户端
./redis-server //redis的服务端
./redis-check-aof //用于修复出问题的AOF文件
./redis-sentinel //用于集群管理

启动redis服务端

启动redis非常简单,直接./redis-server就可以启动服务端了,还可以用下面的方法指定要加载的配置文件:
./redis-server ../redis.conf
默认情况下,redis-server会以非daemon的方式来运行,且默认服务端口为6379。

使用redis客户端

#执行客户端命令即可进入
./redis-cli  
#测试是否连接上redis
127.0.0.1:6379 > ping
返回pong代表连接上了

//用set来设置key、value
127.0.0.1:6379 > set name "chaoge"
OK
//get获取name的值
127.0.0.1:6379 > get name
"chaoge"

redis数据结构

redis是一种高级的key:value存储系统,其中value支持五种数据类型
字符串(strings)
散列(hashes)
列表(lists)
集合(sets)
有序集合(sorted sets)

数据结构示例

1.strings类型

set name "chaoge66" //设置name
get name    //读取name

strings类型支持数值操作
set age "17" //设置key age
get age        //读取age
incr age      //数值+1,遇见数值操作时,redis会将字符串类型转成数值
get age        //此时age是18,value仍然是字符串
type age    //查看键的类型

2.list类型

redis的另外一个数据结构叫做lists,中文叫列表
lists常用操作包括
LPUSH   在lists左侧插入一个新元素 
RPUSH   在lists右侧插入一个新元素
LRANGE  在lists指定范围提取元素
LPOP 左侧删除
RPOP  右侧删除

示例:

lpush mylist "1" //新建一个mylist,在头部插入元素"1"
(integer) 1    //返回mylist元素个数

rpush mylist "2"  //在mylist右侧插入元素"2"

(INTEGER) 2    //返回mylist元素个数

127.0.0.1:6379> lpush mylist "0"  //在mylist左侧插入元素"0"

(integer) 3    //返回mylist元素个数

//列出mylist中从编号0到编号1的元素

127.0.0.1:6379> lrange mylist 0 -1 
1) "0"
2) "1"
3) "2"

lists类型常用在,消息队列、实现分页功能、存储文章评论

3.sets集合类型

redis的集合,是一种无序的集合,集合中的元素没有先后顺序。

集合相关的操作也很丰富,如添加新元素、删除已有元素、取交集、取并集、取差集等。我们来看例子:

//向集合myset中加入一个新元素"one"
127.0.0.1:6379> sadd myset "one" 
(integer) 1
127.0.0.1:6379> sadd myset "two"
(integer) 1
//列出集合myset中的所有元素
127.0.0.1:6379> smembers myset 
1) "one"
2) "two"
//判断元素1是否在集合myset中,返回1表示存在
127.0.0.1:6379> sismember myset "one" 
(integer) 1
//判断元素3是否在集合myset中,返回0表示不存在
127.0.0.1:6379> sismember myset "three" 
(integer) 0
//新建一个新的集合yourset
127.0.0.1:6379> sadd yourset "1" 
(integer) 1
127.0.0.1:6379> sadd yourset "2"
(integer) 1
127.0.0.1:6379> smembers yourset
1) "1"
2) "2"
//对两个集合求并集
127.0.0.1:6379> sunion myset yourset 
1) "1"
2) "one"
3) "2"
4) "two"

集合的使用比如QQ社交功能中的“好友标签”,朋友给你的好友标签“sb”,“dsb”等等,就可以吧每一个用户的标签存储在集合里

4.sorted sets有序集合

redis不但提供了无需集合(sets),还很体贴的提供了有序集合(sorted sets)。有序集合中的每个元素都关联一个序号(score),这便是排序的依据。

很多时候,我们都将redis中的有序集合叫做zsets,这是因为在redis中,有序集合相关的操作指令都是以z开头的,比如zrange、zadd、zrevrange、zrangebyscore等等

127.0.0.1:6379> zadd myzset 1 baidu.com 
(integer) 1
//向myzset中新增一个元素360.com,赋予它的序号是3
127.0.0.1:6379> zadd myzset 3 360.com 
(integer) 1
//向myzset中新增一个元素google.com,赋予它的序号是2
127.0.0.1:6379> zadd myzset 2 google.com 
(integer) 1
//列出myzset的所有元素,同时列出其序号,可以看出myzset已经是有序的了。
127.0.0.1:6379> zrange myzset 0 -1 with scores 
1) "baidu.com"
2) "1"
3) "google.com"
4) "2"
5) "360.com"
6) "3"
//只列出myzset的元素
127.0.0.1:6379> zrange myzset 0 -1 
1) "baidu.com"
2) "google.com"
3) "360.com"

5.哈希数据结构

hashes即哈希。哈希是从redis-2.0.0版本之后才有的数据结构。

hashes存的是字符串和字符串值之间的映射,比如一个用户要存储其全名、姓氏、年龄等等,就很适合使用哈希。

//建立哈希,并赋值
127.0.0.1:6379> HMSET user:001 username antirez password P1pp0 age 34 
OK
//列出哈希的内容
127.0.0.1:6379> HGETALL user:001 
1) "username"
2) "antirez"
3) "password"
4) "P1pp0"
5) "age"
6) "34"
//更改哈希中的某一个值
127.0.0.1:6379> HSET user:001 password 12345 
(integer) 0
//再次列出哈希的内容
127.0.0.1:6379> HGETALL user:001 
1) "username"
2) "antirez"
3) "password"
4) "12345"
5) "age"
6) "34"

redis的事务

事务:所有事件,必须都完成,才结束,如果有任一出现问题,则回滚到初始状态,如转账转出方扣钱成功,转入方账户钱增加,才成功,如果转出中间宕机,则视为不成功,回滚初始每扣钱状态。

import redis

pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
red = redis.Redis(connection_pool=pool)

# redis事务transaction的概念是通过管道的概念来实现的
pipe = red.pipeline(transaction=True)
pipe.multi()

pipe.set('name', 'money')
pipe.set('age', '18')

pipe.execute()

redis的发布/订阅

发布者:

import redis

pool = redis.ConnectionPool(host='127.0.0.1', port=6379) # 默认2**31
redis = redis.Redis(connection_pool=pool)

redis.publish('xxx', 'hello_world')

订阅者:

import redis

pool = redis.ConnectionPool(host='127.0.0.1', port=6379)  # 默认2**31
redis = redis.Redis(connection_pool=pool)

pub = redis.pubsub()  # 获取发布订阅对象
pub.subscribe("xxx")  # 调用订阅方法,监听那个键,即字符串
# pub.parse_response() # 等待响应

while True:
    msg = pub.parse_response()
    print(msg)

redis安全

https://www.cnblogs.com/pyyu/p/9515937.html 

redis-sentinel实战

https://www.cnblogs.com/pyyu/p/9718679.html

redis主从同步

1.安装好master、slave两个节点的redis

2.检查master配置文件

#查看配置文件有用信息行
egrep -v '#|^$' /etc/redis.conf
#主要修改的几行
bind 192.168.119.10 #填写本机ip地址
daemonize yes #设置后台进程方式运行

3.检查设置slave配置文件

bind 192.168.119.11 
daemonize yes
slaveof 192.168.119.10 6379 #填写master的ip端口

4.在master、slave皆启动redis服务,指定配置文件

redis-server /etc/redis.conf

5.在master上设置key,去slave上检查数据,完成简单的主从复制配置

Redis能干啥?细看11种Web应用场景

下面列出11种Web应用场景,在这些场景下可以充分的利用Redis的特性,大大提高效率。

1.在主页中显示最新的项目列表。

Redis使用的是常驻内存的缓存,速度非常快。LPUSH用来插入一个内容ID,作为关键字存储在列表头部。LTRIM用来限制列表中的项目数最多为5000。如果用户需要的检索的数据量超越这个缓存容量,这时才需要把请求发送到数据库。

2.删除和过滤。

如果一篇文章被删除,可以使用LREM从缓存中彻底清除掉。 

3.排行榜及相关问题。

排行榜(leader board)按照得分进行排序。ZADD命令可以直接实现这个功能,而ZREVRANGE命令可以用来按照得分来获取前100名的用户,ZRANK可以用来获取用户排名,非常直接而且操作容易。

4.按照用户投票和时间排序。

这就像Reddit的排行榜,得分会随着时间变化。LPUSH和LTRIM命令结合运用,把文章添加到一个列表中。一项后台任务用来获取列表,并重新计算列表的排序,ZADD命令用来按照新的顺序填充生成列表。列表可以实现非常快速的检索,即使是负载很重的站点。

5.过期项目处理。

使用unix时间作为关键字,用来保持列表能够按时间排序。对current_time和time_to_live进行检索,完成查找过期项目的艰巨任务。另一项后台任务使用ZRANGE...WITHSCORES进行查询,删除过期的条目。

6.计数。

进行各种数据统计的用途是非常广泛的,比如想知道什么时候封锁一个IP地址。INCRBY命令让这些变得很容易,通过原子递增保持计数;GETSET用来重置计数器;过期属性用来确认一个关键字什么时候应该删除。

7.特定时间内的特定项目。

这是特定访问者的问题,可以通过给每次页面浏览使用SADD命令来解决。SADD不会将已经存在的成员添加到一个集合。

8.实时分析正在发生的情况,用于数据统计与防止垃圾邮件等。

使用Redis原语命令,更容易实施垃圾邮件过滤系统或其他实时跟踪系统。

9.Pub/Sub。

在更新中保持用户对数据的映射是系统中的一个普遍任务。Redis的pub/sub功能使用了SUBSCRIBE、UNSUBSCRIBE和PUBLISH命令,让这个变得更加容易。 

10.队列。

在当前的编程中队列随处可见。除了push和pop类型的命令之外,Redis还有阻塞队列的命令,能够让一个程序在执行时被另一个程序添加到队列。你也可以做些更有趣的事情,比如一个旋转更新的RSS feed队列。

11.缓存。

Redis缓存使用的方式与memcache相同。

网络应用不能无休止地进行模型的战争,看看这些Redis的原语命令,尽管简单但功能强大,把它们加以组合,所能完成的就更无法想象。当然,你可以专门编写代码来完成所有这些操作,但Redis实现起来显然更为轻松。

毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作,为不同的大象构建不同的冰箱。希望你喜欢这个比喻。

下面是一篇新鲜出炉的文章,其作者是Redis作者@antirez,他描述了Redis比较适合的一些应用场景,NoSQLFan简单列举在这里,供大家一览:

1.取最新N个数据的操作

比如典型的取你网站的最新文章,通过下面方式,我们可以将最新的5000条评论的ID放在Redis的List集合中,并将超出集合部分从数据库获取

  • 使用LPUSH latest.comments<ID>命令,向list集合中插入数据
  • 插入完成后再用LTRIM latest.comments 0 5000命令使其永远只保存最近5000个ID
  • 然后我们在客户端获取某一页评论时可以用下面的逻辑(伪代码)
FUNCTION get_latest_comments(start,num_items):
    id_list = redis.lrange("latest.comments",start,start+num_items-1)
    IF id_list.length < num_items
        id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")
    END
    RETURN id_list
END

如果你还有不同的筛选维度,比如某个分类的最新N条,那么你可以再建一个按此分类的List,只存ID的话,Redis是非常高效的。

2.排行榜应用,取TOP N操作

这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。

3.需要精准设定过期时间的应用

比如你可以把上面说到的sorted set的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。

4.计数器应用

Redis的命令都是原子性的,你可以轻松地利用INCR,DECR命令来构建计数器系统。

5.Uniq操作,获取某段时间所有数据排重值

这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。

6.实时系统,反垃圾系统

通过上面说到的set功能,你可以知道一个终端用户是否进行了某个操作,可以找到其操作的集合并进行分析统计对比等。没有做不到,只有想不到。

7.Pub/Sub构建实时消息系统

Redis的Pub/Sub系统可以构建实时的消息系统,比如很多用Pub/Sub构建的实时聊天系统的例子。

8.构建队列系统

使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。

redis的妙用

https://mp.weixin.qq.com/s/ASzGn4op1ItKJxTn5ZJZHA?tdsourcetag=s_pcqq_aiomsg

原文地址:https://www.cnblogs.com/sunxiuwen/p/9818678.html