Redis 目录 NoSQL讲解 阿里巴巴架构演进 NoSQL数据模型 NoSQL四大类 CAP BASE Redis入门 Redis安装 五大基本数据类型 三种特殊数据类型 Redis配置详解 Redis持久化 Redis事务操作 Redis实现订阅发布 Redis主从复制 Redis哨兵模式 缓存穿透及解决方案 缓存击穿及解决方案 缓存雪崩及解决方案 基础API之Jedis详解 SpringBoot集成Redis操作 Redis的实践分析 NoSQL概述 为什么要用NoSQL 1.单机Mysql的年代
90年代,一个基本的网站访问量一般不会太大,单个数据库完全够用!
那个时候,更多的使用静态网页(HTML)——–服务器根本没有太大的压力!
思考一下:这种情况下:整个网站的瓶颈是什么?
数据量如果太大,一个机器放不下了! 数据的索引(B+Tree),一个机器内存也放不下! 访问量(读写混合),一个服务器承受不了! 只要你出现以上的三种情况之一,那么你就必须要晋级!
2.Memcached(缓存)+MySQL+垂直拆分(读写分离) 网站80%的情况都是在读,每次都要去查询数据库的话就十分的麻烦!所以说我们希望减轻数据的压力,我们可以使用缓存来保证效率!
发展过程:优化数据结构和索引–>文件缓存(IO)–>Memcached(当时最热门的技术!)
3.分库分表+水平拆分+MySQL集群 技术和业务在发展的同时对人的要求也越来越高
本质:数据库(读,写)
早些年MyISAM:表锁,十分影响效率!高并发下就会出现严重的锁问题
早些年Innodb:行锁
慢慢的就开始使用分库分表来解决写的压力!MySQL在那个年代推出了表分区!这个并没有多少公司使用!
MySQL的集群,很好的满足了那个年代的所有需求!
4.如今最近的年代 2010–2020 十年之间,世界已经发生了翻天覆地的变化;(定位,也是一种数据,音乐,热榜!)
MySQL等关系型数据库就不够用了!数据量很多,变化很快!
MySQL有的使用它来存储一些比较大的文件,博客,图片!数据库表很大,效率就很低了!如果有一种数据库来专门处理这种数据,MySQL的压力就变得十分小(研究如何处理这些问题!)大数据的IO压力下,表几乎没法更大!
5.目前一个基本的互联网项目!
6.为什么要用NoSQL! 用户的个人信息,社交网络,地理位置,用户自己产生的数据,用户的日志等等爆发式的增长!
这时候我们就需要使用NoSQL数据库,NoSQL可以很好的处理以上的情况!
什么是NoSQL 1.NoSQL NoSQL=Not Only SQL(不仅仅是SQL)
关系型数据库:表格,行,列
泛指非关系型数据库,随着Web2.0互联网的诞生!传统的关系型数据库很难对付!尤其是超大规模的高并发的社区!暴露出来很多的难以克服的问题,NoSQL在当今大数据环境下发展的十分迅速,Redis是发展最快的,而且是我们当下必须要掌握的一个技术!
很多的数据类型用户的个人信息,社交网络,地理位置。这些数据类型的存储不需要一个固定的格式!不需要多月的操作就可以横向扩展的! Map<String,Object>使用键值对来控制!
2.NoSQL特点 解耦!
方便扩展(数据之间没有关系,很好扩展!) 大数据量高性能(Redis一秒写8万次,读取11万次,NoSQL的缓存记录级,是一种细粒度的缓存,性能会比较高!) 数据类型是多样的!(不需要事先设计数据库!随取随用!如果是数据量十分大的表,很多人就无法设计了!) 传统的RDBMS和NoSQL 1 2 3 4 5 6 7 8 传统的RDBMS - 结构化组织 - SQL - 数据和关系都存在单独的表中 - 操作语言,数据定义语言 - 严格的一致性 - 基础的事务操作 - ...
1 2 3 4 5 6 7 8 NoSQL - 不仅仅是数据 - 没有固定的查询语言 - 键值对存储,列存储,文档存储,图形数据库(社交关系) - 最终一致性 - CAP定理和BASE(异地多活) - 高性能,高可用,高可扩 - ...
3.了解:3V+3高 大数据时代的3V:主要是描述问题的
海量Velume 多样Variety 实时Velocity 大数据时代的3高:主要是对程序的要求
高并发 高可扩 高性能 真正在公司中的实践:NoSQL+RDBMS一起使用才是最强的,阿里巴巴架构的演进!
阿里巴巴架构的演进
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # 商品信息 - 一般存放在关系型数据库:Mysql,阿里巴巴使用的Mysql都是经过内部改动的。 # 商品描述、评论(文字居多) - 文档型数据库:MongoDB # 图片 - 分布式文件系统 FastDFS - 淘宝:TFS - Google: GFS - Hadoop: HDFS - 阿里云: oss # 商品关键字 用于搜索 - 搜索引擎:solr,elasticsearch - 阿里:Isearch 多隆 # 商品热门的波段信息 - 内存数据库:Redis,Memcache # 商品交易,外部支付接口 - 第三方应用
NoSQL的四大分类 1.kv键值对: 新浪:Redis 美团:Redis+Tair 阿里、百度:Redis+memecache 2.文档型数据库(bson格式和json一样): MongDB(一般必须掌握)MongoDB是一个基于分布式文件存储的数据库,C++编写,主要用来处理大量的文档! MongoDB是一个介于关系型数据库和非关系型数据库中间的产品!MongoDB是非关系型数据库中功能最丰富,最像关系型数据库的! ConthDB 3.列存储数据库 4.图关系数据库
他不是存放图形,放的是关系,比如:朋友圈社交网络,广告推荐! Neo4j,InfoGrid 四者对比! 分类 Examples举例 典型应用场景 数据模型 优点 缺点 键值对(key-value) Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB 内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等。 Key 指向 Value 的键值对,通常用hash table来实现 查找速度快 数据无结构化,通常只被当作字符串或者二进制数据 列存储数据库 Cassandra, HBase, Riak 分布式的文件系统 以列簇式存储,将同一列数据存在一起 查找速度快,可扩展性强,更容易进行分布式扩展 功能相对局限 文档型数据库 CouchDB, MongoDb Web应用(与Key-Value类似,Value是结构化的,不同的是数据库能够了解Value的内容) Key-Value对应的键值对,Value为结构化数据 数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构 查询性能不高,而且缺乏统一的查询语法。 图形(Graph)数据库 Neo4J, InfoGrid, Infinite Graph 社交网络,推荐系统等。专注于构建关系图谱 图结构 利用图结构相关算法。比如最短路径寻址,N度关系查找等 很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群
Redis入门 概述 1.Redis是什么? Redis(Remote Dictionary Server ),即远程字典服务。
是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
2.Redis能该干什么? 内存存储、持久化,内存是断电即失的,所以需要持久化(RDB、AOF) 高效率、用于高速缓冲 发布订阅系统 地图信息分析 计时器、计数器(eg:浏览量) …… 3.特性 多样的数据类型
持久化
集群
事务
…
4.环境搭建 官网:https://redis.io/
推荐使用Linux服务器学习。
windows版本的Redis已经停更很久了…
Windows安装 1.下载安装包 https://github.com/dmajkic/redis
2.下载后解压的目录
3.开启Redis,双击redis-server.exe
4.启动redis-cli.exe测试
Linux安装 本文中Linux系统是ubuntu18,redis是5.0.7版本
1.下载redis安装包 2. 解压redis安装包 一般放在opt目录下 1 tar -zxvf redis-5.0.7.tar.gz //解压redis后可见,redis-5.0.7文件
3.进入解压后的文件,可以看到redis的配置文件
4.基本环境安装 1 2 3 4 5 sudo apt-get install gcc sudo apt-get install g++ gcc --version //查看是否安装成功及安装版本 g++ --version sudo make //加载所需环境,会多出src文件
如果是第一次安装,make命令会执行比较久,耐心等待,成功后会多出一个src文件
5.redis默认安装路径”/usr/local/bin”
6.将redis配置文件复制到当前目录下,之后用这个配置文件进行启动 1 cp /opt/redis-5.0.7/redis.conf
7.redis默认不是后台启动的,修改配置文件redis.conf
8.通过指定的配置文件启动redis服务 1 redis-server my-config/redis.conf
9.使用redis-cli进行连接并测试
10.到此redis在Linux下安装结束并测试已连通 测试性能 redis-benchmark 是一个压力测试工具!
官方自带的性能测试工具!
redis-benchmark命令参数:
简单测试:
1 2 测试:100 个并发请求 100000 请求 redis-benchmark -h localhost -p 6379 -c 100 -n 100000
1 2 3 4 10 万个请求进行写入测试100 个并发客户端每次写入三个字节 只有一台服务器来处理这些请求,单机性能
基础的知识 Redis默认有16个数据库
默认使用第0个
可以使用select进行切换数据库!
1 2 3 4 5 6 [root@hadoop redis-2.8 .19 ]# redis-cli 127.0 .0 .1 :6379 > select 3 OK 127.0 .0 .1 :6379 [3 ]> dbsize (integer) 0 127.0 .0 .1 :6379 [3 ]>
1 2 127.0 .0 .1 :6379 [3 ]> keys * 1 ) "name"
清空当前数据库 flushdb
清空全部数据库内容 flushall
1 2 3 4 5 127.0 .0 .1 :6379 [3 ]> flushdbOK 127.0 .0 .1 :6379 [3 ]> keys *(empty list or set) 127.0 .0 .1 :6379 [3 ]>
思考:为什么redis是6379!(了解)
Redis是单线程的!
明白Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了!所以就使用单线程了!
Redis是C语言写的,官方提供的数据为100000+的QPS,完全不比同样是使用key-value的Memecache差!
Redis为什么单线程还这么快?
1.误区1:高性能的服务器一定是多线程的?
2.误区2:多线程(CPU上下文会切换!)一定比单线程效率高!
先去CPU->内存->硬盘的速度要有所了解!
核心:Redist是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗时的操作!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这个就是最佳方案!
五大数据类型 官网文档
Redis 是一种开源(BSD 许可)的内存数据结构存储 ,用作数据库、缓存、消息代理和流式处理引擎。Redis 提供数据结构 ,例如字符串 、哈希 、列表 、集、带有范围查询的排序集 、位图 、超日志 、地理空间索引 和流 。 Redis 具有内置复制、Lua 脚本 、LRU 逐出 、事务 和不同级别的磁盘持久性 ,并通过 Redis Sentinel 和 Redis 集群 的自动分区提供高可用性。
您可以对这些类型运行原子操作 ,例如附加到字符串 ;递增哈希值 ;将元素推送到 列表 ;计算集合交 集、并 集和差分 集; 或获取排序集中排名最高的成员 。
为了实现最佳性能,Redis 使用内存中数据集 。根据您的使用案例,Redis 可以保留您的数据 通过定期将数据集转储 到磁盘或将每个命令追加到基于磁盘的日志中 。如果您只需要一个功能丰富的网络内存中缓存,也可以禁用持久性。
Redis 支持异步复制 ,具有快速无阻塞同步和自动重连,并在网络拆分时进行部分重新同步。
Redis 还包括:
您可以使用大多数编程语言 的 Redis。
Redis 是用 ANSI C 编写的,适用于大多数 POSIX 系统,如 Linux, BSD 和 Mac OS X,没有外部依赖。Linux 和 OS X 是开发和测试 Redis 最多的两个操作系统,我们建议使用 Linux 进行部署 。Redis 可以在 Solaris 派生的系统(如 SmartOS)中工作,但支持是 最大的努力*。 没有对 Windows 版本的官方支持。
所有命令用于SpringBoot,Jedis的学习
Redis-Key
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 127.0 .0 .1 :6379 > keys * (empty array) 127.0 .0 .1 :6379 > set name liuyunxuan OK 127.0 .0 .1 :6379 > keys *1 ) "name" 127.0 .0 .1 :6379 > set age 1 OK 127.0 .0 .1 :6379 > keys *1 ) "age" 2 ) "name" 127.0 .0 .1 :6379 > EXISTS name (integer) 1 127.0 .0 .1 :6379 > EXISTS name1 (integer) 0 127.0 .0 .1 :6379 > move name 1 (integer) 1 127.0 .0 .1 :6379 > keys *1 ) "age" 127.0 .0 .1 :6379 > set name liuyunxuanOK 127.0 .0 .1 :6379 > keys *1 ) "name" 2 ) "age" 127.0 .0 .1 :6379 > get name"liuyunxuan" 127.0 .0 .1 :6379 > EXPIRE name 10 (integer) 1 127.0 .0 .1 :6379 > ttl name (integer) 2 127.0 .0 .1 :6379 > ttl name (integer) -2 127.0 .0 .1 :6379 > get name (nil) 127.0 .0 .1 :6379 > 127.0 .0 .1 :6379 > type name string 127.0 .0 .1 :6379 > type agestring
不会的命令可以去官网查
String(字符串) 90%的程序员使用Redis只会使用一个String类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 127.0 .0 .1 :6379 > set key1 v1 OK 127.0 .0 .1 :6379 > get key1 "v1" 127.0 .0 .1 :6379 > keys * 1 ) "key1" 127.0 .0 .1 :6379 > EXISTS key1 (integer) 1 127.0 .0 .1 :6379 > APPEND key1 "hello" (integer) 7 127.0 .0 .1 :6379 > get key1"v1hello" 127.0 .0 .1 :6379 > STRLEN key1 (integer) 7 127.0 .0 .1 :6379 > APPEND key1 ",liuyunxuan" (integer) 18 127.0 .0 .1 :6379 > STRLEN key1 (integer) 18 127.0 .0 .1 :6379 > get key1"v1hello,liuyunxuan"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 127.0 .0 .1 :6379 > set views 0 OK 127.0 .0 .1 :6379 > get views"0" 127.0 .0 .1 :6379 > incr views (integer) 1 127.0 .0 .1 :6379 > incr views (integer) 2 127.0 .0 .1 :6379 > get views"2" 127.0 .0 .1 :6379 > decr views (integer) 1 127.0 .0 .1 :6379 > decr views (integer) 0 127.0 .0 .1 :6379 > decr views (integer) -1 127.0 .0 .1 :6379 > get views"-1" 127.0 .0 .1 :6379 > INCRBY views 10 (integer) 9 127.0 .0 .1 :6379 > DECRBY views 10 (integer) -1 127.0 .0 .1 :6379 >
1 2 3 4 5 6 7 8 127.0 .0 .1 :6379 > set key1 "hello,liuyunxuan" OK 127.0 .0 .1 :6379 > get key1"hello,liuyunxuan" 127.0 .0 .1 :6379 > GETRANGE key1 0 3 "hell" 127.0 .0 .1 :6379 > GETRANGE key1 0 -1 "hello,liuyunxuan"
1 2 3 4 5 6 7 8 9 127.0 .0 .1 :6379 > set key2 abcdefgOK 127.0 .0 .1 :6379 > get key2"abcdefg" 127.0 .0 .1 :6379 > SETRANGE key2 1 xx (integer) 7 127.0 .0 .1 :6379 > get key2"axxdefg"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 127.0 .0 .1 :6379 > setex key3 30 "hello" OK 127.0 .0 .1 :6379 > ttl key3 (integer) 22 127.0 .0 .1 :6379 > ttl key3 (integer) 21 127.0 .0 .1 :6379 > ttl key3 (integer) 19 127.0 .0 .1 :6379 > setnx mykey "redis" (integer) 1 127.0 .0 .1 :6379 > keys *1 ) "mykey" 2 ) "key1" 3 ) "key2" 127.0 .0 .1 :6379 > ttl key3 (integer) -2 127.0 .0 .1 :6379 > setnx mykey "MongoDB" (integer) 0 127.0 .0 .1 :6379 > get mykey"redis"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 127.0 .0 .1 :6379 > mset k1 v1 k2 v2 k3 v3 OK 127.0 .0 .1 :6379 > keys *1 ) "k3" 2 ) "k2" 3 ) "k1" 127.0 .0 .1 :6379 > mget k1 k2 k3 1 ) "v1" 2 ) "v2" 3 ) "v3" 127.0 .0 .1 :6379 > msetnx k1 v1 k4 v4 (integer) 0 127.0 .0 .1 :6379 > get k4 (nil)
1 2 3 4 5 6 7 8 set user:1 {name:zhangsan,age:3 } 127.0 .0 .1 :6379 > mset user:1 :name zhangsan user:1 :age 2 OK 127.0 .0 .1 :6379 > mget user:1 :name user:1 :age1 ) "zhangsan" 2 ) "2"
1 2 3 4 5 6 7 8 9 10 getset 127.0 .0 .1 :6379 > getset db redis (nil) 127.0 .0 .1 :6379 > get db"redis" 127.0 .0 .1 :6379 > getset db mongodb "redis" 127.0 .0 .1 :6379 > get db"mongodb" 127.0 .0 .1 :6379 >
数据结构是相同的!
String类型的使用场景:value除了是我们的字符串还可以是我们的数字!
List(列表) 基本的数据类型,列表
在Redis中我们可以把list玩成栈,队列,阻塞队列!
所有list命令都是以l开头的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 127.0 .0 .1 :6379 > LPUSH list one (integer) 1 127.0 .0 .1 :6379 > LPUSH list two (integer) 2 127.0 .0 .1 :6379 > LPUSH list three (integer) 3 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "three" 2 ) "two" 3 ) "one" 127.0 .0 .1 :6379 > LRANGE list 0 1 1 ) "three" 2 ) "two" 127.0 .0 .1 :6379 > RPUSH list righr (integer) 4 127.0 .0 .1 :6379 > LRANGE list 0 1 1 ) "three" 2 ) "two" 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "three" 2 ) "two" 3 ) "one" 4 ) "righr"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 LPOP RPOP 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "three" 2 ) "two" 3 ) "one" 4 ) "righr" 127.0 .0 .1 :6379 > LPOP list "three" 127.0 .0 .1 :6379 > RPOP list "righr" 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "two" 2 ) "one" 127.0 .0 .1 :6379 >
1 2 3 4 5 6 7 8 Lindex 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "two" 2 ) "one" 127.0 .0 .1 :6379 > lindex list 1 "one" 127.0 .0 .1 :6379 > lindex list 0 "two"
1 2 3 4 5 6 7 8 9 Llen 127.0 .0 .1 :6379 > LPUSH list one (integer) 1 127.0 .0 .1 :6379 > LPUSH list two (integer) 2 127.0 .0 .1 :6379 > LPUSH list three (integer) 3 127.0 .0 .1 :6379 > LLEN list (integer) 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 移除指定的值! 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "three" 2 ) "three" 3 ) "two" 4 ) "one" 127.0 .0 .1 :6379 > lrem list 1 one (integer) 1 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "three" 2 ) "three" 3 ) "two" 127.0 .0 .1 :6379 > lrem list 1 three(integer) 1 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "three" 2 ) "two" 127.0 .0 .1 :6379 > LPUSH list three (integer) 3 127.0 .0 .1 :6379 > lrem list 2 three(integer) 2 127.0 .0 .1 :6379 > LRANGE list 0 -1 1 ) "two"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 trim 修剪 ; list 截断 127.0 .0 .1 :6379 > keys *(empty array) 127.0 .0 .1 :6379 > RPUSH mylist "hello" (integer) 1 127.0 .0 .1 :6379 > RPUSH mylist "hello1" (integer) 2 127.0 .0 .1 :6379 > RPUSH mylist "hello2" (integer) 3 127.0 .0 .1 :6379 > RPUSH mylist "hello3" (integer) 4 127.0 .0 .1 :6379 > ltrim mylist 1 2 OK 127.0 .0 .1 :6379 > LRANGE mylist 0 -1 1 ) "hello1" 2 ) "hello2"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 rpoplpush 127.0 .0 .1 :6379 > rpush mylist "hello" (integer) 1 127.0 .0 .1 :6379 > rpush mylist "hello1" (integer) 2 127.0 .0 .1 :6379 > rpush mylist "hello2" (integer) 3 127.0 .0 .1 :6379 > rpoplpush mylist myotherlist "hello2" 127.0 .0 .1 :6379 > lrange mylist 0 -1 1 ) "hello" 2 ) "hello1" 127.0 .0 .1 :6379 > lrange myotherlist 0 -1 1 ) "hello2"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 lset 127.0 .0 .1 :6379 > EXISTS list (integer) 0 127.0 .0 .1 :6379 > lset list 0 item (error) ERR no such key 127.0 .0 .1 :6379 > lpush list value1 (integer) 1 127.0 .0 .1 :6379 > lrange list 0 0 1 ) "value1" 127.0 .0 .1 :6379 > lset list 0 item OK 127.0 .0 .1 :6379 > lrange list 0 0 1 ) "item" 127.0 .0 .1 :6379 > lset list 1 other (error) ERR index out of range
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 linsert 127.0 .0 .1 :6379 > rpush mylist "hello" (integer) 1 127.0 .0 .1 :6379 > rpush mylist "world" (integer) 2 127.0 .0 .1 :6379 > linsert mylist before "world" "other" (integer) 3 127.0 .0 .1 :6379 > LRANGE mylist 0 -1 1 ) "hello" 2 ) "other" 3 ) "world" 127.0 .0 .1 :6379 > linsert mylist after "world" "new" (integer) 4 127.0 .0 .1 :6379 > LRANGE mylist 0 -1 1 ) "hello" 2 ) "other" 3 ) "world" 4 ) "new"
小结
他实际上是一个链表,before Node after 。left,right都可以插入值 如果key不存在,创建新的链表 如果key存在,新增内容 如果移除了所有值,空链表,也代表不存在! 在两边插入或者改动值,效率最高!中间元素,相对来说效率会低一点! 消息排队! 消息队列!(Lpush, Rpop),栈(Lpush,Lpop)!
Set(集合) set中的值不能重复的!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 127.0 .0 .1 :6379 > sadd myset "hello" (integer) 1 127.0 .0 .1 :6379 > sadd myset "world" (integer) 1 127.0 .0 .1 :6379 > sadd myset "china" (integer) 1 127.0 .0 .1 :6379 > SMEMBERS myset 1 ) "hello" 2 ) "world" 3 ) "china" 127.0 .0 .1 :6379 > SISMEMBER myset hello (integer) 1 127.0 .0 .1 :6379 > SISMEMBER myset nihao (integer) 0
1 2 127.0 .0 .1 :6379 > SCARD myset (integer) 3
1 2 3 4 5 6 7 8 9 127.0 .0 .1 :6379 > srem myset hello (integer) 1 127.0 .0 .1 :6379 > SCARD myset (integer) 2 127.0 .0 .1 :6379 > SISMEMBER myset (error) ERR wrong number of arguments for 'sismember' command127.0 .0 .1 :6379 > SMEMBERS myset1 ) "world" 2 ) "china"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 set 无序不重复集合,随机抽取! 127.0 .0 .1 :6379 > SRANDMEMBER myset"china" 127.0 .0 .1 :6379 > SRANDMEMBER myset"china" 127.0 .0 .1 :6379 > SRANDMEMBER myset"china" 127.0 .0 .1 :6379 > SRANDMEMBER myset"world" 127.0 .0 .1 :6379 > SRANDMEMBER myset "china" 127.0 .0 .1 :6379 > SRANDMEMBER myset 2 1 ) "world" 2 ) "china"
1 2 3 4 5 6 7 8 删除指定的key,随机删除key! 127.0 .0 .1 :6379 > SMEMBERS myset1 ) "world" 2 ) "china" 127.0 .0 .1 :6379 > spop myset "world" 127.0 .0 .1 :6379 > SMEMBERS myset1 ) "china"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 将一个指定的值,移动到另外一个set集合! 127.0 .0 .1 :6379 > sadd myset hello (integer) 1 127.0 .0 .1 :6379 > sadd myset world (integer) 1 127.0 .0 .1 :6379 > sadd myset china (integer) 1 127.0 .0 .1 :6379 > sadd myset2 set2 (integer) 1 127.0 .0 .1 :6379 > smove myset myset2 china (integer) 1 127.0 .0 .1 :6379 > SMEMBERS myset1 ) "hello" 2 ) "world" 127.0 .0 .1 :6379 > SMEMBERS myset21 ) "set2" 2 ) "china"
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 数字集合类: -差集 -交集 -并集 127.0 .0 .1 :6379 > sadd key1 a (integer) 1 127.0 .0 .1 :6379 > sadd key1 b (integer) 1 127.0 .0 .1 :6379 > sadd key1 c (integer) 1 127.0 .0 .1 :6379 > sadd key2 c (integer) 1 127.0 .0 .1 :6379 > sadd key2 d (integer) 1 127.0 .0 .1 :6379 > sadd key2 e (integer) 1 127.0 .0 .1 :6379 > SDIFF key1 key2 1 ) "a" 2 ) "b" 127.0 .0 .1 :6379 > SINTER key1 key2 1 ) "c" 127.0 .0 .1 :6379 > SUNION key1 key2 1 ) "a" 2 ) "b" 3 ) "c" 4 ) "d" 5 ) "e"
微博。A用户将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!
共同关注,共同爱好,二度好友,推荐好友!(六度分割理论)
Hash(哈希) Map集合,key-<key,map>! 的时候 这个值是一个map集合! 本质和String类型没有太大区别,还是一个简单的key-value!
set myhash field liuyunxuan
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 127.0 .0 .1 :6379 > hset myhash field1 liuyunxuan (integer) 1 127.0 .0 .1 :6379 > hget myhash field1 "liuyunxuan" 127.0 .0 .1 :6379 > hmset myhash field1 hello field2 world OK 127.0 .0 .1 :6379 > hmget myhash field1 field2 1 ) "hello" 2 ) "world" 127.0 .0 .1 :6379 > hgetall myhash 1 ) "field1" 2 ) "hello" 3 ) "field2" 4 ) "world" 127.0 .0 .1 :6379 > 127.0 .0 .1 :6379 > clear127.0 .0 .1 :6379 > hgetall myhash1 ) "field1" 2 ) "hello" 3 ) "field2" 4 ) "world" 127.0 .0 .1 :6379 > hdel myhash field1 (integer) 1 127.0 .0 .1 :6379 > hgetall myhash1 ) "field2" 2 ) "world"
1 2 3 4 5 6 7 8 9 10 11 12 hlen 127.0 .0 .1 :6379 > hmset myhash filed1 hello filed2 worldOK 127.0 .0 .1 :6379 > HGETALL myhash1 ) "field2" 2 ) "world" 3 ) "filed1" 4 ) "hello" 5 ) "filed2" 6 ) "world" 127.0 .0 .1 :6379 > hlen myhash (integer) 3
1 2 3 4 5 6 127.0 .0 .1 :6379 > HEXISTS myhash field1 (integer) 0 127.0 .0 .1 :6379 > HEXISTS myhash field3 (integer) 0 127.0 .0 .1 :6379 > HEXISTS myhash filed1 (integer) 1
1 2 3 4 5 6 7 8 9 10 127.0 .0 .1 :6379 > hkeys myhash 1 ) "field2" 2 ) "filed1" 3 ) "filed2" 127.0 .0 .1 :6379 > hvals myhash 1 ) "world" 2 ) "hello" 3 ) "world"
1 2 3 4 5 6 7 8 9 10 11 incr decr 127.0 .0 .1 :6379 > hset myhash filed3 5 (integer) 1 127.0 .0 .1 :6379 > HINCRBY myhash filed3 1 (integer) 6 127.0 .0 .1 :6379 > HINCRBY myhash filed3 -1 (integer) 5 127.0 .0 .1 :6379 > hsetnx myhash filed4 hello (integer) 1 127.0 .0 .1 :6379 > hsetnx myhash filed4 world (integer) 0
hash可以存一些变更的数据 user name age ,尤其是用户信息之类的,经常变动的信息!hash更适合对象的存储,String更适合字符串的存储!
Zset(有序集合) 在set的基础上,增加了一个值,set k1 v1 zset k1 score v1
1 2 3 4 5 6 7 8 127.0 .0 .1 :6379 > zadd myset 1 one (integer) 1 127.0 .0 .1 :6379 > zadd myset 2 two 3 three (integer) 2 127.0 .0 .1 :6379 > ZRANGE myset 0 -1 1 ) "one" 2 ) "two" 3 ) "three"
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 排序如何实现 127.0 .0 .1 :6379 > zadd salary 2500 xiaohong (integer) 1 127.0 .0 .1 :6379 > zadd salary 5000 zhangsan(integer) 1 127.0 .0 .1 :6379 > zadd salary 500 lisi(integer) 1 127.0 .0 .1 :6379 > zrangebyscore salary -inf +inf 1 ) "lisi" 2 ) "xiaohong" 3 ) "zhangsan" 127.0 .0 .1 :6379 > zrangebyscore salary -inf +inf withscores 1 ) "lisi" 2 ) "500" 3 ) "xiaohong" 4 ) "2500" 5 ) "zhangsan" 6 ) "5000" 127.0 .0 .1 :6379 > zrangebyscore salary -inf 2500 withscores 1 ) "lisi" 2 ) "500" 3 ) "xiaohong" 4 ) "2500" 127.0 .0 .1 :6379 > ZREVRANGE salary 0 -1 1 ) "zhangsan" 2 ) "lisi"
1 2 3 4 5 6 7 8 9 10 11 12 127.0 .0 .1 :6379 > zrange salary 0 -1 1 ) "lisi" 2 ) "xiaohong" 3 ) "zhangsan" 127.0 .0 .1 :6379 > zrem salary xiaohong (integer) 1 127.0 .0 .1 :6379 > zrange salary 0 -1 1 ) "lisi" 2 ) "zhangsan" 127.0 .0 .1 :6379 > zcard salary (integer) 2
1 2 3 4 5 6 7 8 127.0 .0 .1 :6379 > zadd myset 1 hello(integer) 1 127.0 .0 .1 :6379 > zadd myset 2 world 3 liuyunxuan(integer) 2 127.0 .0 .1 :6379 > zcount myset 1 3 (integer) 3 127.0 .0 .1 :6379 > zcount myset 1 2 (integer) 2
其余的一些API,可以去官网查看。
案例思路:set 排序 存储班级成绩表,工资表排序!
普通消息,1.重要消息 2.带权重进行判断!
排行榜应用实现
三种特殊数据类型 geospatial(地理位置) 朋友的定位,附近的人,打车距离计算!
Redis的GEO在3.2版本就推出了!
geoadd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 127.0 .0 .1 :6379 > geoadd china:city 34.26 108.96 xian(error) ERR invalid longitude,latitude pair 34.260000 ,108.960000 127.0 .0 .1 :6379 > geoadd china:city 116.41 39.91 beijing(integer) 1 127.0 .0 .1 :6379 > geoadd china:city 121.48 31.40 shanghai(integer) 1 127.0 .0 .1 :6379 > geoadd china:city 106.54 29.40 chongqing(integer) 1 127.0 .0 .1 :6379 > geoadd china:city 113.88 22.55 shenzhen(integer) 1 127.0 .0 .1 :6379 > geoadd china:city 120.16 30.24 hangzhou(integer) 1 127.0 .0 .1 :6379 > geoadd china:city 108.96 34.26 xian(integer) 1
geopos
获取当前定位:一定是一个坐标值
1 2 3 4 5 6 7 8 127.0 .0 .1 :6379 > geopos china:city beijing 1 ) 1 ) "116.40999823808670044" 2 ) "39.90999956664450821" 127.0 .0 .1 :6379 > geopos china:city beijing chongqing1 ) 1 ) "116.40999823808670044" 2 ) "39.90999956664450821" 2 ) 1 ) "106.54000014066696167" 2 ) "29.39999880018641676"
geodist
两人之间的距离
m for 米.km for 千米.mi for 英里.ft for 英尺.1 2 3 4 127.0 .0 .1 :6379 > geodist china:city beijing shanghai km "1051.1201" 127.0 .0 .1 :6379 > geodist china:city beijing chongqing km "1475.0562"
georadius
我附近的人?(获得所有附近的人的地址,定位!)通过半径来查询!
获取指定数量的人,200.
所有的数据都应该录入:china:city。才会让结果更加精确
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 40 41 42 43 127.0 .0 .1 :6379 > GEORADIUS china:city 110 30 1000 km 1 ) "chongqing" 2 ) "xian" 3 ) "shenzhen" 4 ) "hangzhou" 127.0 .0 .1 :6379 > GEORADIUS china:city 110 30 500 km1 ) "chongqing" 2 ) "xian" 127.0 .0 .1 :6379 > GEORADIUS china:city 110 30 500 km withdist 1 ) 1 ) "chongqing" 2 ) "340.8679" 2 ) 1 ) "xian" 2 ) "483.8340" 127.0 .0 .1 :6379 > GEORADIUS china:city 110 30 500 km withcoord 1 ) 1 ) "chongqing" 2 ) 1 ) "106.54000014066696167" 2 ) "29.39999880018641676" 2 ) 1 ) "xian" 2 ) 1 ) "108.96000176668167114" 2 ) "34.25999964418929977" 127.0 .0 .1 :6379 > GEORADIUS china:city 110 30 500 km withdist withcoord count 1 1 ) 1 ) "chongqing" 2 ) "340.8679" 3 ) 1 ) "106.54000014066696167" 2 ) "29.39999880018641676" 127.0 .0 .1 :6379 > GEORADIUS china:city 110 30 500 km withdist withcoord count 2 1 ) 1 ) "chongqing" 2 ) "340.8679" 3 ) 1 ) "106.54000014066696167" 2 ) "29.39999880018641676" 2 ) 1 ) "xian" 2 ) "483.8340" 3 ) 1 ) "108.96000176668167114" 2 ) "34.25999964418929977" 127.0 .0 .1 :6379 > GEORADIUS china:city 110 30 500 km withdist withcoord count 3 1 ) 1 ) "chongqing" 2 ) "340.8679" 3 ) 1 ) "106.54000014066696167" 2 ) "29.39999880018641676" 2 ) 1 ) "xian" 2 ) "483.8340" 3 ) 1 ) "108.96000176668167114" 2 ) "34.25999964418929977"
georadiusbymember
1 2 3 4 5 6 7 127.0 .0 .1 :6379 > GEORADIUSBYMEMBER china:city beijing 1000 km1 ) "beijing" 2 ) "xian" 127.0 .0 .1 :6379 > GEORADIUSBYMEMBER china:city shanghai 400 km1 ) "hangzhou" 2 ) "shanghai"
geohash
该命令将返回11个字符的Geohash字符串!
1 2 3 4 127.0 .0 .1 :6379 > geohash china:city beijing chongqing1 ) "wx4g0crhte0" 2 ) "wm5z22h53v0"
GEO底层的实现原理其实就是Zset!我们可以使用Zset命令来操作geo!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 127.0 .0 .1 :6379 > ZRANGE china:city 0 -1 1 ) "chongqing" 2 ) "xian" 3 ) "shenzhen" 4 ) "hangzhou" 5 ) "shanghai" 6 ) "beijing" 127.0 .0 .1 :6379 > ZREM china:city beijing (integer) 1 127.0 .0 .1 :6379 > ZRANGE china:city 0 -1 1 ) "chongqing" 2 ) "xian" 3 ) "shenzhen" 4 ) "hangzhou" 5 ) "shanghai"
hyperloglog 什么是基数?
A {1.3.5.7.8.7}
B {1.3.5.7.8}
基数(不重复的元素),可以接受误差!
简介
Redis2.8.9版本就更新了Hyperloglog数据结构!
Redis Hyperloglog 基数统计的算法!
优点:占用的内存是固定的,2^64不同的元素的技术,只需要废12KB内存!如果要从内存角度来比较的话Hyperloglog首选!
网页的UV(一个人访问一个网站多次,但是还是算作一个人)
传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断!
这个方式如果保存大量的用户ID,就会比较麻烦!我们的目的是为了计算,而不是保存用户ID;
测试使用
1 2 3 4 5 6 7 8 9 10 11 12 127.0 .0 .1 :6379 > PFADD mykey a b c d e f g h i j (integer) 1 127.0 .0 .1 :6379 > PFCOUNT mykey (integer) 10 127.0 .0 .1 :6379 > PFADD mykey2 i j z x c v b n m (integer) 1 127.0 .0 .1 :6379 > PFCOUNT mykey2 (integer) 9 127.0 .0 .1 :6379 > PFMERGE mykey3 mykey mykey2 OK 127.0 .0 .1 :6379 > PFCOUNT mykey3 (integer) 15
如果允许容错,那么一定可以使用Hyperloglog!
如果不允许容错,就使用set或者自己的数据类型即可!
bitmap 位存储
统计用户信息,活跃,不活跃!登录,未登录!打卡,365打卡!两个状态的都可以使用Bitmap!
Bitmap位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!
365天=365bit 1字节=8bit 46个字节左右!
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 127.0 .0 .1 :6379 > SETBIT sign 0 1 (integer) 0 127.0 .0 .1 :6379 > SETBIT sign 1 0 (integer) 0 127.0 .0 .1 :6379 > SETBIT sign 2 0 (integer) 0 127.0 .0 .1 :6379 > SETBIT sign 3 1 (integer) 0 127.0 .0 .1 :6379 > SETBIT sign 4 1 (integer) 0 127.0 .0 .1 :6379 > SETBIT sign 5 0 (integer) 0 127.0 .0 .1 :6379 > SETBIT sign 6 0 (integer) 0 127.0 .0 .1 :6379 > GETBIT sign 3 (integer) 1 127.0 .0 .1 :6379 > GETBIT sign 6 (integer) 0 127.0 .0 .1 :6379 > BITCOUNT sign (integer) 3
事务 redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,执行过程中按照顺序执行 一次性,顺序性,排他性,执行一些列的命令
redis单条命令是保持原子性,但是事务不保证原子性 redis事务没有隔离级别的概念 所有的命令在事务中,并没有被直接执行,只有发起执行命令才会被执行!exec redis事务 a.开启事务(multi) b.命令入队 c.执行事务(exec)
Jeids SpringBoot整合 Redis.conf详解 Redis持久化 Redis发布订阅 Redis主从复制 Redis缓存穿透和雪崩