Redis 是什么
Redis(Remote Dictionary Server,远程字典服务的缩写),是免费和开源的。是当下最热门的NoSQL技术之一,也被称为结构化数据库。
Redis能干嘛
- 内存存储,也可以持久化,内存中是断电即失,所以说持久化很有必要(rdb,aof)
- 效率高,可以用于高速缓存
- 发布订阅系统
- 地图信息分析
- 计时器,计数器等(比如浏览量,点赞数等)
- 提供多种语言api,使用方便。
特性
- 多样的数据类型
- 持久化
- 集群
- 事务
Redis推荐在linux上搭建,windows版本只能在git上下载,停更好久了。redis其实十分的小,下载到本地也就几兆。
windows的redis下载及安装:
- Github下载地址:https://github.com/MicrosoftArchive/redis/releases
- 百度网盘下载地址 https://pan.baidu.com/s/1z1_OdNVbtgyEjiktqgB83g 密码:kdfq
解压后放在你想放的位置,不考虑任何配置的话,其实这个时候就可以启动redis试一下了。
启动后可以看到redis的一些基本信息,比如redis版本,redis端口号(默认是6379)
在启动客户端后,可以直接使用了其实。我们可以再打开redis的客户端redis-cli。如下图,已经set/get好几次,并且如图get一个没有的key会获取不到。
如此,windows下简单的redis操作已经完成了。
至于持久化什么的,甚至端口的更改等,在redis的配置文件中有。
redis测试工具
在redis下载解压出来的文件中(不管是Linux还是windows版本都有的,我只用windows测试下)
redis-benchmark是一个压力测试工具,官方自带的性能测试工具,大概的命令参数如下:
这个参数是一定要加的,反正一开始我无脑直接启动这个测试工具,然后电脑卡死了,并且看好多同学都说电脑受不了。然后我简单的测试了下读和写的功能,截图如下:
如图所示,一百个并发,十万条数据(每条数据假装的三个字节。)读写都用了一秒多,set的话平均每秒8130,而get平均每秒84175(读的话和官网说的有点出入,官网说是每秒11w读,写的话和官网说的差不多)
Redis的基础知识
- Redis默认有16个数据库,默认使用后第0个。
!!!这里有个有趣的知识,sql写多了我一直以为select是查询的意思。但是其实不是的,select是选择的意思,redis中也用到了这个单词。刚刚都说了redis中有多个数据库,其实数据库之间的数据是不共享的。可以用select选择使用哪个数据库。如下图
顺便附上一个redis中的常用命令整理贴:
redis常用命令大全
Redis是单线程的
为什么redis是单线程的呢?因为redis是很快的,是基于内存操作的。所以cpu不是redis的性能瓶颈,redis的瓶颈是根据机器的内存和网络带宽的,所以单线程还是多线程没有区别,所以就用单线程了。
Redis是c语言写的,官方提供的数据是10万吞吐量,完全不比Memecache差。
为什么redis单线程还这么快?
其实这个是因为几个常识上的误区。
- 高性能的服务器一定是多线程的?
- 多线程(cpu上下文切换)一定比单线程效率高?
这个是不对的,其实cpu的切换是很慢的,多线程之间的线程调度就很浪费时间了。
读写效率确实是cpu>内存>硬盘。
但是因为redis是将所有的数据全部放在内存中,如果使用单线程不会产生线程调度(cpu上下文切换)的时间浪费,是效率最高的。对于内存系统来说,没有上下文切换效率最高。就因为redis 的多次读写都是在一个cpu上的,所以是最佳的方案。
Redis的五大数据类型
附上redis官网对redis的简介:
其实任何api接口提供的功能本身都是从redis原生命令衍生的。这句话其实挺好理解的,就跟mybatis plus 本身封装了一些基本的crud,这些虽然有了封装,但是本质上还是sql语句。redis也是这样。其实redis中的命令比较简单的,我也不一一记录了,一共也不多,建议大家自己挨个敲一遍试试。redis官网是有命令的。并且redis不区分大小写元素。
redis中,对string类型数据的一些操作
-
比如常见的判断长度,追加。
-
另外还有一个很人性化的操作:增加/减少(步长)。其实很多时候我们会用到数据统计的功能,比如阅读量,点赞数这些,都是递增的。比如秒杀的商品数是递减的。这些+1.-商品数量的操作,在redis中也是有现成命令的。如下图:
-
获取某个字符串类型value的一部分。这个和任何语言都差不多,第一个下标从0开始,截取的时候m,n。是从m到n的串。这个是闭区间的。其次替换某部分value的值也ok。
- 设置给定时限的key,和判断是否存在,不存在才赋值的操作。
这个setnx命令在分布式锁中经常用到。 -
redis其实也可以一次设置多个kv对。如下图。这里的重点就是mset操作是原子性的。
-
redis中还有比较有意思的就是组合命令。getset。如下图。
String类型的使用场景比较多。也是redis中最常用的数据类型。value除了可以是字符串,其实还可以是数字。比如之前说的incr/decr功能都很适合数值处理。
redis中,对list类型的使用
在redis里面,list其实也可以作为堆栈队列等。
redis命令中,所有对list的操作都用L表示。
-
list简单增加操作和查询操作。根据下标查询元素
-
list的移除操作和通过下标获取值。
- list的长度和移除指定的值(我现在是在公司写笔记呢,所以没截图。用文字记一遍吧。)
- list获取list长度: llen name.
- 移除list指定的元素:lrem name 2 i 这个命令是移除name中值是1的两个元素。重点是这个2是两个。i是元素的值。
- 通过下标截取list的一部分:ltrim name 1,2(这个也是一个闭区间,包括1,2)这个截取的过程中会改变list本身的值。所以截取和改变是同时发生的。
- list的组合操作
- 移除一个list的元素加入到另一个list中。 eg:rpoplpush pop的元素名称 push的元素名称。
判断是不是存在这个list exists name(返回0是没有,1是有)
-
list中lget/lset操作是将列表中指定下标的值替换成另外一个值。这个操作的前提是:
- 这个列表要存在
- 这个列表要有这个下标的元素。
往list列表 指定值前面插入元素。 linsert name before "i".同理也可以往某个元素后面插入。就是linsert name after "i"。
**list在redis中实际上是一个链表。没有节点的链表是不存在的。before/after node,left,right都可以插入值。如果key不存在,要有挂节点的操作(lpush)才能有这个链表。链表前后两端操作才是最快的,中间插入效率相对低一点。
这个list可以用作消息队列。
redis中,对set类型的使用
redis对set的操作都是s开头的。set中的元素是不能重复的!set是无序不重复集合。
- set基本的添加,查看操作
添加操作:sadd name "value1".sadd name "value2".sadd name "value3".(当添加重复的元素,会返回0,失败。)
查看整个set操作:smembers name
查看set中某个值是不是存在的:sismember name value1(返回1是存在,0是不存在) - 获取set中元素的个数:scard name (返回set中的元素的个数)
- 删除set中的指定元素: srem name value1
- 随机获取set中的一个元素: srandmember name
随机获取set中的多个元素: srandmember name 元素数 - 随机删除一个元素: spop name(随机弹出一个元素,就是删除了)
- 把set中的指定元素移动到另外一个元素中: smove name1 name2 "value1"
- 数字集合类操作:
- 差集(两个set中,不同的。以第一个set为主。就是第一个set中第二个set不存在的元素) sdiff key1 key2
- 交集(两个set中共同的,这个可以查看两个人的共同好友,共同关注之类的) sinter key1 key2
- 并集(两个set中所有的) sunion key1 key2
Hash
hash其实就是Map集合。建议大家理解为套娃。
所有hash的操作都是h开头的。本质和string没有什么区别。只不过是又变成了kv对。相当于多套了一层而已
- hash的存值和取值
存值:hset name key1 value1
取值:hget name key1
存多个值: hmset name key1 value1 key2 value2 key3 value3
取多个值: hmget name key1 key2 key3
获取hash中的全部kv对: hgetall name (展示形式是k v 一对一个的那种。奇数位是key 偶数位是value) - 删除hash指定的key hdel name key1(删除是成对删除的。删除key就可以)
- 获取当前hash中的kv对数: hlen name
- 判断指定hash中的key是不是存在: hexists name key1(0是不存在,1是存在)
- 只获取hash中的key或value:hkeys name(获取所有的key) hvalues name(获取所有的value)
- hash中的value也可以自增: hincrby name key1 1(这个key1对应的值要是数字才可以)
- hash也可以不存在则创建: hsetnx name key1 (0是操作失败,1是成功)
hash的应用:hash可以变更数据。比如用户信息的保存。只不过现在大多数人都是用json串存储的。但是想想json的话:取出,解析,更改,变成json,存储。但是如果是hash,则可以直接更改。
Zset(有序集合)
Zset其实就是在set基础上加了一个值。使得这个集合有序。zset的命令都是z开始的。
-
添加 Zadd myset 1 one(zadd是添加命令 myset是key 排序是1 one是元素值)
如下图(明明先插入的1,3,2但是查看的结果是1,2,3):
-
排序 其实刚刚就能看出来,默认排序就是从小到大,其实还可以属性的范围查询。如下(我想要小于等于2大于等于3的排序,所以结果只有two,three):
redis中对zset的操作更像是sql语句了。按照某个字段orderby然后分页。还可以带有序列(score)查询。
这个排序也可以从大到小(默认是从小到大)zrevrange myset 0 -1(0到-1是全部。如果想取前几条可以0-n)
- 移除zset中元素的操作。zset myset two
-
获取zset中元素的个数(这个大大区别于之前的几个类型,不是len)zcard myset
-
统计某个数值区间有几个值 zcount myset min max(在min和max之间有几个值。这个都是闭区间的)
zset的常用场景:zset是有序的set,所以其实set能做的zset都能做 。但是其排序也是很有必要的。比如工资排序,成绩表等。
还可以设置为带权重的一些数据:比如排行榜,一级消息二级消息等。
其实redis的命令主要还是自己去看官方文档慢慢熟悉。用的多了就会慢慢记住。官方文档才是一切的基础。
Geospatial(地理位置)
Redis的3.2以后就有了这个功能。这个功能可以推算地理位置的信息。比如两地之间的距离。方圆几里的人等,只有6个命令。可以去官网看看,如下图:
下面就一个个说geo的命令。redis中所有geo的命令都是geo开始的。
-
添加:geoadd name 经度 维度 成员名(这个可以添加多个,如下图)
其实这里手动一个个添加很少用。如果是用代码的话,java可以读取配置文件一次性导入的。另外经纬度是有限制的。这个反正也很少手动输入,不违背事实就行了。
-
获取地理位置:geopos name member(这个也可以获取多个,直接空格隔开就行)
-
获取两个给定位置之间的距离(这个可以指定单位,比如m米,km千米,ml英里,ft英尺。不指定的话默认是米)如果两个位置有一个不存在返回空值。 geodist name member1 member2 (m/km等)
-
获取某点方圆几里的人。一般是通过半径查询的。georadius name 经度 纬度 距离 距离单位 (可以选择带距离,可以选择带经纬度。还可以获取指定数量的人,在结果集中选择部分)
-
获取某元素周围指定距离的元素(上一个是任选一个点) georadiusbymember name member 半径 距离单位
如下图所示(我才发现我把上海录成了shenghai)
-
返回一个位置的经纬度,用hash表示(据说是最少用的,其实就是经纬度转化成一个11位字符串。字符串越长越精确。两个字符串长得越想说明两个地方越近。)。 如下图
geo就这六个命令,其实挺好记的,而且除了最后一个实用性都很强。geo底层的实现原理其实就是zset。我们其实可以用zset的命令操作geo的元素。是很有意思的一件事。而且geo本身是没有移除操作,但是zset中可以哟!附上一张有意思的图
Hyperloglog
这个是一个用于统计的数据变种。redis 2.8.9以上出现的。(统计出现误差是可以接受的)
使用场景:有时候一个网站,一个人访问多次,还是算作一个人,传统的做法是用set保存用户id,set不允许重复,可以统计set中元素数量判断。但是当数据量过大的话,会比较麻烦。而且我们的目的是用来计数而不是保存用户id,而Hyperloglog就很适合这个情景。
Hyperloglog优点:占用的内存是固定的,2的64次方的元素只需要12kb内存。
Hyperloglog缺点:官方说有0.81%的错误率。一般这个是可以接受的。
Hyperloglog命令以pf开始
这个一共就三个方法:
- 增加一个集合(自动去重):pfadd name value1 value2 ...valuen
- 查看一个集合的元素数(去重后的): pfcount name
- 将多个集合合并成一个(自动去重): pfmerge key(合并后的名字) key1 key2...
说一个比较有意思的事,这个hyperloglog底层是string。而且是一个很大的string。可以直接用get key查看哟!
Bitmap
这个是位存储。只有两个状态(登陆,未登录。打卡,未打卡等)都可以用Bitmap来实现。ps:可以用Bitmap,不是必须用。别的方式也能很好实现。而且需求要明确。如果还要统计某天共有多少人登陆就不能这样了。
方法主要就三个:
- 添加记录:setbit name member 0/1
- 查询记录:getbit name member
-
统计某个key的打卡天数: bitcount name
至此,Redis是什么,能干嘛,特性和五大基本数据类型,3个变种数据类型都讲完了,这篇文章就到此结束啦~!如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利!另外java技术交流群130031711,欢迎各位加入!