当前位置: 首页 > news >正文

建网站程序潍坊仿站定制模板建站

建网站程序,潍坊仿站定制模板建站,百度广告费用,宁波网站建设方案联系方式文章目录1、Nosql概述1.1 为什么要用Nosql1.2 什么是NoSQL1.3 阿里巴巴演进分析2、NoSQL的四大分类3、Redis入门3.1 概述3.2 Windows安装3.3 Linux安装3.4 测试性能3.5 基础的知识4、五大数据类型4.1 Redis-Key4.2 String#xff08;字符串#xff09;4.3 List#xff08;列… 文章目录1、Nosql概述1.1 为什么要用Nosql1.2 什么是NoSQL1.3 阿里巴巴演进分析2、NoSQL的四大分类3、Redis入门3.1 概述3.2 Windows安装3.3 Linux安装3.4 测试性能3.5 基础的知识4、五大数据类型4.1 Redis-Key4.2 String字符串4.3 List列表4.4 Set集合4.5 Hash哈希4.6 Zset有序集合5、三种特殊数据类型5.1 Geospatial 地理位置5.2 Hyperloglog 基数统计5.3 Bitmap 位图6、事务7、Jedis7.1 事务8、SpringBoot整合9、Redis.conf详解10、Redis持久化10.1 RDBRedis DataBase10.2 AOFAppend Only File11、Redis发布订阅12、Redis主从复制13、哨兵模式14、Redis缓存穿透和雪崩14.1 缓存穿透查不到14.2 缓存击穿量太大缓存过期14.3 缓存雪崩1、Nosql概述 1.1 为什么要用Nosql 1 、单机MySQL的年代 90 年代一个基本的网站访问量一般不会太大单个数据库完全足够 那个时候更多的去使用静态网页 Html ~ 服务器根本没有太大的压力 思考一下这种情况下整个网站的瓶颈是什么 1 、数据量如果太大、一个机器放不下了 2 、数据的索引 B Tree一个机器内存也放不下 3 、访问量读写混合一个服务器承受不了~ 只要你开始出现以上的三种情况之一那么你就必须要晋级 2 、Memcached缓存 MySQL 垂直拆分 读写分离 网站80%的情况都是在读每次都要去查询数据库的话就十分的麻烦所以说我们希望减轻数据的压 力我们可以使用缓存来保证效率 发展过程 优化数据结构和索引– 文件缓存IO— Memcached当时最热门的技术 3 、分库分表 水平拆分 MySQL集群 技术和业务在发展的同时对人的要求也越来越高 本质数据库读写 早些年 MyISAM 表锁十分影响效率高并发下就会出现严重的锁问题 转战 InnoDB行锁 慢慢的就开始使用分库分表来解决写的压力 MySQL 在那个年代推出了表分区这个并没有多少公司使用 MySQL 的 集群很好满足那个年代的所有需求 4、如今年代 2010–2020 十年之间世界已经发生了翻天覆地的变化定位也是一种数据音乐热榜 MySQL 等关系型数据库就不够用了数据量很多变化很快~ MySQL 有的使用它来村粗一些比较大的文件博客图片数据库表很大效率就低了如果有一种数据库来专门处理这种数据MySQL压力就变得十分小研究如何处理这些问题大数据的IO压力下表几乎没法更大 目前一个基本的互联网项目 为什么要用NoSQL 用户的个人信息社交网络地理位置。用户自己产生的数据用户日志等等爆发式增长 这时候我们就需要使用NoSQL数据库的Nosql 可以很好的处理以上的情况 1.2 什么是NoSQL NoSQL NoSQL Not Only SQL 不仅仅是SQL 关系型数据库表格 行 列 泛指非关系型数据库的随着web2.0互联网的诞生传统的关系型数据库很难对付web2.0时代尤其 是超大规模的高并发的社区 暴露出来很多难以克服的问题NoSQL在当今大数据环境下发展的十分迅速Redis是发展最快的而且是我们当下必须要掌握的一个技术 很多的数据类型用户的个人信息社交网络地理位置。这些数据类型的存储不需要一个固定的格式不需要多余的操作就可以横向扩展的 MapString,Object 使用键值对来控制 NoSQL 特点 1 、方便扩展数据之间没有关系很好扩展 2 、大数据量高性能Redis 一秒写 8 万次读取 11 万NoSQL的缓存记录级是一种细粒度的缓存性能会比较高 3 、数据类型是多样型的不需要事先设计数据库随取随用如果是数据量十分大的表很多人就无法设计了 4 、高可用 传统的RDBMS 和 NoSQL 传统 RDBMS -结构化组织 -SQL -数据和关系都在单独的表中 -严格的一致性 -操作数据定义语言 -基础的事务 -....NoSQL -不仅仅是数据 -没有固定的查询语言 -键值对存储列存储文档存储图形数据库社交关系 -最终一致性 -CAP定理和BASE理论 异地多活 初级架构师 -高性能高可用高可扩 -....了解3V3高 大数据时代的3V主要是描述问题的 海量Volume多样Variety实时Velocity 大数据时代的 3 高主要是对程序的要求 高并发高可扩高性能 真正在公司中的实践NoSQL RDBMS 一起使用才是最强的阿里巴巴的架构演进 技术没有高低之分就看你如何去使用提升内功思维的提高 1.3 阿里巴巴演进分析 思考问题这么多东西难道都是在一个数据库中的吗? 技术急不得越是慢慢学才能越扎实 开源才是技术的王道 任何一家互联网的公司都不可能只是简简单单让用户能用就好了 大量公司做的都是相同的业务竞品协议 随着这样的竞争业务是越来越完善然后对于开发者的要求也是越来越高 如果你未来相当一个架构师 没有什么是加一层解决不了的 # 1、商品的基本信息名称、价格、商家信息关系型数据库就可以解决了 MySQL / Oracle 淘宝早年就去IOE了- 王坚推荐文章阿里云的这群疯子 40 分钟重要淘宝内部的 MySQL 不是大家用的 MySQL# 2、商品的描述、评论文字比较多文档型数据库中MongoDB# 3、图片分布式文件系统 FastDFS- 淘宝自己的 TFS- Gooale的 GFS- Hadoop HDFS- 阿里云的 oss# 4、商品的关键字 搜索 - 搜索引擎 solr elasticsearch- ISerach多隆多去了解一下这些技术大佬所有牛逼的人都有一段苦逼的岁月但是你只要像SB一样的去坚持终将牛逼# 5、商品热门的波段信息、- 内存数据库- Redis Tair、Memache...# 6、商品的交易外部的支付接口- 三方应用 要知道一个简单地网页背后的技术一定不是大家所想的那么简单 大型互联网应用问题 数据类型太多了 数据源繁多经常重构 数据要改造大面积改造 解决问题 这里以上都是NoSQL入门概述不仅能够提高大家的知识还可以帮助大家了解大厂的工作内容 2、NoSQL的四大分类 KV键值对 新浪 Redis美团Redis Tair阿里、百度Redis memecache 文档型数据库bson格式 和json一样 MongoDB 一般必须要掌握 MongoDB 是一个基于分布式文件存储的数据库C 编写主要用来处理大量的文档MongoDB 是一个介于关系型数据库和非关系型数据库中间的产品MongoDB 是非关系型数 据库中功能最丰富最像关系型数据库的 ConthDB 列存储数据库 HBase分布式文件系统 图关系数据库 他不是存图形放的是关系比如朋友圈社交网络广告推荐Neo4j InfoGrid 四者对比 分类Examples举例典型应用场景数据模型优点缺点键值key-valueTokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB内容缓存主要用于处理大量数据的高访问负载也用于一些日志系统等等。Key 指向 Value 的键值对通常用hash table来实现查找速度快数据无结构化通常只被当作字符串或者二进制数据列存储数据库Cassandra, HBase, Riak分布式的文件系统以列簇式存储将同一列数据存在一起查找速度快可扩展性强更容易进行分布式扩展功能相对局限文档型数据库CouchDB, MongoDbWeb应用与Key-Value类似Value是结构化的不同的是数据库能够了解Value的内容Key-Value对应的键值对Value为结构化数据数据结构要求不严格表结构可变不需要像关系型数据库一样需要预先定义表结构查询性能不高而且缺乏统一的查询语法。图形(Graph)数据库Neo4J, InfoGrid, Infinite Graph社交网络推荐系统等。专注于构建关系图谱图结构利用图结构相关算法。比如最短路径寻址N度关系查找等很多时候需要对整个图做计算才能得出需要的信息而且这种结构不太好做分布式的集群方案。 3、Redis入门 3.1 概述 Redis 是什么 RedisRemote Dictionary Server )即远程字典服务! 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库并提供多种语言的API。 redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件并且在此基础上实现了 master-slave(主从)同步。 免费和开源是当下最热门的 NoSQL 技术之一也被人们称之为结构化数据库 Redis 能干嘛 内存存储、持久化内存中是断电即失、所以说持久化很重要rdb、aof效率高可以用于高速缓存发布订阅系统地图信息分析计时器、计数器浏览量… 特性 多样的数据类型 持久化 集群 事务 … 缺点 不适合存储重要的数据财务类等 不适合存储经常修改的数据 3.2 Windows安装 1 、下载安装包https://github.com/dmajkic/redis/releases 2 、下载完毕得到压缩包 3 、解压到自己电脑上的环境目录下的就可以的Redis 十分的小只有5M 4 、开启Redis双击运行服务–redis-server.exe即可 5 、使用redis客户端–redis-cli.exe来连接redis 记住一句话Window下使用确实简单但是Redis 推荐我们使用Linux去开发使用 3.3 Linux安装 1 、下载安装包 redis-5.0.8.tar.gz 用xftp把安装包放到 /opt下 2 、解压Redis的安装包 程序 /opt tar -zxvf redis-5.0.8.tar.gz 3 、进入解压后的文件可以看到我们redis的配置文件 4 、基本的环境安装 yum install gcc-c # 安装gcc如果使用redis6.0以上的话需要gcc9.0版本以上才gcc -v # 查看安装版本make # 自动进行配置安装后必须执行需要等待较长时间make install # 接着执行5 、redis的默认安装路径 /usr/local/bin cd /usr/local/bin # 进入目录ls # 查看6 、将redis配置文件。复制到我们当前目录下 mkdir RedisConfig # 创建目录存放配置文件cp /opt/redis-5.0.8/redis.conf RedisConfig/ # 将/opt/redis-5.0.8/下的配置文件拷贝过来7 、redis默认不是后台启动的修改配置文件 vi redis.conf # 进行编辑8 、启动Redis服务 cd /usr/local/bin # 回到bin目录redis-server RedisConfig/redis.conf # 启动redis服务9 、使用redis-cli 进行连接测试 redis-cli -p 6379 # -h 指定主机 -p指定端口ping # 测试连接10 、复制连接新开一个窗口查看redis的进程是否开启 ps -ef|grep redis11 、如何关闭Redis服务呢 shutdown # 关闭服务exit # 退出12 、再次查看进程是否存在 13 、后面我们会使用单机多Redis启动集群测试 3.4 测试性能 redis-benchmark 是一个压力测试工具 官方自带的性能测试工具 redis-benchmark 命令参数 redis 性能测试工具可选参数如下所示 序号选项描述默认值1-h指定服务器主机名127.0.0.12-p指定服务器端口63793-s指定服务器 socket4-c指定并发连接数505-n指定请求数100006-d以字节的形式指定 SET/GET 值的数据大小27-k1keep alive 0reconnect18-rSET/GET/INCR 使用随机 key, SADD 使用随机值9-P通过管道传输 请求110-q强制退出 redis。仅显示 query/sec 值11–csv以 CSV 格式输出12-l生成循环永久执行测试13-t仅运行以逗号分隔的测试命令列表。14-IIdle 模式。仅打开 N 个 idle 连接并等待。 我们来简单测试下 # 测试 100 个并发连接 每个并发100000 个请求需要先开启redis redis-benchmark -h localhost -p 6379 -c 100 -n 100000如何查看这些分析呢 3.5 基础的知识 redis默认有 16 个数据库 默认使用的是第 0 个 # 可以使用 select 进行切换数据库 127 .0.0.1:6379 select 3 # 切换数据库 OK 127 .0.0.1:6379[3] DBSIZE # 查看DB大小 (integer) 0 127 .0.0.1:6379[3] set name xu 127 .0.0.1:6379[3] keys * # 查看数据库所有的key 1 ) name 127.0.0.1:6379[3] FLUSHDB # 清除当前数据库 OK 127.0.0.1:6379[3] FLUSHALL # 清除全部数据库的内容 OK思考为什么redis是 6379 粉丝效应了解一下即可 Redis 是单线程的 明白Redis是很快的官方表示Redis是基于内存操作CPU不是Redis性能瓶颈Redis的瓶颈是根据机器的内存和网络带宽来定既然可以使用单线程来实现就使用单线程了所以就使用了单线程了 Redis 是C 语言写的官方提供的数据为 100000 的QPS完全不比同样是使用 key-vale的 Memecache差 Redis 为什么单线程还这么快 1 、误区 1 高性能的服务器一定是多线程的 2 、误区 2 多线程CPU上下文会切换一定比单线程效率高 先去CPU内存硬盘的速度要有所了解 核心redis 是将所有的数据全部放在内存中的所以说使用单线程去操作效率就是最高的多线程 CPU上下文会切换耗时的操作对于内存系统来说如果没有上下文切换效率就是最高的多次读写都是在一个CPU上的在内存情况下这个就是最佳的方案 4、五大数据类型 Redis 是一个开源BSD许可的内存中的数据结构存储系统它可以用作数据库、缓存和消息中间件MQ。 它支持多种类型的数据结构如 字符串strings 散列hashes 列表lists 集合sets 有序集合sorted sets 与范围查询 bitmaps hyperloglogs 和 地理空间 geospatial 索引半径查询。 Redis 内置了 复制replicationLUA脚本Lua scripting LRU 驱动事件LRU eviction事务transactions 和不同级别的 磁盘持久化persistence 并通过 Redis哨兵Sentinel和 自动分区Cluster提供高可用性high availability。 我们现在讲解的所有命令大家一定要全部记住后面我们使用SpringBoot。Jedis所有的方法就是 这些命令——单点登录 4.1 Redis-Key 127 .0.0.1:6379 keys * # 查看所有的key (empty list or set) 127 .0.0.1:6379 set name kuangshen # set key 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 # 判断当前的key是否存在 (integer) 1 127 .0.0.1:6379 EXISTS name (integer) 0 127 .0.0.1:6379 move name 1 # 移除当前的key (integer) 1 127 .0.0.1:6379 keys * 1 ) age 127 .0.0.1:6379 set name qinjiang OK 127 .0.0.1:6379 keys * 1 ) age 2 ) name 127 .0.0.1:6379 clear 127 .0.0.1:6379 keys * 1 ) age 2 ) name 127 .0.0.1:6379 get name qinjiang 127 .0.0.1:6379 EXPIRE name 10 # 设置key的过期时间单位是秒 (integer) 1 127 .0.0.1:6379 ttl name # 查看当前key的剩余时间 (integer) 4 127 .0.0.1:6379 ttl name (integer) 3 127 .0.0.1:6379 ttl name (integer) 2 127 .0.0.1:6379 ttl name (integer) 1 127 .0.0.1:6379 ttl name (integer) -2 127 .0.0.1:6379 get name (nil) 127 .0.0.1:6379 type name # 查看当前key的一个类型 string 127 .0.0.1:6379 type age string4.2 String字符串 90% 的 java程序员使用 redis 只会使用一个String类型 ########################################################################## 127 .0.0.1:6379 set key1 v1 # 设置值 OK 127 .0.0.1:6379 get key1 # 获得值 v1 127 .0.0.1:6379 keys * # 获得所有的key 1 ) key1 127 .0.0.1:6379 EXISTS key1 # 判断某一个key是否存在 (integer) 1 127 .0.0.1:6379 APPEND key1 hello # 追加字符串如果当前key不存在就相当于setkey (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 ,kaungshen (integer) 17 127 .0.0.1:6379 STRLEN key1 (integer) 17 127 .0.0.1:6379 get key1 v1hello,kaungshen ########################################################################## # i # 步长 i 127 .0.0.1:6379 set views 0 # 初始浏览量为 0 OK 127 .0.0.1:6379 get views 0 127 .0.0.1:6379 incr views # 自增 1 浏览量变为 1 (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 # 自减 1 浏览量-1 (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 INCRBY views 10 (integer) 19 127 .0.0.1:6379 DECRBY views 5 (integer) 14########################################################################## # 字符串范围 getrange 127 .0.0.1:6379 set key1 hello,kuangshen # 设置 key1 的值 OK 127 .0.0.1:6379 get key1 hello,kuangshen 127 .0.0.1:6379 getrange key1 0 3 # 截取字符串 [0,3] hell 127 .0.0.1:6379 GETRANGE key1 0 -1 # 获取全部的字符串 和 get key是一样的 hello,kuangshen########################################################################## # 替换 setrange 127 .0.0.1:6379 set key2 abcdefg OK 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########################################################################## setex (set with expire) # 设置值同时设置过期时间setnx (set if not exist) # 不存在再设置存在的话保持原值 在分布式锁中会常常使用127 .0.0.1:6379 setex key3 30 hello # 设置key3 的值为 hello,30秒后过期 OK 127 .0.0.1:6379 ttl key3 (integer) 26 127 .0.0.1:6379 get key3 hello 127 .0.0.1:6379 setnx mykey redis # 如果mykey 不存在创建mykey (integer) 1 127 .0.0.1:6379 keys * 1 ) key2 2 ) mykey 3 ) key1 127 .0.0.1:6379 ttl key3 (integer) -2 127 .0.0.1:6379 setnx mykey MongoDB # 如果mykey存在创建失败 (integer) 0 127 .0.0.1:6379 get mykey redis########################################################################## mset # 同时设置多个值 mget # 同时获取多个值127 .0.0.1:6379 mset k1 v1 k2 v2 k3 v3 # 同时设置多个值 OK 127 .0.0.1:6379 keys * 1 ) k1 2 ) k2 3 ) k3 127 .0.0.1:6379 mget k1 k2 k3 # 同时获取多个值 1 ) v1 2 ) v2 3 ) v3 127.0.0.1:6379 msetnx k1 v2 k4 v4 #设置失败k1已经存在msetnx是原子性操作 (integer) 0 127.0.0.1:6379 get k4 (nil)########################################################################## # 对象 set user:1 {name:zhangsan,age:3} # 设置一个user:1 对象 值为 json字符来保存一个对象127.0.0.1:6379 set user:1 {name:xu,age:3} OK 127.0.0.1:6379 get user:1 #本质还是键值对user:1为key{name:xu,age:3}为value {name:xu,age:3} # 这里的key是一个巧妙的设计 user:{id}:{filed} , 如此设计在Redis中是完全OK了 127.0.0.1:6379 mset user:1:name xu1 user:1:age 4 # 这里本质也是键值对 OK 127.0.0.1:6379 get user:1 {name:xu,age:3} 127.0.0.1:6379 mget user:1:name user:1:age 1) xu1 2) 4########################################################################## getset # 先get然后再set 127 .0.0.1:6379 getset db redis # 如果不存在值则返回 nil (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数据结构是相同的 String类似的使用场景value除了是我们的字符串还可以是我们的数字 计数器 统计多单位的数量 粉丝数 对象缓存存储 4.3 List列表 基本的数据类型列表 在redis里面我们可以把list玩成 栈、队列、阻塞队列 所有的list命令都是用 L 开头的Redis不区分大小写命令 ########################################################################## lpush # 从左边头部插入 rpush # 从右边尾部插入 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 # 不能用get命令获取list中的所有值 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 right # 将一个值或者多个值插入到列表尾部 右 (integer) 4 127 .0.0.1:6379 LRANGE list 0 -1 1 ) three 2 ) two 3 ) one 4 ) righr########################################################################## 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 # 移除list的第一个元素 three 127 .0.0.1:6379 Rpop list # 移除list的最后一个元素 righr 127 .0.0.1:6379 LRANGE list 0 -1 1 ) two 2 ) one########################################################################## lindex 127 .0.0.1:6379 LRANGE list 0 -1 1 ) two 2 ) one 127 .0.0.1:6379 lindex list 1 # 通过下标获得 list 中的某一个值 one 127 .0.0.1:6379 lindex list 0 two########################################################################## llen # 获取列表长度 127 .0.0.1:6379 Lpush list one (integer) 1 127 .0.0.1:6379 Lpush list two (integer) 2127 .0.0.1:6379 Lpush list three(integer) 3127 .0.0.1:6379 Llen list # 返回列表的长度(integer) 3##########################################################################lrem # 移除指定的值从头部开始的顺序移除# 取关 uid127.0.0.1:6379 lrange list 0 -1 1) 3 2) 2 3) 1 4) 3 5) 3 127.0.0.1:6379 lrem list 1 3 # 移除list集合中指定个数的value精确匹配 (integer) 1 127.0.0.1:6379 lrange list 0 -1 1) 2 2) 1 3) 3 4) 3 127.0.0.1:6379 lrem list 3 3 # 移除的个数比列表拥有的个数多的话就全部移除 (integer) 2 127.0.0.1:6379 lrange list 0 -1 1) 2 2) 1########################################################################## ltrim # 修剪 list被截断!127.0.0.1:6379 lrange list 0 -1 1) 6 2) 5 3) 4 4) 1 5) 2 6) 1 127.0.0.1:6379 ltrim list 2 3 # 截取指定开始下标和结束下标的列表 OK 127.0.0.1:6379 lrange list 0 -1 1) 4 2) 1##########################################################################rpoplpush # 移除列表的最后一个元素将他移动到新的列表的头部中127 .0.0.1:6379 rpush mylist hello (integer) 1127 .0.0.1:6379 rpush mylist hello1(integer) 2127 .0.0.1:6379 rpush mylist hello2(integer) 3127 .0.0.1:6379 rpoplpush mylist myotherlist # 移除列表的最后一个元素将他移动到新的列表头部中hello2127 .0.0.1:6379 lrange mylist 0 -1 # 查看原来的列表1 ) hello2 ) hello1127 .0.0.1:6379 lrange myotherlist 0 -1 # 查看目标列表中确实存在改值1 ) hello2##########################################################################lset # 将列表中指定下标的值替换为另外一个值更新操作127 .0.0.1:6379 EXISTS list # 判断这个列表是否存在(integer) 0127 .0.0.1:6379 lset list 0 item # 如果不存在列表我们去更新就会报错(error) ERR no such key127 .0.0.1:6379 lpush list value1(integer) 1127 .0.0.1:6379 LRANGE list 0 01 ) value1127 .0.0.1:6379 lset list 0 item # 如果存在更新当前下标的值OK127 .0.0.1:6379 LRANGE list 0 01 ) item127 .0.0.1:6379 lset list 1 other # 如果不存在则会报错(error) ERR index out of range##########################################################################linsert # 将某个具体的value插入到列把你中某个元素如果列表有多个符合的元素从头部开始找到的元素就是指定的元素的前面或者后面127 .0.0.1:6379 Rpush mylist hello(integer) 1127 .0.0.1:6379 Rpush mylist world(integer) 2127 .0.0.1:6379 LINSERT mylist before world other(integer) 3127 .0.0.1:6379 LRANGE mylist 0 -11 ) hello2 ) other3 ) world127 .0.0.1:6379 LINSERT mylist after world new(integer) 4127 .0.0.1:6379 LRANGE mylist 0 -11 ) hello2 ) other3 ) world4 ) new小结 他实际上是一个链表before Node after Node leftright 都可以插入值如果key 不存在创建新的链表如果key存在新增内容如果移除了所有值空链表也代表不存在在两边插入或者改动值效率最高 改变中间元素相对来说效率会低一点~ 消息排队消息队列 Lpush Rpop 栈 Lpush Lpop 4.4 Set集合 set中的值是不重复的 ########################################################################## sadd # set集合中添加多个元素 smembers # 查看指定set的所有值 sismembers # 判断某一个值是不是在set集合中127.0.0.1:6379 sadd myset 1 2 3 4 5 xu # set集合中添加元素 (integer) 6 127.0.0.1:6379 smembers myset # 查看指定set的所有值 1) 2 2) 4 3) 3 4) 5 5) xu 6) 1 127 .0.0.1:6379 sismembers myset 1 # 判断某一个值是不是在set集合中 (integer) 1 127 .0.0.1:6379 SISMEMBER myset 6 (integer) 0########################################################################## 127.0.0.1:6379 scard myset # 获取set集合中的内容元素个数 (integer) 6########################################################################## srem # 移除set集合中的指定元素(可以多个) 127.0.0.1:6379 srem myset 3 4 # 移除set集合中的指定元素(可以多个) (integer) 2 127.0.0.1:6379 smembers myset 1) 2 2) 5 3) xu 4) 1########################################################################## set 无序不重复集合。 srandmember # 抽随机元素127.0.0.1:6379 srandmember myset # 随机抽取一个元素 xu 127.0.0.1:6379 srandmember myset 5 127.0.0.1:6379 srandmember myset 5 # 抽取随机5个元素 1) 2 2) 5 3) 1 4) xu 127.0.0.1:6379 srandmember myset 3 1) 5 2) 1 3) xu##########################################################################spop # 随机删除key可指定个数127.0.0.1:6379 spop myset 1 127.0.0.1:6379 spop myset 5 127.0.0.1:6379 smembers myset 1) 2 2) xu 127.0.0.1:6379 spop myset 2 # 随机删除两个元素 1) 2 2) xu 127.0.0.1:6379 smembers myset (empty list or set)##########################################################################将一个指定的值移动到另外一个set集合127 .0.0.1:6379 sadd myset hello(integer) 1127 .0.0.1:6379 sadd myset world(integer) 1127 .0.0.1:6379 sadd myset kuangshen(integer) 1127 .0.0.1:6379 sadd myset2 set2(integer) 1127 .0.0.1:6379 smove myset myset2 kuangshen # 将一个指定的值移动到另外一个set集合(integer) 1127 .0.0.1:6379 SMEMBERS myset1 ) world2 ) hello127 .0.0.1:6379 SMEMBERS myset21 ) kuangshen2 ) set2########################################################################### 微博B站共同关注(并集)# 数字集合类- 差集 - 交集- 并集127.0.0.1:6379 smembers myset 1) 1 2) 3 3) 4 127.0.0.1:6379 smembers myset2 1) 1 2) 2 127.0.0.1:6379 sdiff myset myset2 # 差集以第一个为主做比较 1) 3 2) 4 127.0.0.1:6379 sinter myset myset2 # 交集 共同好友 1) 1 127.0.0.1:6379 sunion myset myset2 # 并集 1) 1 2) 2 3) 3 4) 4 127.0.0.1:6379 sadd myset3 1 2 3 5 (integer) 4 127.0.0.1:6379 sdiff myset myset2 myset3 # 差集以第一个为主做比较 1) 4 127.0.0.1:6379 sinter myset myset2 myset3 1) 1 127.0.0.1:6379 sunion myset myset2 myset3 1) 1 2) 2 3) 3 4) 4 5) 5微博A用户将所有关注的人放在一个set集合中将它的粉丝也放在一个集合中 共同关注共同爱好二度好友推荐好友六度分割理论 4.5 Hash哈希 Map集合key-map! 时候这个值是一个map集合 本质和String类型没有太大区别还是一个简单的 key-vlaue 127 .0.0.1:6379 hset myhash field1 kuangshen # set一个具体 key-vlaue (integer) 1 127 .0.0.1:6379 hget myhash field1 # 获取一个字段值 kuangshen 127 .0.0.1:6379 hmset myhash field1 hello field2 world # set多个 key-vlaue 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 hdel myhash field1 # 删除hash指定key字段对应的value值也就消失了 (integer) 1 127 .0.0.1:6379 hgetall myhash 1 ) field2 2 ) world##########################################################################127 .0.0.1:6379 hmset myhash field1 hello field2 world OK 127 .0.0.1:6379 HGETALL myhash 1 ) field2 2 ) world 3 ) field1 4 ) hello 127 .0.0.1:6379 hlen myhash # 获取hash表的字段数量 (integer) 2##########################################################################127 .0.0.1:6379 hexists myhash field1 # 判断hash中指定字段是否存在 (integer) 1 127 .0.0.1:6379 HEXISTS myhash field3 (integer) 0########################################################################### 只获得所有field # 只获得所有value 127 .0.0.1:6379 hkeys myhash # 只获得所有field 1 ) field2 2 ) field1 127 .0.0.1:6379 hvals myhash # 只获得所有value 1 ) world 2 ) hello########################################################################### 没有 hdecrb 和 hsetex 指令 127 .0.0.1:6379 hset myhash field3 5 (integer) 1 127 .0.0.1:6379 hincrby myhash field3 2 # 指定增量 (integer) 7 127 .0.0.1:6379 HINCRBY myhash field3 -2 (integer) 5 127 .0.0.1:6379 hsetnx myhash field4 hello # 如果不存在则可以设置 (integer) 1 127 .0.0.1:6379 hsetnx myhash field4 world # 如果存在则不能设置 (integer) 0hash变更的数据 user name age,尤其是是用户信息之类的经常变动的信息hash 更适合于对象的存储String更加适合字符串存储 4.6 Zset有序集合 在set的基础上增加了一个值set k1 v1 zset k1 score1 v1 根据 score 的大小进行排序 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 127.0.0.1:6379 zrange myset 0 -1 withscores # 附带成绩比较排序值显示 1) one 2) 1 3) two 4) 2 5) three 6) 3###########################################################################排序如何实现 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 xu (integer) 1 # ZRANGEBYSCORE key min max 127 .0.0.1:6379 zrangebyscore salary -inf inf # 显示全部的用户 从小到大 这个指令跟 ‘ zrange salary 0 -1 ’一样 1 ) xu 2 ) xiaohong 3 ) zhangsan 127.0.0.1:6379 zrevrange salary 0 -1 # 从大到小排序 1) zhangsan 2) xiaohong 3) xu 127 .0.0.1:6379 ZRANGEBYSCORE salary -inf inf withscores # 显示全部的用户并且附带成绩 1 ) xu 2 ) 500 3 ) xiaohong 5 ) zhangsan 6 ) 5000 127 .0.0.1:6379 ZRANGEBYSCORE salary -inf 2500 withscores # 显示工资小于 2500 员工的升序排序 1 ) kaungshen 2 ) 500 3 ) xiaohong 4 ) 2500########################################################################### 移除zset中的元素 127 .0.0.1:6379 zrange salary 0 -1 1 ) xu 2 ) xiaohong 3 ) zhangsan 127 .0.0.1:6379 zrem salary xiaohong # 移除有序集合中的指定元素 (integer) 1 127 .0.0.1:6379 zrange salary 0 -1 1 ) kaungshen 2 ) zhangsan 127 .0.0.1:6379 zcard salary # 获取有序集合中的个数 (integer) 2##########################################################################127 .0.0.1:6379 zadd myset 1 hello (integer) 1 127 .0.0.1:6379 zadd myset 2 world 3 kuangshen (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 带权重进行判断 排行榜应用实现取Top N 测试 5、三种特殊数据类型 5.1 Geospatial 地理位置 朋友的定位附近的人打车距离计算 Redis 的 Geo 在Redis3.2 版本就推出了 这个功能可以推算地理位置的信息两地之间的距离方圆几里的人 可以查询一些测试数据http://www.jsons.cn/lngcodeinfo/0706D99C19A781A3/ 只有 六个命令 Redis 地理位置(geo) 命令 命令描述Redis GEOHASH 命令返回一个或多个位置元素的 Geohash 表示Redis GEOPOS 命令从key里返回所有给定位置元素的位置经度和纬度Redis GEODIST 命令返回两个给定位置之间的距离Redis GEORADIUS 命令以给定的经纬度为中心 找出某一半径内的元素Redis GEOADD 命令将指定的地理空间位置纬度、经度、名称添加到指定的key中Redis GEORADIUSBYMEMBER 命令找出位于指定范围内的元素中心点是由给定的位置元素决定GEOADD 添加地理位置 # geoadd 添加地理位置 # 规则两极无法直接添加我们一般会下载城市数据直接通过java程序一次性导入 # 有效的经度从-180度到 180 度。 # 有效的纬度从-85.05112878度到85.05112878度。 # 当坐标位置超出上述指定范围时该命令将会返回一个错误。 # 127.0.0.1:6379 geoadd china:city 39.90 116.40 beijin # (error) ERR invalid longitude,latitude pair 39 .900000,116.400000 # 参数 key 值 127 .0.0.1:6379 geoadd china:city 116.40 39.90 beijing (integer) 1 127 .0.0.1:6379 geoadd china:city 121.47 31.23 shanghai (integer) 1 127 .0.0.1:6379 geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen (integer) 2 127 .0.0.1:6379 geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian (integer) 2GEOPOS 获取指定的城市的经度和纬度 获得指定位置定位一定是一个坐标值 127 .0.0.1:6379 geopos china:city beijing # 获取指定的城市的经度和纬度 1 ) 1 ) 116.399998962879180912 ) 39.90000009167092543 127 .0.0.1:6379 GEOPOS china:city beijing chongqing 1 ) 1 ) 116.399998962879180912 ) 39.90000009167092543 2 ) 1 ) 106.499997675418853762 ) 29.52999957900659211GEODIST 返回两个位置之间的距离 两人之间的距离 单位 m 表示单位为米 (默认单位)km 表示单位为千米mi 表示单位为英里ft 表示单位为英尺 127 .0.0.1:6379 geodist china:city beijing shanghai km # 查看上海到北京的直线距离 1067.3788 127 .0.0.1:6379 GEODIST china:city beijing chongqing km # 查看重庆到北京的直线距离 1464.0708GEORADIUS 以给定的经纬度为中心 找出某一半径内的位置元素 我附近的人 获得所有附近的人的地址定位通过半径来查询 获得指定数量的人 200 所有数据应该都录入china:city 才会让结果更加请求 127 .0.0.1:6379 georadius china:city 110 30 1000 km # 以 110 30 这个经纬度为中心寻找方圆1000km内的城市 1 ) chongqi 2 ) xian 3 ) shengzhen 4 ) hangzhou 127 .0.0.1:6379 GEORADIUS china:city 110 30 500 km 1 ) chongqi 2 ) xian 127 .0.0.1:6379 GEORADIUS china:city 110 30 500 km withdist # 显示附带位置距离 1 ) 1 ) chongqi2 ) 341.9374 2 ) 1 ) xian2 ) 483.8340 127 .0.0.1:6379 GEORADIUS china:city 110 30 500 km withcoord # 显示他人的定位信息 1 ) 1 ) chongqi2 ) 1 ) 106.499997675418853762 ) 29.52999957900659211 2 ) 1 ) xian2 ) 1 ) 108.960001766681671142 ) 34.25999964418929977 127 .0.0.1:6379 GEORADIUS china:city 110 30 500 km withdist withcoord count 1 # 筛选出指定数目的结果 1 ) 1 ) chongqi2 ) 341.93743 ) 1 ) 106.499997675418853762 ) 29.52999957900659211 127 .0.0.1:6379 GEORADIUS china:city 110 30 500 km withdist withcoord count 2 1) 1) chongqing2) 341.93743) 1) 106.499997675418853762) 29.52999957900659211 2) 1) xian2) 483.83403) 1) 108.960001766681671142) 34.25999964418929977GEORADIUSBYMEMBER 以指定的key为中心找出某一半径内的位置元素 # 找出位于指定元素周围的其他元素 127 .0.0.1:6379 georadiusbymember china:city beijing 1000 km 1 ) beijing 2 ) xian 127 .0.0.1:6379 GEORADIUSBYMEMBER china:city shanghai 400 km 1 ) hangzhou 2 ) shanghaiGEOHASH 返回一个或多个位置元素的 Geohash 表示 该命令将返回 11 个字符的Geohash字符串! # 将二维的经纬度转换为一维的字符串如果两个字符串越接近那么则距离越近 127 .0.0.1:6379 geohash china:city beijing chongqing 1 ) wx4fbxxfke0 2 ) wm5xzrybty0GEO 底层的实现原理其实就是 Zset我们可以使用Zset命令来操作geo 127 .0.0.1:6379 zrange china:city 0 -1 # 查看地图中全部的元素 1 ) chongqing 2 ) xian 3 ) shengzhen 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 ) shengzhen 4 ) hangzhou 5 ) shanghai5.2 Hyperloglog 基数统计 什么是基数 A {1,3,5,7,8,7} B{1,3,5,7,8} 基数不重复的元素 5可以接受误差 简介 Redis 2.8.9 版本就更新了 Hyperloglog 数据结构 Redis Hyperloglog 基数统计的算法 优点占用的内存是固定2^64 不同的元素的技术只需要废 12KB内存如果要从内存角度来比较的话 Hyperloglog 首选 网页的 UV 一个人访问一个网站多次但是还是算作一个人 传统的方式 set 保存用户的id然后就可以统计 set 中的元素数量作为标准判断! 这个方式如果保存大量的用户id就会比较麻烦我们的目的是为了计数而不是保存用户id 0.81% 错误率 统计UV任务可以忽略不计的 测试使用 127 .0.0.1:6379 pfadd mykey a b c d e f g h i j # 创建第一组元素 mykey (integer) 1 127 .0.0.1:6379 pfcount mykey # 统计 mykey 元素的基数数量 (integer) 10 127 .0.0.1:6379 PFadd mykey2 i j z x c v b n m # 创建第二组元素 mykey2 (integer) 1 127 .0.0.1:6379 PFCOUNT mykey2 (integer) 9 127 .0.0.1:6379 pfmerge mykey3 mykey mykey2 # 合并两组 mykey mykey2 mykey3 并集 OK 127 .0.0.1:6379 PFCOUNT mykey3 # 看并集的数量 (integer) 15如果允许容错那么一定可以使用 Hyperloglog 如果不允许容错就使用 set 或者自己的数据类型即可 5.3 Bitmap 位图 位存储 统计用户信息活跃不活跃 登录 、 未登录 打卡 365 打卡 两个状态的都可以使用Bitmaps Bitmap 位图数据结构 都是操作二进制位来进行记录就只有 0 和 1 两个状态 365 天 365 bit 1字节 8bit 46 个字节左右 # 使用bitmap 来记录 周一到周日的打卡 # 周一 1 周二 0 周三 1 周四0 ...... 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 1 (integer) 0 127.0.0.1:6379 setbit sign 3 0 (integer) 0 127.0.0.1:6379 setbit sign 4 0 (integer) 0 127.0.0.1:6379 setbit sign 5 1 (integer) 0 127.0.0.1:6379 setbit sign 6 0 (integer) 0 # 查看某一天是否有打卡 127.0.0.1:6379 getbit sign 5 (integer) 1 127.0.0.1:6379 getbit sign 6 (integer) 0 # 统计操作统计 打卡的天数 127.0.0.1:6379 bitcount sign (integer) 36、事务 Redis 事务本质一组命令的集合 一个事务中的所有命令都会被序列化在事务执行过程的中会按照顺序执行 一次性、顺序性、排他性执行一些列的命令 ------ 队列 set set set 执行 -------Redis事务没有没有隔离级别的概念 所有的命令在事务中并没有直接被执行只有发起执行命令的时候才会执行Exec Redis单条命令是保证原子性的但是事务不保证原子性 redis的事务 开启事务multi命令入队…执行事务exec 正常执行事务 # 正常执行事务 127 .0.0.1:6379 multi # 开启事务 OK # 命令入队 127 .0.0.1:6379 set k1 v1 QUEUED 127 .0.0.1:6379 set k2 v2 QUEUED 127 .0.0.1:6379 get k2 QUEUED 127 .0.0.1:6379 set k3 v3 QUEUED 127 .0.0.1:6379 exec # 执行事务 1 ) OK 2 ) OK 3 ) v2 4 ) OK放弃事务 127 .0.0.1:6379 multi # 开启事务 OK 127 .0.0.1:6379 set k1 v1 QUEUED 127 .0.0.1:6379 set k2 v2 QUEUED 127 .0.0.1:6379 set k4 v4 QUEUED 127 .0.0.1:6379 discard # 取消事务 OK 127 .0.0.1:6379 get k4 # 事务队列中命令都不会被执行 (nil)编译型异常代码有问题 命令有错 事务中所有的命令都不会被执行 127 .0.0.1:6379 multi OK 127 .0.0.1:6379 set k1 v1 QUEUED 127 .0.0.1:6379 set k2 v2 QUEUED 127 .0.0.1:6379 set k3 v3 QUEUED 127 .0.0.1:6379 getset k3 # 错误的命令 (error) ERR wrong number of arguments for getset command 127 .0.0.1:6379 set k4 v4 QUEUED 127 .0.0.1:6379 set k5 v5 QUEUED 127 .0.0.1:6379 exec # 执行事务报错 (error) EXECABORT Transaction discarded because of previous errors. 127 .0.0.1:6379 get k5 # 所有的命令都不会被执行 (nil)运行时异常 如果事务队列中存在语法性那么执行命令的时候其他命令是可以正常执行的错误命令抛出异常 127 .0.0.1:6379 set k1 v1 OK 127 .0.0.1:6379 multi OK 127 .0.0.1:6379 incr k1 # 会执行的时候失败 QUEUED 127 .0.0.1:6379 set k2 v2 QUEUED 127 .0.0.1:6379 set k3 v3 QUEUED 127 .0.0.1:6379 get k3 QUEUED 127 .0.0.1:6379 exec 1 ) (error) ERR value is not an integer or out of range # 虽然第一条命令报错了但是依旧正常执行成功了 2 ) OK 3 ) OK 4 ) v3 127 .0.0.1:6379 get k2 v2 127 .0.0.1:6379 get k3 v3监控 Watch 面试常问 **悲观锁**很悲观认为什么时候都会出问题无论做什么都会加锁 **乐观锁**很乐观认为什么时候都不会出问题所以不会上锁 更新数据的时候去判断一下在此期间是否有人修改过这个数据 获取version更新的时候比较 version Redis 监视测试 单线程 正常执行成功 127 .0.0.1:6379 set money 100 OK 127 .0.0.1:6379 set out 0 OK 127 .0.0.1:6379 watch money # 监视 money 对象 OK 127 .0.0.1:6379 multi # 事务正常结束数据期间没有发生变动这个时候就正常执行成功 OK 127 .0.0.1:6379 DECRBY money 20 QUEUED 127 .0.0.1:6379 INCRBY out 20 QUEUED 127 .0.0.1:6379 exec 1 ) (integer) 80 2 ) (integer) 20测试多线程修改值 , 使用watch 可以当做redis的乐观锁操作 127 .0.0.1:6379 watch money # 监视 money OK 127 .0.0.1:6379 multi OK 127 .0.0.1:6379 DECRBY money 10 QUEUED 127 .0.0.1:6379 INCRBY out 10 QUEUED 127 .0.0.1:6379 exec # 执行之前另外一个线程修改了money的值这个时候就会导致事务执行失败 (nil)如果修改失败获取最新的值就好 127.0.0.1:6379 unwatch # 事务执行失败先解锁 OK 127.0.0.1:6379 get money # 查看被修改后的值 900 127.0.0.1:6379 watch money # 获取最新的值再次监视 OK 127.0.0.1:6379 multi # 开启事务 OK 127.0.0.1:6379 decrby money 100 QUEUED 127.0.0.1:6379 incrby out 100 QUEUED 127.0.0.1:6379 exec # 对比监视的值是否发生变化如果没有执行成功 1) (integer) 800 2) (integer) 1007、Jedis 什么是Jedis 是 Redis 官方推荐的 java连接开发工具 使用Java 操作 Redis 中间件如果你要使用 java 操作 redis那么一定要对 Jedis 十分的熟悉 测试 1 、导入对应的依赖 !--导入jedis的包-- dependencies!-- https://mvnrepository.com/artifact/redis.clients/jedis --dependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion3.2.0/version/dependency!--fastjson--dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.62/version/dependency /dependencies2 、编码测试 连接数据库操作命令断开连接 public class RedisPing {public static void main(String[] args) {Jedis jedis new Jedis(127.0.0.1,6379);System.out.println(jedis.ping());jedis.close(); //关闭连接// jedis.shutdown(); //关闭服务} }输出 常用的API String List Set Hash Zset 所有的api命令就是我们对应的上面学习的指令一个都没有变化 7.1 事务 package com.xu;import com.alibaba.fastjson.JSONObject; import redis.clients.jedis.Jedis; import redis.clients.jedis.Transaction;public class RedisPing {public static void main(String[] args) {Jedis jedis new Jedis(127.0.0.1,6379);jedis.flushDB(); //清除数据JSONObject jsonObject new JSONObject(); //json对象jsonObject.put(name, xu);jsonObject.put(age, 11);String jsonString jsonObject.toJSONString(); //转换为json字符串Transaction multi jedis.multi();//开启事务try {multi.set(key1, jsonString);multi.set(key2, jsonString);int i 1 / 0; // 代码抛出异常事务执行失败multi.exec(); //执行事务} catch (Exception e) {multi.discard(); //出现异常停止事务e.printStackTrace();} finally {System.out.println(jedis.get(key1));System.out.println(jedis.get(key2));jedis.close(); //关闭连接}} }8、SpringBoot整合 SpringBoot 操作数据spring-data jpa jdbc mongodb redis SpringData 也是和 SpringBoot 齐名的项目 说明 在 SpringBoot2.x 之后原来使用的jedis 被替换为了 lettuce? jedis : 采用的直连多个线程操作的话是不安全的如果想要避免不安全的使用 jedis pool 连接 池 更像 BIO 模式 lettuce : 采用netty实例可以在多个线程中进行共享不存在线程不安全的情况可以减少线程数据 了更像 NIO 模式 源码分析 Bean // 我们可以自己定义一个redisTemplate来替换这个默认的 ConditionalOnMissingBean(name redisTemplate) public RedisTemplateObject, Object redisTemplate(RedisConnectionFactory isConnectionFactory) throws UnknownHostException {// 默认的 RedisTemplate 没有过多的设置redis 对象都是需要序列化// 两个泛型都是 Object, Object 的类型我们后使用需要强制转换 String, ObjectRedisTemplateObject, Object template new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template; } Bean ConditionalOnMissingBean // 由于 String 是redis中最常使用的类型所以说单独提出来了一个bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactoryredisConnectionFactory) throws UnknownHostException {StringRedisTemplate template new StringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template; }整合测试一下 1 、导入依赖 !-- 操作redis -- dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId /dependency2 、配置连接 # 配置redis spring.redis.host127.0.0.1 spring.redis.port 63793 、测试 SpringBootTest class Redis02SpringbootApplicationTests {Autowiredprivate RedisTemplate redisTemplate;Testvoid contextLoads() {// redisTemplate 操作不同的数据类型api和我们的指令是一样的// opsForValue 操作字符串 类似String 位图在这个里面// opsForList 操作List 类似List// opsForSet// opsForHash// opsForZSet// opsForGeo// opsForHyperLogLog// 除了进本的操作我们常用的方法都可以直接通过redisTemplate操作比如事务和基本的CRUD// 获取redis的连接对象// RedisConnection connection redisTemplate.getConnectionFactory().getConnection();// connection.flushDb();// connection.flushAll();redisTemplate.opsForValue().set(mykey,关注狂神说公众号);System.out.println(redisTemplate.opsForValue().get(mykey));} }关于对象的保存 我们来编写一个自己的 RedisTemplete package com.kuang.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; Configuration public class RedisConfig {// 自己定义了一个 RedisTemplateBeanSuppressWarnings(all)public RedisTemplateString, Object redisTemplate(RedisConnectionFactoryfactory) {// 固定模板在企业中拿去就可以直接使用// 我们为了自己开发方便一般直接使用 String, ObjectRedisTemplateString, Object template new RedisTemplateString,Object();template.setConnectionFactory(factory);// Json序列化配置Jackson2JsonRedisSerializer jackson2JsonRedisSerializer newJackson2JsonRedisSerializer(Object.class);ObjectMapper om new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);// String 的序列化StringRedisSerializer stringRedisSerializer newStringRedisSerializer();// key采用String的序列化方式template.setKeySerializer(stringRedisSerializer);// hash的key也采用String的序列化方式template.setHashKeySerializer(stringRedisSerializer);// value序列化方式采用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash的value序列化方式采用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;} }所有的redis操作其实对于java开发人员来说十分的简单更重要是要去理解redis的思想和每一种数据结构的用处和作用场景 9、Redis.conf详解 启动的时候就通过配置文件来启动 单位 1 、配置文件 unit单位 对大小写不敏感 包含 就好比我们学习的Spring、Improt include 网络 bind 127 .0.0.1 # 绑定的ipprotected-mode yes # 保护模式port 6379 # 端口设置通用 GENERAL daemonize yes # 以守护进程的方式运行默认是 no我们需要自己开启为yespidfile /var/run/redis_6379.pid # 如果以后台的方式运行我们就需要指定一个 pid 文件# 日志 # Specify the server verbosity level. # This can be one of: # debug (a lot of information, useful for development/testing) # verbose (many rarely useful info, but not a mess like the debug level) # notice (moderately verbose, what you want in production probably) 生产环境 # warning (only very important / critical messages are logged) loglevel noticelogfile # 日志的文件位置名databases 16 # 数据库的数量默认是 16 个数据库always-show-logo yes # 是否总是显示LOGO快照 持久化 在规定的时间内执行了多少次操作则会持久化到文件 .rdb 和 .aof redis 是内存数据库如果没有持久化那么数据断电即失 # 如果900s内如果至少有一个1 key进行了修改我们及进行持久化操作 save 900 1 # 如果300s内如果至少10 key进行了修改我们及进行持久化操作 save 300 10 # 如果60s内如果至少10000 key进行了修改我们及进行持久化操作 save 60 10000 # 我们之后学习持久化会自己定义这个测试stop-writes-on-bgsave-error yes # 持久化如果出错是否还需要继续工作rdbcompression yes # 是否压缩 rdb 文件需要消耗一些cpu资源rdbchecksum yes # 保存rdb文件的时候进行错误的检查校验dir ./ # rdb 文件保存的目录REPLICATION 主从复制 SECURITY 安全 可以在这里设置redis的密码默认是没有密码 127 .0.0.1:6379 ping PONG 127 .0.0.1:6379 config get requirepass # 获取redis的密码 1 ) requirepass 2 ) 127 .0.0.1:6379 config set requirepass 123456 # 设置redis的密码 OK 127 .0.0.1:6379 config get requirepass # 发现所有的命令都没有权限了 (error) NOAUTH Authentication required. 127 .0.0.1:6379 ping (error) NOAUTH Authentication required. 127 .0.0.1:6379 auth 123456 # 使用密码进行登录 OK 127 .0.0.1:6379 config get requirepass 1 ) requirepass 2 ) 123456限制 CLIENTS maxclients 10000 # 设置能连接上redis的最大客户端的数量maxmemory bytes # redis 配置最大的内存容量maxmemory-policy noeviction # 内存到达上限之后的处理策略1 、volatile-lru只对设置了过期时间的key进行LRU默认值2 、allkeys-lru 删除lru算法的key3 、volatile-random随机删除即将过期key4 、allkeys-random随机删除5 、volatile-ttl 删除即将过期的6 、noeviction 永不过期返回错误APPEND ONLY 模式 aof配置 appendonly no # 默认是不开启aof模式的默认是使用rdb方式持久化的在大部分所有的情况下rdb完全够用appendfilename appendonly.aof # 持久化的文件的名字# appendfsync always # 每次修改都会 sync。消耗性能 appendfsync everysec # 每秒执行一次 sync可能会丢失这1s的数据 # appendfsync no # 不执行 sync这个时候操作系统自己同步数据速度最快具体的配置我们在 Redis持久化 中去给大家详细详解 10、Redis持久化 面试和工作持久化都是重点 Redis 是内存数据库如果不将内存中的数据库状态保存到磁盘那么一旦服务器进程退出服务器中 的数据库状态也会消失。所以 Redis 提供了持久化功能 10.1 RDBRedis DataBase 什么是RDB 在指定的时间间隔内将内存中的数据集快照写入磁盘也就是行话讲的Snapshot快照它恢复时是将快照文件直接读到内存里。 Redis会单独创建fork一个子进程来进行持久化会先将数据写入到一个临时文件中待持久化过程都结束了再用这个临时文件替换上次持久化好的文件。整个过程中主进程是不进行任何IO操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复且对于数据恢复的完整性不是非常敏感那 RDB 方式要比 AOF 方式更加的高效。RDB 的缺点是最后一次持久化后的数据可能丢失。我们默认的就是 RDB一般情况下不需要修改这个配置 有时候在生产环境我们会将这个文件进行备份 rdb保存的文件是dump.rdb 都是在我们的配置文件中快照中进行配置的 触发机制 1 、save的规则满足的情况下会自动触发rdb规则 2 、执行 flushall 命令也会触发我们的rdb规则 3 、退出redis也会产生 rdb 文件 备份就自动生成一个 dump.rdb 如何恢复 rdb 文件 1 、只需要将rdb文件放在我们redis启动目录就可以redis启动的时候会自动检查dump.rdb 恢复其中 的数据 2 、查看需要存在的位置 127 .0.0.1:6379 config get dir 1 ) dir 2 ) /usr/local/bin # 如果在这个目录下存在 dump.rdb 文件启动就会自动恢复其中的数据几乎就它自己默认的配置就够用了但是我们还是需要去学习 优点 1 、适合大规模的数据恢复 2 、对数据的完整性要不高 缺点 1 、需要一定的时间间隔进行操作如果redis意外宕机了这个最后一次修改数据就没有的了 2 、fork进程的时候会占用一定的内容空间 10.2 AOFAppend Only File 将我们的所有命令都记录下来history恢复的时候就把这个文件全部在执行一遍 AOF是什么 以日志的形式来记录每个写操作将Redis执行过的所有指令记录下来读操作不记录只许追加文件但不可以改写文件redis启动之初会读取该文件重新构建数据换言之redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作 AOF保存的是 appendonly.aof 文件 默认是不开启的我们需要手动进行配置我们只需要将 appendonly 改为yes就开启了 aof 重启redis 就可以生效了 如果这个 aof 文件有错误这时候 redis 是启动不起来的我们需要修复这个aof文件 redis 给我们提供了一个工具 redis-check-aof --fix 如果文件正常重启就可以直接恢复了 重写规则说明 aof 默认就是文件的无限追加文件会越来越大 如果 aof 文件大于 64m太大了 fork一个新的进程来将我们的文件进行重写 优点 appendonly no # 默认是不开启aof模式的默认是使用rdb方式持久化的在大部分所有的情况下 rdb完全够用 appendfilename appendonly.aof # 持久化的文件的名字# appendfsync always # 每次修改都会 sync。消耗性能 appendfsync everysec # 每秒执行一次 sync可能会丢失这1s的数据 # appendfsync no # 不执行 sync这个时候操作系统自己同步数据速度最快# rewrite 重写1 、每一次修改都同步文件的完整会更加好 2 、每秒同步一次可能会丢失一秒的数据 3 、从不同步效率最高的 缺点 1 、相对于数据文件来说aof 远远大于 rdb修复的速度也比 rdb 慢 2 、Aof 运行效率也要比 rdb 慢所以我们 redis 默认的配置就是rdb持久化 扩展 1 、RDB 持久化方式能够在指定的时间间隔内对你的数据进行快照存储 2 、AOF 持久化方式记录每次对服务器写的操作当服务器重启的时候会重新执行这些命令来恢复原始的数据AOF命令以 Redis 协议追加保存每次写的操作到文件末尾Redis还能对AOF文件进行后台重写使得AOF文件的体积不至于过大。 3 、只做缓存如果你只希望你的数据在服务器运行的时候存在你也可以不使用任何持久化 4 、同时开启两种持久化方式 在这种情况下当redis重启的时候会优先载入AOF文件来恢复原始的数据因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。RDB 的数据不实时同时使用两者时服务器重启也只会找AOF文件那要不要只使用AOF呢作者建议不要因为RDB更适合用于备份数据库AOF在不断变化不好备份快速重启而且不会有AOF可能潜在的Bug留着作为一个万一的手段。 5 、性能建议 因为RDB文件只用作后备用途建议只在Slave上持久化RDB文件而且只要 15 分钟备份一次就够了只保留 save 900 1 这条规则。如果Enable AOF 好处是在最恶劣情况下也只会丢失不超过两秒数据启动脚本较简单只load自 己的AOF文件就可以了代价一是带来了持续的IO二是AOF rewrite 的最后将 rewrite 过程中产 生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可应该尽量减少AOF rewrite 的频率AOF重写的基础大小默认值64M太小了可以设到5G以上默认超过原大小100%大小重写可以改到适当的数值。如果不Enable AOF 仅靠 Master-Slave Repllcation 实现高可用性也可以能省掉一大笔IO也 减少了rewrite时带来的系统波动。代价是如果Master/Slave 同时倒掉会丢失十几分钟的数据 启动脚本也要比较两个 Master/Slave 中的 RDB文件载入较新的那个微博就是这种架构。 11、Redis发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式发送者(pub)发送消息订阅者(sub)接收消息。微信、 微博、关注系统 Redis 客户端可以订阅任意数量的频道。 订阅/发布消息图 第一个消息发送者 第二个频道 第三个消息订阅者 下图展示了频道 channel1 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的 关系 当有新消息通过 PUBLISH 命令发送给频道 channel1 时 这个消息就会被发送给订阅它的三个客户 端 命令 这些命令被广泛用于构建即时通信应用比如网络聊天室(chatroom)和实时广播、实时提醒等。 序号命令及描述1[PSUBSCRIBE pattern pattern …] 订阅一个或多个符合给定模式的频道。2PUBSUB subcommand [argument [argument …]] 查看订阅与发布系统状态。3PUBLISH channel message 将信息发送到指定的频道。4PUNSUBSCRIBE [pattern [pattern …]] 退订所有给定模式的频道。5[SUBSCRIBE channel channel …] 订阅给定的一个或多个频道的信息。6UNSUBSCRIBE [channel [channel …]] 指退订给定的频道。测试 订阅端 127 .0.0.1:6379 subscribe kuangshenshuo # 订阅一个频道 kuangshenshuo Reading messages... (press Ctrl-C to quit) 1 ) subscribe 2 ) kuangshenshuo 3 ) (integer) 1 # 等待读取推送的信息 1 ) message # 消息 2 ) kuangshenshuo # 那个频道的消息 3 ) hello,kuangshen # 消息的具体内容1 ) message 2 ) kuangshenshuo 3 ) hello,redis发送端 127 .0.0.1:6379 publish kuangshenshuo hello,kuangshen # 发布者发布消息到频道 (integer) 1 127 .0.0.1:6379 PUBLISH kuangshenshuo hello,redis # 发布者发布消息到频道 (integer) 1 127 .0.0.1:6379原理 Redis是使用C实现的通过分析 Redis 源码里的 pubsub.c 文件了解发布和订阅机制的底层实现籍此加深对 Redis 的理解。 Redis 通过 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能。 通过 SUBSCRIBE 命令订阅某频道后redis-server 里维护了一个字典字典的键就是一个个 频道而字典的值则是一个链表链表中保存了所有订阅这个 channel 的客户端。SUBSCRIBE 命令的关键就是将客户端添加到给定 channel 的订阅链表中。 通过 PUBLISH 命令向订阅者发送消息redis-server 会使用给定的频道作为键在它所维护的 channel 字典中查找记录了订阅这个频道的所有客户端的链表遍历这个链表将消息发布给所有订阅者。 Pub/Sub 从字面上理解就是发布Publish与订阅Subscribe在Redis中你可以设定对某一个 key值进行消息发布及消息订阅当一个key值上进行了消息发布后所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统比如普通的即时聊天群聊等功能。 使用场景 1 、实时消息系统 2 、实时聊天频道当做聊天室将信息回显给所有人即可 3 、订阅关注系统都是可以的 稍微复杂的场景我们就会使用 消息中间件 MQ 12、Redis主从复制 概念 主从复制是指将一台Redis服务器的数据复制到其他的Redis服务器。前者称为主节点 (master/leader)后者称为从节点(slave/follower)数据的复制是单向的只能由主节点到从节点。 Master以写为主Slave 以读为主。 默认情况下每台Redis服务器都是主节点且一个主节点可以有多个从节点(或没有从节点)但一个从节点只能有一个主节点。 主从复制的作用主要包括 数据冗余主从复制实现了数据的热备份是持久化之外的一种数据冗余方式。故障恢复当主节点出现问题时可以由从节点提供服务实现快速的故障恢复实际上是一种服务的冗余。负载均衡在主从复制的基础上配合读写分离可以由主节点提供写服务由从节点提供读服务即写Redis数据时应用连接主节点读Redis数据时应用连接从节点分担服务器负载尤其是在写少读多的场景下通过多个从节点分担读负载可以大大提高Redis服务器的并发量。高可用集群基石除了上述作用以外主从复制还是哨兵和集群能够实施的基础因此说主从复制是Redis高可用的基础。 一般来说要将Redis运用于工程项目中只使用一台Redis是万万不能的宕机原因如下 从结构上单个Redis服务器会发生单点故障并且一台服务器需要处理所有的请求负载压力较 大从容量上单个Redis服务器内存容量有限就算一台Redis服务器内存容量为256G也不能将所有内存用作Redis存储内存一般来说单台Redis最大使用内存不应该超过20G。 电商网站上的商品一般都是一次上传无数次浏览的说专业点也就是多读少写。 对于这种场景我们可以使如下这种架构 主从复制读写分离 80% 的情况下都是在进行读操作减缓服务器的压力架构中经常使用 一主二从 只要在公司中主从复制就是必须要使用的因为在真实的项目中不可能单机使用Redis 环境配置 127 .0.0.1:6379 info replication # 查看当前库的信息 # Replication role:master # 角色 master connected_slaves:0 # 没有从机 master_replid:b63c90e6c501143759cb0e7f450bd1eb0c70882a master_replid2:0000000000000000000000000000000000000000 master_repl_offset:0 second_repl_offset:-1 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0只配置从库不用配置主库 复制 3 个配置文件然后修改对应的信息 1 、端口 2 、pid文件名字 3 、log文件名字 4 、dump.rdb 文件名字 修改完毕之后启动我们的 3 个redis服务器可以通过进程信息查看ps -ef|grep redis 一主二从 默认情况下每台Redis服务器都是主节点 我们一般情况下只用配置从机就好了 认老大 一主 79 二从 80 81 127.0.0.1:6380 slaveof 127.0.0.1 6379 # SLAVEOF host 6379 找谁当自己的老大 OK 127.0.0.1:6380 info replication # Replication role:slave # 当前角色是从机 master_host:127.0.0.1 # 可以的看到主机的信息 master_port:6379 master_link_status:up master_last_io_seconds_ago:5 master_sync_in_progress:0 slave_repl_offset:14 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:c63801d05f947eb101e2d46cfd8209a41653d49b master_replid2:0000000000000000000000000000000000000000 master_repl_offset:14 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:14# 主机信息 127.0.0.1:6379 info replication # Replication role:master connected_slaves:1 slave0:ip127.0.0.1,port6380,stateonline,offset112,lag1 # 可以看到从机信息 master_replid:c63801d05f947eb101e2d46cfd8209a41653d49b master_replid2:0000000000000000000000000000000000000000 master_repl_offset:112 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:112如果两个都配置完了就是有两个从机的 真实的从主配置应该在配置文件中配置这样的话是永久的我们这里使用的是命令暂时的 细节 主机可以写从机不能写只能读主机中的所有信息和数据都会自动被从机保存 主机写 127.0.0.1:6379 set k1 v1 OK 127.0.0.1:6379 get k1 v1从机只能读 127.0.0.1:6380 keys * 1) k1 127.0.0.1:6380 get k1 v1 127.0.0.1:6380 set k2 v2 (error) READONLY You cant write against a read only replica.测试主机断开连接从机依旧连接到主机的但是没有写操作这个时候主机如果回来了从机依旧可以直接获取到主机写的信息 如果是使用命令行来配置的主从这个时候如果重启了就会变回主机只要变为从机立马就会从主机中获取值 复制原理 Slave 启动成功连接到 master 后会发送一个sync同步命令 Master 接到命令启动后台的存盘进程同时收集所有接收到的用于修改数据集命令在后台进程执行完毕之后master将传送整个数据文件到slave并完成一次完全同步**全量复制**。 全量复制而slave服务在接收到数据库文件数据后将其存盘并加载到内存中。 增量复制Master 继续将新的所有收集到的修改命令依次传给slave完成同步 但是只要是重新连接master一次完全同步**全量复制**将被自动执行 我们的数据一定可以在从机中看到 层层链路 上一个Master链接下一个 Slave 这时候也可以完成我们的主从复制 如果没有老大了这个时候能不能选择一个老大出来呢 手动 谋朝篡位 如果主机断开了连接我们可以使用 slaveof no one 让自己变成主机其他的节点就可以手动连 接到最新的这个主节点手动如果这个时候老大修复了那就重新连接老大 13、哨兵模式 概述 主从切换技术的方法是当主服务器宕机后需要手动把一台从服务器切换为主服务器这就需要人工干预费事费力还会造成一段时间内服务不可用。这不是一种推荐的方式更多时候我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel哨兵 架构来解决这个问题。谋朝篡位的自动版能够后台监控主机是否故障如果故障了根据投票数自动将从库转换为主库。 哨兵模式是一种特殊的模式首先Redis提供了哨兵的命令哨兵是一个独立的进程作为进程它会独立运行。其原理是 哨兵通过发送命令等待Redis服务器响应从而监控运行的多个Redis实例。 这里的哨兵有两个作用 通过发送命令让Redis服务器返回监控其运行状态包括主服务器和从服务器。当哨兵监测到master宕机会自动将slave切换成master然后通过 发布订阅模式 通知其他的从服务器修改配置文件让它们切换主机。 然而一个哨兵进程对Redis服务器进行监控可能会出现问题为此我们可以使用多个哨兵进行监控。 各个哨兵之间还会进行监控这样就形成了多哨兵模式。 假设主服务器宕机哨兵 1 先检测到这个结果系统并不会马上进行failover过程仅仅是哨兵 1 主观的认为主服务器不可用这个现象成为 主观下线 。当后面的哨兵也检测到主服务器不可用并且数量达到一定值时那么哨兵之间就会进行一次投票投票的结果由一个哨兵发起进行failover[故障转移]操作。切换成功后就会通过发布订阅模式让各个哨兵把自己监控的从服务器实现切换主机这个过程称为客观下线 。 测试 我们目前的状态是 一主二从 1 、配置哨兵配置文件 sentinel.conf 后面的这个数字 1 代表主机挂了slave投票看让谁接替成为主机票数最多的就会成为主机 # sentinel monitor 被监控的名称 host port 1 sentinel monitor myredis 127.0.0.1 6379 12 、启动哨兵 [rootLinux-xu bin]# redis-sentinel RedisConfig/sentinel.conf 61063:X 27 Jul 2020 17:17:09.768 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 61063:X 27 Jul 2020 17:17:09.768 # Redis version5.0.8, bits64, commit00000000, modified0, pid61063, just started 61063:X 27 Jul 2020 17:17:09.768 # Configuration loaded 61063:X 27 Jul 2020 17:17:09.770 * Increased maximum number of open files to 10032 (it was originally set to 1024)._._ _.-__ -._ _.- . _. -._ Redis 5.0.8 (00000000/0) 64 bit.- .-. \/ _.,_ -._ ( , .- | , ) Running in sentinel mode|-._-...- __...-.-._| _.-| Port: 26379| -._ ._ / _.- | PID: 61063-._ -._ -./ _.- _.- |-._-._ -.__.- _.-_.-| | -._-._ _.-_.- | http://redis.io -._ -._-.__.-_.- _.- |-._-._ -.__.- _.-_.-| | -._-._ _.-_.- | -._ -._-.__.-_.- _.- -._ -.__.- _.- -._ _.- -.__.- 61063:X 27 Jul 2020 17:17:09.772 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. 61063:X 27 Jul 2020 17:17:09.774 # Sentinel ID is 40074a476dbe27d420e78ec7eac1ba0b6d5266cb 61063:X 27 Jul 2020 17:17:09.774 # monitor master myredis 127.0.0.1 6379 quorum 1 61063:X 27 Jul 2020 17:17:09.783 * slave slave 127.0.0.1:6381 127.0.0.1 6381 myredis 127.0.0.1 6379 61063:X 27 Jul 2020 17:17:09.786 * slave slave 127.0.0.1:6380 127.0.0.1 6380 myredis 127.0.0.1 6379如果Master 节点断开了这个时候就会从从机中随机选择一个服务器 这里面有一个投票算法 如果主机此时回来了只能归并到新的主机下当做从机这就是哨兵模式的规则 哨兵模式 优点 哨兵集群基于主从复制模式所有的主从配置优点它全有主从可以切换故障可以转移系统的可用性就会更好哨兵模式就是主从模式的升级手动到自动更加健壮 缺点 Redis 不好在线扩容集群容量一旦到达上限在线扩容就十分麻烦实现哨兵模式的配置其实是很麻烦的里面有很多选择 哨兵模式的全部配置 # Example sentinel.conf # 哨兵sentinel实例运行的端口 默认 26379 port 26379 # 多个哨兵集群就得配置端口# 哨兵sentinel的工作目录 dir /tmp# 哨兵sentinel监控的redis主节点的 ip port # master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符.-_组成。 # quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了 # sentinel monitor master-name ip redis-port quorum sentinel monitor mymaster 127 .0.0.1 6379 2# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码 # 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码 # sentinel auth-pass master-name password sentinel auth-pass mymaster MySUPER--secret-0123passw0rd# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认 30 秒 # sentinel down-after-milliseconds master-name milliseconds sentinel down-after-milliseconds mymaster 30000# 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步这个数字越小完成failover所需的时间就越长但是如果这个数字越大就意味着越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。 # sentinel parallel-syncs master-name numslaves sentinel parallel-syncs mymaster 1# 故障转移的超时时间 failover-timeout 可以用在以下这些方面 #1. 同一个sentinel对同一个master两次failover之间的间隔时间。 #2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。 #3.当想要取消一个正在进行的failover所需要的时间。 #4.当进行failover时配置所有slaves指向新的master所需的最大时间。不过即使过了这个超时slaves依然会被正确配置为指向master但是就不按parallel-syncs所配置的规则来了 # 默认三分钟 # sentinel failover-timeout master-name milliseconds sentinel failover-timeout mymaster 180000# SCRIPTS EXECUTION #配置当某一事件发生时所需要执行的脚本可以通过脚本来通知管理员例如当系统运行不正常时发邮件通知 相关人员。 #对于脚本的运行结果有以下规则 #若脚本执行后返回 1 那么该脚本稍后将会被再次执行重复次数目前默认为 10 #若脚本执行后返回 2 或者比 2 更高的一个返回值脚本将不会重复执行。 #如果脚本在执行过程中由于收到系统中断信号被终止了则同返回值为 1 时的行为相同。 #一个脚本的最大执行时间为60s如果超过这个时间脚本将会被一个SIGKILL信号终止之后重新执行。 #通知型脚本:当sentinel有任何警告级别的事件发生时比如说redis实例的主观失效和客观失效等等将会去调用这个脚本这时这个脚本应该通过邮件SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时将传给脚本两个参数一个是事件的类型一个是事件的描述。如果sentinel.conf配置文件中配置了这个脚本路径那么必须保证这个脚本存在于这个路径并且是可执行的否则sentinel无法正常启动成功。 #通知脚本 # shell编程 # sentinel notification-script master-name script-path sentinel notification-script mymaster /var/redis/notify.sh# 客户端重新配置主节点参数脚本 # 当一个master由于failover而发生改变时这个脚本将会被调用通知相关的客户端关于master地址已经发生改变的信息。 # 以下参数将会在调用脚本时传给脚本: # master-name role state from-ip from-port to-ip to-port # 目前state总是“failover”, # role是“leader”或者“observer”中的一个。 # 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的 # 这个脚本应该是通用的能被多次调用不是针对性的。 # sentinel client-reconfig-script master-name script-path sentinel client-reconfig-script mymaster /var/redis/reconfig.sh # 一般都是由运维来配置14、Redis缓存穿透和雪崩 服务的高可用问题 在这里我们不会详细的区分析解决方案的底层 Redis缓存的使用极大的提升了应用程序的性能和效率特别是数据查询方面。但同时它也带来了一些问题。其中最要害的问题就是数据的一致性问题从严格意义上讲这个问题无解。如果对数据的一致性要求很高那么就不能使用缓存。 另外的一些典型问题就是缓存穿透、缓存雪崩和缓存击穿。目前业界也都有比较流行的解决方案。 14.1 缓存穿透查不到 概念 缓存穿透的概念很简单用户想要查询一个数据发现redis内存数据库没有也就是缓存没有命中于是向持久层数据库查询。发现也没有于是本次查询失败。当用户很多的时候缓存都没有命中秒杀于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力这时候就相当于出现了缓存穿透。 解决方案 布隆过滤器 布隆过滤器是一种数据结构对所有可能查询的参数以hash形式存储在控制层先进行校验不符合则丢弃从而避免了对底层存储系统的查询压力 缓存空对象 当存储层不命中后即使返回的空对象也将其缓存起来同时会设置一个过期时间之后再访问这个数据将会从缓存中获取保护了后端数据源 但是这种方法会存在两个问题 1 、如果空值能够被缓存起来这就意味着缓存需要更多的空间存储更多的键因为这当中可能会有很多的空值的键 2 、即使对空值设置了过期时间还是会存在缓存层和存储层的数据会有一段时间窗口的不一致这对于需要保持一致性的业务会有影响。 14.2 缓存击穿量太大缓存过期 概述 这里需要注意和缓存击穿的区别缓存击穿是指一个key非常热点在不停的扛着大并发大并发集中对这一个点进行访问当这个key在失效的瞬间持续的大并发就穿破缓存直接请求数据库就像在一个屏障上凿开了一个洞。 当某个key在过期的瞬间有大量的请求并发访问这类数据一般是热点数据由于缓存过期会同时访问数据库来查询最新数据并且回写缓存会导使数据库瞬间压力过大。 解决方案 设置热点数据永不过期 从缓存层面来看没有设置过期时间所以不会出现热点 key 过期后产生的问题。 加互斥锁 分布式锁使用分布式锁保证对于每个key同时只有一个线程去查询后端服务其他线程没有获得分布式锁的权限因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁因此对分布式锁的考验很大。 14.3 缓存雪崩 概念 缓存雪崩是指在某一个时间段缓存集中过期失效。Redis 宕机 产生雪崩的原因之一比如在写本文的时候马上就要到双十二零点很快就会迎来一波抢购这波商品时间比较集中的放入了缓存假设缓存一个小时。那么到了凌晨一点钟的时候这批商品的缓存就都过期了。而对这批商品的访问查询都落到了数据库上对于数据库而言就会产生周期性的压力波峰。于是所有的请求都会达到存储层存储层的调用量会暴增造成存储层也会挂掉的情况。 其实集中过期倒不是非常致命比较致命的缓存雪崩是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩一定是在某个时间段集中创建缓存这个时候数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机对数据库服务器造成的压力是不可预知的很有可能瞬间就把数据库压垮。 解决方案 redis高可用 这个思想的含义是既然redis有可能挂掉那我多增设几台redis这样一台挂掉之后其他的还可以继续工作其实就是搭建的集群。异地多活 限流降级在SpringCloud讲解过 这个解决方案的思想是在缓存失效后通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存其他线程等待。 数据预热 数据加热的含义就是在正式部署之前我先把可能的数据先预先访问一遍这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key设置不同的过期时间让缓存失效的时间点尽量均匀。
http://www.zqtcl.cn/news/467179/

相关文章:

  • app官网入口昆明排名优化
  • 新乡网站建设开发wordpress如何添加一个文章列表页
  • 中国3大做外贸的网站seo建站营销
  • 建站免费加盟高台县建设局网站
  • 网站联盟推广江门提供网站制作平台
  • 百度上面如何做网站asp源码下载
  • 婚庆网站的设计意义网站规格
  • 网站收录率嘉兴网站开发公司
  • 优秀的设计网站不备案 没版权 网站
  • 建设 互动 网站 模式网络营销模式不是孤立存在的
  • 怡梦姗网站做么上海21世纪人才网官网登录
  • 家政网站建设方案分析哈尔滨做网站找哪家好
  • 如何建设论坛网站营销宣传策划方案
  • 企业网站推广排名技术网
  • 网站建设网页设计培训学校延边网站建设
  • 自己做网站需要的技术个人简历表格下载
  • 做网站建设小程序ukidc做电影网站
  • 网站内容分析软文范例100字
  • 网站建站策划用vs做网站
  • 如何建自己的网站做农村电子商务的网站有哪些内容
  • 手机销售网站设计怎么推广软件让别人下载
  • 贵州三蒲建设工程有限公司网站莱阳网站制作
  • 外贸买家网站适合初学者模仿的网站
  • 安徽蚌埠怀远县建设局网站米卓网站建设
  • 网站框架怎么建设微信旧版本下载
  • 速贝网站友情链接怎么做企业网站开发的设计流程
  • 网站建设 安庆网站开发免责合同
  • 天津深圳网站开发定制网络工程考研方向
  • 做app网站的公司哪家好济南网站建设市场
  • 自己做网站页面网站国内空间和国外空间