介绍
Redis官网:http://redis.io
国内社区:http://www.redis.cn
http://nosql-database.org 列出了世界上目前正在使用的nosql产品
nosql产品特点:
1、一般不适用严格的表结构(由行和列组成的表)
2、数据查询一般都不再使用sql查询
常见nosql的产品 比较:
类型
主要产品
简介
KV存储
Redis/Memcached
使用key快速查到其value,Memcached支持string类型的value,Redis除string类型外还支持set、hash、sort set、list等类型
文档存储
MongoDB /CouchDB
使用JSON或类JSON的BSON数据结构,存储内容为文档型,能实现部分关系数据库的功能
列存储
HBase /Cassandra
按照列进行数据存储,便于存储结构化和半结构化数据,方便做数据压缩和针对某一列和某几列的数据查询
图存储
Neo4J /FlockDB
图形关系的存储,能够很好弥补关系数据库在图形存储的不足
对象存储
Db4o /Versant
通过类似面向对象语言的方式操作数据库,通过对象的方式存取数据
XML存储
Berkeley DB XML /BaseX
高效存储XML数据,支持XML的内部查询语言,如XQuery、XPath
总结:redis是个key-value类型的nosql产品,数据在内存中获取,同时支持数据的持久化操作,保证了数据安全。注意:数据是无价的。
Redis安装
window系统下Redis的安装
redis安装包中文件介绍
在命令行工具窗口启动redis服务端
1 2 3 4 5 6 7 8 9 启动客户端 redis -cli.exe -h 192.168.1.11 -p 6379 测试: >set name asion //设置个string类型数据,key=name,value=asion >get name //获取name的value -h redis服务器的IP地址 -p redis的端口 默认6379 按ctrl+c 关闭redis服务
Linux下redis的安装 ,需要redis源码包和php扩展包
xshell操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 make命令: make是用来编译的,它从Makefile中读取指令,然后编译。大多数的源代码包都经过这一步进行编译(当然有些perl或python编写的软件需要调用perl或python来进行编译) make all:编译程序、库、文档等(等同于make) make install:安装已经编译好的程序(有些软件需要先运行 make check 或 make test来进行一些测试),这一步一般需要你有 root 权限(因为要向系统写入文件),复制文件树中到文件到指定的位置。 make unistall:卸载已经安装的程序。 make clean:删除由make命令产生的文件 make distclean:删除由./configure产生的文件 make check:测试刚刚编译的软件(某些程序可能不支持) make installcheck:检查安装的库和程序(某些程序可能不支持) make dist:重新打包成packname-version.tar.gz //连接ftp(用FlashFXP软件),上传redis源码包和php扩展包到linux系统,cp包到 linux下 /user/local/src/ #service vsftpd status (查看ftp服务有没有开启) #tar -zxvf redis-3.0.7.tar.gz 进入目录,并进行解压,进入源码包目录 #make(直接make,不需要使用configure过程,这是编译) #make PREFIX=/user/local/redis install(指定安装目录) #mkdir /etc/redis //安装redis到指定目录 #cp redis.conf /etc/redis/ # ./redis-server //cd 切换到redis/bin,启动服务,可以ctrl +c关闭服务 #vim /etc/redis/redis.conf //使redis服务在后台运行,修改配置文件redis.conf,将daemonize no 改为daemonize yes完成保存 在bin目录下 #./redis-server /etc/redis/redis.conf //使用配置文件启动服务 查看redis服务是否正常启动 #ps axu |grep redis-server //使用ps查看,看到./redis-server*:6379 #netstat -tunple | grep 6379 //使用netstat查看,看到LISTEN和redis-server #pkill -9 redis-server //关闭后台redis服务,用pkill关闭 //在用ps或netstat查看 //使用客户端连接服务 #./redis-server /etc/redis/redis.conf(确保服务启动) #./redis-cli -h 192.168.1.11 -p 6379 测试 >set name asion(set命令,key是name,value是asion ) >get name(获取value值)
redis数据结构类型
string
1 2 3 4 5 6 7 >set name asion //set设置,key是name,value是asion >incr age //对key为age的value +1操作 >decr age //对key为age的value -1操作 >incrby age 23 //对key为age的value+23 >decrby age 23 //对key为age的value-23 >keys * //获取redis中所有key >del age //对key为age的进行删除操作
redis中对key的设计
场景:
获得最新的10个登录用户信息:select * from user order by logintime desc limit 10;
mysql中it_user表
1 2 3 4 it_user:id:1:username 保存username,若保存email,则将username换成email 表名:主键字段:主键值:其他字段 >set it_user:id:1:username asion //设置key为it_user:id:1:username,value为asion >keys it_user:id:1* //h获取id为1的用户的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1.Redis的数据是共享的: redis集群,如果将用户信息存储在web服务的本地缓存,则每个web服务都会缓存一份,当用户修改昵称时,需要通知其它web服务更新用户缓存。 如果将用户信息存储在Redis,则只有一份缓存,所有的web访问的都是同一份缓存,当用户修改昵称时,所有web服务都能同时访问到最新的缓存。 2.Redis是单线程的 由于Redis的性能瓶颈在于内存读写速度,而不是CPU,设计者将Redis设计成了单线程模式,其所有操作都是原子性的,避免了多线程带来的复杂性。 应用场景 1.计数器 string类型的incr和decr命令的作用是将key中储存的数字值加一/减一,这两个操作具有原子性,总能安全地进行加减操作,因此可以用string类型进行计数,如微博的评论数、点赞数、分享数,抖音作品的收藏数,京东商品的销售量、评价数等。 2.分布式锁 string类型的setnx的作用是“当key不存在时,设值并返回1,当key已经存在时,不设值并返回0”,“判断key是否存在”和“设值”两个操作是原子性地执行的,因此可以用string类型作为分布式锁,返回1表示获得锁,返回0表示没有获得锁。 例如,为了保证定时任务的高可用,往往会同时部署多个具备相同定时任务的服务,但是业务上只希望其中的某一台服务执行定时任务,当定时任务的时间点触发时,多个服务同时竞争一个分布式锁,获取到锁的执行定时任务,没获取到的放弃执行定时任务。定时任务执行完时通过del命令删除key即释放锁,如果担心del命令操作失败而导致锁一直未释放,可以通过expire命令给锁设置一个合理的自动过期时间,确保即使del命令失败,锁也能被释放。不过expire命令同样存在失败的可能性,如果你用的是Java语言,建议使用JedisCommands接口提供的String set(String key, String value, String nxxx, String expx, long time)方法,这个方法可以将setnx和expire原子性地执行,其它语言的Redis客户端也应当提供了类似的方法。 3存储对象 利用JSON强大的兼容性、可读性和易用性,将对象转换为JSON字符串,再存储在string类型中,是个不错的选择,如用户信息、商品信息等。
string底层是简单动态字符串(simple dynamic string, SDS)
C字符串
SDS
获取字符串长度的复杂度为O(N)
获取字符串长度的复杂度为O(1)
API是不安全的,可能会造成缓冲区溢出
API是安全的,不会造成缓冲区溢出
修改字符串长度N次必然需要执行N次内存重分配
修改字符串长度N次最多需要执行N次内存重分配
只能保存文本数据
可以保存文本或者二进制数据
可以使用所有库中的函数
可以使用一部分库的函数
参考:https://blog.csdn.net/pugongying_95/article/details/99718749
hash
1 2 3 4 5 6 7 >hset userInfo name asion //hsetd命令设置单个,key为userInfo,value为name asion //类似于php中关联数组$userInfo=array('name'=>'asion') >hget userInfo name //获取单个值value >hmset userInfo age 12 email gogo@163.com //hmset设置多个,获取单个值value是一样的操作,获取userInfo全部value值,用hgetall >hgetall userInfo
1 2 3 4 1.购物车 以用户id为key,商品id为field,商品数量为value,恰好构成了购物车的3个要素。 2.存储对象 hash类型的(key, field, value)的结构与对象的(对象id, 属性, 值)的结构相似,也可以用来存储对象。
参考:https://www.cnblogs.com/pangzizhe/p/10657801.html
list链表
左侧头部,右侧尾部
1 2 3 4 5 lpush link1 a //从左侧(头部)向链表link1压入a rpush link2 A //从右侧(尾部)向链表link2压入A lrang link1 0 -1//从左侧开始取link1数据,0是第一个单元,-1代表最后一个单元 lpop link1 //弹出link1左侧第一个元素 rpop link1 //弹出link1右侧第一个元素
1 2 3 4 5 6 1.消息队列 list类型的lpop和rpush(或者反过来,lpush和rpop)能实现队列的功能,故而可以用Redis的list类型实现简单的点对点的消息队列。不过我不推荐在实战中这么使用,因为现在已经有Kafka、NSQ、RabbitMQ等成熟的消息队列了,它们的功能已经很完善了,除非是为了更深入地理解消息队列,不然我觉得没必要去重复造轮子。 2.排行版 list类型的lrange命令可以分页查看队列中的数据。 3.最新列表 list类型的lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表,如朋友圈的点赞列表、评论列表
https://www.cnblogs.com/pangzizhe/p/10674501.html
秒杀场景的使用,作为参考:
https://blog.csdn.net/a7442358/article/details/102463137
set集合
三特定:
1、数据彼此没有顺序之分
2、数据彼此不重复
3、数据的个数是确定的
常见运算:
交集、并集、差集
1 2 3 4 sadd set1 a //像集合set1中添加单元a smembers set1 //获取集合set1中的所有单元 srem set1 a //移除集合set1中的a单元 spop set1 //随机弹出集合中的一个单元
社交类网站中用于推荐好友、共同好友等。
1 2 3 4 5 6 7 8 sinter set:user:id:3:friend set:user:id:45:friend //3号用户和45号用户的共同好友(求交集) sunion set:user:id:3:friend set:user:id:45:friend //3号用户和45号用户的全部好友(并集) sdiff set:user:id:3:friend set:user:id:45:friend //让3号用户给45号用户推荐好友(差集)
1 2 3 4 5 6 7 8 9 10 1.好友/关注/粉丝/感兴趣的人 set类型唯一的特点使得其适合用于存储好友/关注/粉丝/感兴趣的人集合,集合中的元素数量可能很多,每次全部取出来成本不小,set类型提供了一些很实用的命令用于直接操作这些集合,如 a. sinter命令可以获得A和B两个用户的共同好友 b. sismember命令可以判断A是否是B的好友 c. scard命令可以获取好友数量 d. 关注时,smove命令可以将B从A的粉丝集合转移到A的好友集合 2.随机展示 通常,app首页的展示区域有限,但是又不能总是展示固定的内容,一种做法是先确定一批需要展示的内容,再从中随机获取 3.黑名单/白名单 经常有业务出于安全性方面的考虑,需要设置用户黑名单、ip黑名单、设备黑名单等,set类型适合存储这些黑名单数据,sismember命令可用于判断用户、ip、设备是否处于黑名单之中
参考:https://www.cnblogs.com/pangzizhe/p/10723019.html
zset(sort set)
三特点:
1、数据彼此有顺序之分(权重:如1-9阿拉伯数字或者 a-z字母顺序等)
2、数据彼此不重复
3、数据的个数是确定的
1 2 3 4 //给class:phpRank的集合中添加权重为5的mark zadd class:phpRank 5 mark //显示集合中的元素和对应权重(withscores按权重排好序了) zrange class:phpRank 0 -1 withscores
应用场景
1 2 3 4 5 6 1.延时队列 score作为时间戳,自动按照时间最近的进行排序,启一个线程持续poll并设置park时间,完成延迟队列的设计 2.排行榜 score作为浏览次数,自动进行排序,但要注意冷数据 3.滑动窗口限流 score作为时间戳,可统计最近一段时间内内的成员数量,实现滑动窗口限流
参考:https://zhuanlan.zhihu.com/p/147912757
redis持久化功能
redis为了本身数据的安全和完整性,会将内存中的数据按照一定的方法同步到电脑的磁盘中,这个过程被称为持久化操作;下次再次启动redis服务时,会将磁盘上保存的数据重新的加载到内存中。
常见的持久化操作方式有两种:
a基于快照的方式:按照一定周期把将内存中的数据同步到磁盘文件中。
b基于日志文件的追加:把对redis数据造成更改的命令记录到日志文件里面,然后在再一次重启的时候,执行一下日志文件里面对redis写的操作,达到数据还原的目的。
持久化技术对于Redis服务性能来说是有损的
基于快照的方式
1、修改配置文件
1 2 3 #vim /etc/redis/redis.conf :/save搜索save,按n下一个 找到内容->基于周期性持久化,只要任何一个条件达到,就会触发
save 900 1 含义,如果在900s内对redis的key进行过1次操作,则会把内存里面的数据同步到磁盘文件
save 300 10 含义,如果在300s内对redis的key进行过10次操作,则会把内存里面的数据同步到磁盘文件
save 60 10000 含义,如果在60s内对redis的key进行过10000次操作,则会把内存里面的数据同步到磁盘文件
保存磁盘的文件位置
实操:
1 2 >bgsave //人为的触发基于快照的持久化操作 #pkill -9 redis -sever //人为的模拟服务宕机
基于文件追加的方式
1、修改redis.conf文件
1 #vim /etc/redis/redis.conf
备份文件的周期
appendfsync always 只要存在对redis数据造成更改的操作,都要记录到磁盘文件上
appendfsync everysec 每1s进行一次,把对redis数据造成更改的操作,都要记录到磁盘文件上
appendfsync no 完全交给操作系统来完成,即当操作系统不繁忙的时候,会把对redis数据造成更改的操作,都要记录到磁盘文件上,这种操作最不靠谱。
实操:基于文件追加方式的文件已经存在
基于快照和日志文件的持久化场景
RDB(快照)和AOF(日志)区别场景分析
RDB
优点:
RDB快照是一个压缩过的非常紧凑的文件,保存着某个时间点的数据集,适合做数据的备份,灾难恢复;
可以最大化Redis的的性能,在保存RDB文件,服务器进程只需要fork一个子进程来完成RDB文件的创建,父进程不需要做IO操作;
与AOF相比,恢复大数据集的时候会更快;
缺点:
RDB的数据安全性是不如AOF的,保存整个数据集的过程是比繁重的,根据配置可能要几分钟才快照一次,如果服务器宕机,那么就可能丢失几分钟的数据;
Redis数据集较大时,fork的子进程要完成快照会比较耗CPU、耗时;
AOF
优点:
数据更完整,安全性更高,秒级数据丢失(取决fsync策略,如果是everysec,最多丢失1秒的数据);
AOF文件是一个只进行追加的日志文件,且写入操作是以Redis协议格式保存,内容是可读的,适合误删紧急恢复;
缺点:
对于相同的数据集,AOF文件的体积要大于RDB文件,数据恢复也会比较慢;
根据所使用的fsync策略,AOF的速度可能会慢于RDB(性能降低的影响)。 不过在一般情况下,每秒fsync的性能依然非常高;
RDB和AOF的选择 :
通常来说,应该同时使用两种持久化方案,以保证数据安全。
如果数据不敏感,且可以从其他地方重新生成,可以关闭持久化。
如果数据比较重要,且能够承受几分钟的数据丢失,比如缓存等,只需要使用RDB即可。如果不能承受数分钟以内得数据丢失,对业务数据非常敏感,选用AOF
如果是用做内存数据,要使用Redis的持久化,建议是RDB和AOF都开启。
如果只用AOF,优先使用everysec的配置选择,因为它在可靠性和性能之间取了一个平衡。
灾难恢复选用RDB双保险策略,当RDB与AOF两种方式都开启时,Redis会优先使用AOF恢复数据,因为AOF保存的文件比RDB文件更完整。
参考官网:https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/
持久化应用场景
1Redis应用于抢购、限购、限量发放优惠券、激活等业务的数据存储设计
2Redis应用于具有操作先后顺序的数据控制
3Redis应用于最新消息展示
4Redis应用于基于黑名单与白名单设定的服务控制
5Redis应用于计数器组合排序功能对应的排名
6Redis应用于按次结算的服务控制
参考:https://blog.csdn.net/weixin_35099248/article/details/111577925
mongodb的高并发处理https://www.cnblogs.com/hulianwangjiagoushi/p/12073244.html