目录
命令查询官方文档:http://www.redis.cn/
一. Redis的历史
1. 什么是nosql
nosql=not only sql,不仅仅是sql,是区别于关系型数据库的一种。
关系型数据库:具有行列组成的表格样式的数据库
nosql数据库:数据的存储不需要指定类型、不需要过多的操作就可以横向扩展,
2. nosql特点:
- 方便扩展(数据之间KV存储,没有关系,很好扩展)
- 大数据量高性能(官方测试一秒钟读取11万,写8万次)
- 数据类型是多样的,随取随用,并可以设置过期
- 关系型数据库RDBMS和nosql数据库区别
传统的RDBMS:
- 结构化组织(行列组成的表关系)
- 有单独的执行操作语法
- 严格的一致性
- 事务控制
nosql数据库:
- 没有固定的查询语句
- 存储形式多样:键值对存储、列存储、文档存储、图形数据库
- 保证最终一致性
- 高性能、高可用、高扩展
- CAP定理和BASE 实现了异地多活。
3. nosql 的四大分类
①KV键值对
通过KV的形式完成存储,像Redis的KV键值对
②文档型数据库
最经典的就是MongoDB,他是一个基于分布式文件存储的数据库,主要用来处理大量的文件
他是介于关系型数据库和非关系型数据库之间,并且是非关系型数据库中最接近关系型数据库的数据库.
③列数据库
Hbase、分布式文件系统等以列进行存储的数据库
④图形数据库(关系拓扑图)
一般用来存储朋友圈社交网络、广告产品推荐等。
------图片来自网络
4. 什么是Redis、Redis能做什么?
Redis(Remote Dictionary Server ),即远程字典服务。是支持网络、可基于内存亦可持久化的日志型、Key-Value数据库。
Redis能做什么:
- 可以作为内存存储,并提供持久化功能(内存不持久化则断电即失)
- 效率高,可以用于告诉缓存
- 发布订阅系统
- 地图信息分析
- 计数器计时器控制
二.Redis安装以及基本知识
1. Linux安装Redis
①下载Redis安装包:https://redis.io/
②解压安装包至/usr/develop/redis目录中
③解压安装包,tar -zxvf redis-5.0.8.tar.gz
④安装Redis编译环境: yun install -y gcc-c++
⑤进入到Redis的路径,make执行编译后make install执行安装。
⑥安装完成后默认安装目录是在/usr/local/bin下,将安装包中的配置文件rdis.conf复制到/usr/local/bin/wconf下:
cp /usr/develop/redis/redis.conf /usr/local/bin/wconf
⑦修改配置文件:
默认是非后台启动,修改为后台启动:daemonize yes
默认是本机访问,修改为任意终端访问:bind 0.0.0.0
默认是无密码访问,添加Redis访问密码:取消第502行的注释,并修改密码为root
# use a very strong password otherwise it will be very easy to break.
# requirepass root
# Command renaming.
⑧启动Redis。指定配置文件方式启动:在/usr/local/bin路径下:./redis-server wconf/redis.conf,查询到Redis进程号即代表启动成功了。
⑨启动客户端测试ping为pong即代表服务启动成功
2. redis-benchmark压力测试工具的使用
redis-benchmark是Redis官方的压力测试工具,通过命令来进行测试。
简单测试1000个并发下请求10W个请求,每次请求100字节的压力测试命令:
redis-benchmark -h localhost -p 6379 -c 1000 -n 100000 -d 100
其他常用指令可自行百度
3. Redis的基本知识
---redis默认有16个库,在配置文件database 16 中表示
---Redis是单线程
Redis是基于内存操作。CPU不是Redis的性能瓶颈(多线程是CPU),Redis的瓶颈是根据机器的内存和网络带宽。所以使用单线程来实现。
为什么单线程还这么快呢:
①多线程不一定比单线程效率高,多线程会涉及到CPU的上下文切换,这是一个耗时的操作。Redis是完全放在内存操作的,读写都是在同一个CPU上操作的。同时也不存在并发时的加锁释放锁的问题。当访问量多时,单线程能够节省多线程CPU的上下文切换。所以说单线程是最快。
②才用多路IO复用模型,属于非阻塞IO
4. redis的常用命令
不会的命令可以查看官网
* select 6 #切换数据库
* dbsize #查看数据库大小
三. Redis的五大数据类型
redis-key的命令
* keys * # 查看所有key
* flushdb #清空当前库 flushall #清空所有数据库
* exists key #查询某个key是否存在,1存在/0不存在
* move key 1 #移除key值,1代表当前库
* expire key 30 #设置key值30秒过期
* ttl key #查询key的剩余过期时间 单位是S
* type key #查看key的数据类型
1. String(字符串)
字符串类型的KV数据,使用场景:value一般是字符串或者数字。可以用来做计数器、统计数量等
* set key hello #设置值
* get key #获取值
*del name #删除键值
* mset k1 v1 k2 v2 # 批量设置kv值,同时set了k1、k2
* mget k1 k2 # 批量获取值,同时获取k1、k2的值
* append key "append" # 给key值后面追加字符串append,如果key值不存在,则会新创建
* strlen key #获取字符串的长度
* incr key #将key值+1,可以用来记录网站的浏览量 每次执行就会+1,操作非数字的key会报错
* incrby key 10 #将key值每次+10,即可以设置步长
* decr key #将key值-1。
* decrby key 10 #将key值每次-10
* getrange key 0 3 #截取字符串,相当于java中substring, getrange key start end ,从0开始,本例为从0截取到3---->[0,3]字符
GETRANGE key1 4 -1 #从4截取到最后,-1为最后。
* setrange key 1 xx #替换,把key中从第1个开始,替换成xx。指定位置的替换。可替换一个或多个
* setex(set with expire) #设置一个key值,并设置过期时间 : setex key 30 "hello", 设置key值为hello并30秒过去
* setnx(set if no exist) #设置一个key值,当他不存在时,如果该key值已经存在,则会设置失败,直接set如果存在则会覆盖
setnx key "hello" 如果存在返回0,set失败,如果不存在返回1,set成功。 在分布式锁中常常会被使用。
* msetnx k1 v1 k4 v4 #setnx是一个原子性操作,如果k1已经存在了,k4不存在,同样k4也不会添加成功。
技巧:通过巧妙的key值,方便工作 例如,设置ID为1的用户登录次数+1 set user:1:login 0 以后再每次给该用户+1时,可以动态的根据ID来给该value值进行操作,不用直接存储user对象解析后再+1了。
* getset key hello # 如果不存在值,返回null,并设置新值,如果存在,返回原来值,并设置新的值。可用来更新操作。
2. list(列表)
在Redis里,可以把list作为栈、队列、阻塞队列来使用。list中的值是可以重复的。
所有list命令都是用l开头的。
list的存储顺序是: lpush list one, lpush list two, lpush list three。则获取第0个位three,获取第1个位two,获取第2个为one.顺序为先进后出。倒着来的。
list 实际上是一个链表,存在node,node 有before和after, 在left和right都可以进行插入值。
在两边执行操作,效率最高,但是在中间元素操作,效率会低一点。
* lpush list one lpush list two lpush list three #将一个值或者多个值放入列表的头部,push的顺序是往左边(头部)放,存放顺序是从右至左
* lrange list 0 -1 #获取全部的list值, lrange list 0 1 ,获取0-1的值, 顺序是从左到右取值。
list在存放值的时候存在正序下标与倒序下标:lrange 就是根据两种不同下标来进行获取数据的
* rpush list four #将一个多个值放在列表的尾部。push的顺序是往右边(尾部)放,存放顺序为从左往右。
* lpop list #将list的值最左边的值移除,并返回该值。即第一个
* rpop list #将list的最右边的值移除,并返回该值。即最后一个
* lrem list 2 one #从左到右移除list中指定的两个one值,并指定移除个数
* lindex list 1 # 通过下标获取list中的某个值。从0开始
* LLEN list #获取list的长度
* ltrim list 1 2 #将list中的1-2位置上的值进行截取,list中其余的就没有了。通过下标截取指定长度。
* rpoplpush list otherList #移动操作。将list中的最后一个(rpop)移动到(lpush) otherList中去,otherlist中就是list被移除的最后一个值
* lset list 0 value #将列表中已经存在的指定下标的值更新为另一个值,如果list不存在/或者下标越界,则报错。
* linsert list before/after "hello" "other" #在list中指定的元素前/后 插入一个指定的value值。hello是list中存在的指定元素, other 是需要插入的值,此时执行结果就是 list中多了一个元素,在hello的前面
3. set(集合)
set集合中的元素是不可重复的,并且是无序的
* sadd set1 "hello" #在set1这个set集合中添加一个值,如果是已经存在的值则会报错(返回0)
*smember set1 #返回该集合中的所有值
*sismember set1 hello #查询该集合中是否存在该值,存在返回1 不存在返回0
*scard set1 #返回该集合的个数
*srem set1 hello #移除该集合中的hello值
*srandmember set1 # 随机获取该集合中的一个值,可用来做随机业务
*srandmember set1 2 #随机获取该集合中的指定个数值,用来做随机业务
*spop set1 [count] #随机删除(弹出)集合中的某个元素,可指定个数,并返回移除的值
*smove set1 set2 hello #移动,将set1中的hello移动到set2中,如果set2不存在,则会创建该集合,如果set1不存在,则失败
*sdiff set1 set2 #获取两个集合中的差集,拿set1对比set2
*sinter set1 set2 #获取两个集合中的交集 共同好友可以这样实现
*sunion set1 set2 #获取两个集合中的并集
4. Hash(哈希)
hash的存储方式为:key-map(key-value) ,适合存储经常修改更新的对象,例如user信息等。本质和string类型没有太大区别
实际应用中,存储对象一般有1. string类型存储k -json的形式,2. hash类型存储对象,但是string类型不够灵活,操作时需要先把json序列华为对象,在进行操作。
总结:,一般对象用string + json存储,对象中某些频繁变化的属性抽出来用hash存储。
*hset key field value #给hash类型的key值存放 field:value值,如果该值已经存在,则会替换覆盖原来的值
*hset h f1 "a"
*hmset h f1 a f2 b f3 c #给h批量添加field值
*hget h f1 #获取h 的f1值
*hgetall h #获取h的所有KV值
*hdel h f1 #删除h中制定的f1值,可同时删除多个
*hlen h #获取hash的长度,数量
*hexists h f1 #查询h中f1字段是否存在,存在返回1,不存在返回0
*hkeys h #查询该对象中所有的key
*hvals h #查询该对象所有的value值
hincrby h f2 1 #增量、将h的f2字段+1 必须是整数型,否则报错。如果f2不存在,则会先初始化为0,然后再执行incrby,可以配合 expire设置固定时间的点击次数,作为原子性计数器来用等。
hsetnx h f2 aa #判断是否存在,如果f2存在则set失败0,如果不存在则成功1
5. Zset(有序不可重复集合)
zset是有序集合,可以实现应用在排行榜等排序的功能实现上。
zset在set的基础上,增加了一个值
set: sadd set a
zset: zadd zset 1 a #意思是存储在zset对象中的a值,有一个排序值1
*zadd zset 1 a #意思是存储在zset对象中的a值,有一个排序值1,该排序值为数字
*zrange zset 0 -1 #与list一样,0 -1是获取所有的值
*zrange zset 0 -1 #获取该集合中的所有值
*zrangebyscore zset -inf +inf withscores #该集合按照score排序,从负无穷到正无穷,并显示出score的值。默认语法是从最小 值到最大值
*zrangebyscore zset 500 2500 withscores #显示该集合中500 <= score <=2500的所有值,并显示出score的值
*zrangebyscore zset (500 2500 withscores #显示该集合中500 < score <=2500的所有值,默认是闭区间,加(表示开区间
*zrem zset a #移除zset中的a值
*zcard zset #查询zset的长度
*zcount zset 1 5 #获取score在1-5之间的成员数量
四. 三种特殊数据类型
1. geospatial (地理位置)
朋友的定位,附近的人,距离计算等...
附近的人实现思路:
定时更新用户地理位置,并存储在Redis的geo中,当用户需要获取附近的人时,以该用户为中心,获取该用户指定范围内的指定人数。返回用户信息即可。
只有六个命令
*geoadd china:city 120.16 30.24 hangzhou #geoadd key 纬度 经度 城市名 添加地理位置,两极无法直接添加
*geopos china:city beijing shanghai #获取指定key指的经纬度
*geodist china:city beijing shanghai #获取北京到上海的直线距离,单位默认是m 可以指定:m km(千米) mi(英里) ft(英尺)
*georadius china:city 110.00 30.00 1000 km [withdist] [withcoord] [count 1]
#以给定的经纬度为中心,找出该集合中某一半径内的元 素,获取china:city中,以110.00,30.00 经纬度位置为中 心,半径在1000 KM以内的所有元素,withdist是显示距 离,withcoord显示经纬度,count 限制数量
*georadiusbymember china:city beijing 1000 km #以该集合中指定成员为中心,其余一致
#区别:georadius适用于利用地图进行计算,georadiusbymember适用于好友之间的计算
*geohash china:city shanghai chongqing #将二维的经纬度,转化为11位的hash字符串
总结:geo的命令是基于zset实现的,我们可以同构zset的命令操作geo,例如删除元素
zrem china:city beijing #将北京从集合中移除
zrange china:city 0 -1 #查看地图中全部元素
2. hyperloglog (基数统计算法)
简介:
将不重复的数据进行统计,一般用于访问量,浏览量等统计数据的应用。占用内存非常小。效率高。是很好的统计值解决方案
官方提供的错误率是0.81% 适用于允许容错率的。统计2的64次方数据,只需要12KB的内存即可
pfadd k1 a b c d #在key1中存在值
pfcount k1 #统计key1中的不重复基数值
pfmerge k3 k1 k2... #将k1,k2...等值合并在k3中 并集
3. bitmaps (位图位运算)
简介:位图,都是曹邹二进制位来进行记录,只有0 1 两个状态,适用于记录实际业务中只有两个状态的场景,例如:打卡(打、未打)
*setbit sign 0 1 #设置sign的第0位 值为1 位数只能是数字,值只能是0/1
*getbit sign 2 #查询sign中第2位的值,结果返回 0/1
*bitcount sign #统计sign中为1 的所有值
应用:如果用户ID为整数,则可以通过
setbit 20200827 userid 1 的方式来记录该用户今日是否签到,是否登录,是否打卡等,从而通过后续API进行统计数据
bitmaps还支持位运算,与或非