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

php做的直播网站自适应网站好建们

php做的直播网站,自适应网站好建们,wordpress升级提示文件流的目标,免费注册网址文章目录 狂神聊Redis1、Nosql概述1.1、为什么要用Nosql1.2、什么是NoSQL1.3、NoSQL的四大分类 2、Redis 入门2.1、概述2.2、Windows 安装2.3、Linux安装2.4、测试性能2.5、Redis基础知识 3、五大基本数据类型3.1、Redis-Key3.2、String3.3、List3.4、Set3.5、Hash#xff08;… 文章目录 狂神聊Redis1、Nosql概述1.1、为什么要用Nosql1.2、什么是NoSQL1.3、NoSQL的四大分类 2、Redis 入门2.1、概述2.2、Windows 安装2.3、Linux安装2.4、测试性能2.5、Redis基础知识 3、五大基本数据类型3.1、Redis-Key3.2、String3.3、List3.4、Set3.5、Hash哈希3.6、Zset有序集合 4、三种特殊数据类型4.1、Geospatial4.2、Hyperloglog4.3、Bitmap 5、事务6、Jedis6.1、什么是 Jedis6.2、Jedis连接Redis6.3、常用的API 7、SpringBoot整合8、Redis.con详解9、Redis 持久化9.1、RDB Redis DataBase9.2、AOFAppend Only File Redis 实现订阅发布10、Redis 主从复制10.1、基本概念10.2、环境配置10.3、一主二从10.4、哨兵模式 11、Redis缓存穿透和雪崩11.1、缓存穿透查不到导致的10.2、缓存击穿量太大缓存过期10.3、缓存雪崩 狂神聊Redis 五大基本数据类型 StringListSetHashZset 三种特殊数据类型 geohyperloglogbitmap Redis 配置详解Redis 持久化 RDBAOF Redis 事务操作Redis 实现订阅发布Redis 主从复制Redis 哨兵模式现在公司中所有的集群都用哨兵模式缓存穿透及解决方案缓存击穿及解决方案缓存雪崩及解决方案 1、Nosql概述 1.1、为什么要用Nosql 以下为发展历程~ 单机MySQL年代 90年代单个数据库完全足够 那个时候都是静态网页Html~服务器没有太大压力 思考整个网站的瓶颈是什么 数据量太大一个机器放不下数据的索引B树一个机器内存放不下访问量读写混合一个服务器承受不了~ 只要开始出现以上的三种情况之一那么就必须升级 Memcached 缓存 MySQL 垂直拆分读写分离 网站 80% 都是在读每次去查数据库很麻烦为了减轻数据库的压力我们希望使用缓存来保证效率 发展过程优化数据结构和索引— 文件缓存IO—Memcached 当时最热门的技术 3、分库分表 水平拆分 MySQL集群 技术和业务在发展的同时对人的要求也越来越高 本质数据库读、写 早些年 MyISAM表锁表锁是锁住整张表所以可以避免死锁。不过最大的负面问题是锁竞争概率最高。并发性最差。 十分影响效率高并发下回出现严重的锁问题 转战 InnoDB行锁也称为记录锁mysql服务层没有实现行锁机制行锁只存在存储引擎层实现。 文件读写方式发生了变化慢慢的就开始使用分库分表来解决写的压力 MySQL当年还推出了 表分区 和 集群~ 4、如今最近的年代 2010–2020 十年之间世界发生了翻天覆地的变化定位也是一种数据音乐热榜 MySQL等关系型数据库不够用了数据量很大变化很快 MySQL有的使用它来存储一些比较大的文件博客图片数据库表很大效率就低了 目前互联网基本架构模型 为什么要用NoSQL 用户的个人信息社交网络地理位置用户让自己产生数据用户日志等爆发时增长 这时候就需要使用 NoSQL 数据库的NoSQL可以很好的处理以上的情况 1.2、什么是NoSQL NoSQL Not only SQL不仅仅是SQL 关系型数据库表格行列 泛指非关系型数据库随着web2.0互联网的诞生传统的关系型数据库很难对付web2.0时代 MapString, Object NoSQL 特点 方便扩展数据之间没有关系很好扩展大数据量高性能Redis 一秒写8万次读取11万次数据类型是多样型的不需要事先设计数据库随去随用如果是数据量十分大的表很多人就无法设计了 Mongdb文档存储 # 1、商品的基本信息 名称、价格、商家信息# 2、商品的描述、评论文字比较多文档型数据库MongoDB# 3、图片分布式文件系统FastDFS # 我现在用的- 淘宝自己的 TFS- Google GFS- Hadoop HDFS- 阿里云的 OSS# 4、商品的关键字搜索- 搜索引擎 solr ElasticSearch- ISearch : 多隆# 5、商品热门的波段信息- 内存数据库- Redis、Tair、Memcache...# 6、商品的交外部的支付接口- 三方应用 1.3、NoSQL的四大分类 KV键值对 新浪Redis美团Redis Tair阿里百度Redis Memcache 文档型数据库bson格式和json一样: MongoDB一般必须掌握 MongoDB 是一个基于分布式文件存储的数据库C编写主要用来处理大量的文档MongoDB是一个介于关系型数据库和非关系型数据库中间的产品MongoDB是非关系型数据库中功能最丰富最像关系型数据库的 列存储数据库 HBase分布式文件系统 图形Graph数据库 Neo4jInfoGrid这个不是存图形放的是关系比如朋友圈社交网络广告推荐 2、Redis 入门 2.1、概述 Remote Dictionary Server )即远程字典服务 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库并提供多种语言的API。 redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件并且在此基础上实现了master-slave(主从)同步。也被称为 结构化数据库 Redis 能干吗 内存存储、持久化内存是断电即失所以说持久化很重要RDB、AOF效率高可以用于高速缓存发布订阅系统地图信息分析计时器、计数器浏览量… 特性 多样的数据类型持久化集群事务 Redis 下载 狂神的公众号狂神说官网https://redis.io/中文网http://www.redis.cn/Windows 在github上下载 Redis 推荐都是在Linux服务器上搭建的我们是基于Linux学习的 2.2、Windows 安装 下载安装包https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100 下载完毕解压即可 解压到自己电脑上的环境目录下即可Redis非常小 开启redis双击运行服务即可 注如果双击闪退那就在安装目录下执行如下命令即可 redis-server.exe redis.windows.conf使用redis客户端来连接redis 推荐使用 Linux开发 2.3、Linux安装 下载安装包 2.4、测试性能 redis-benchmark 是一个压力测试工具 官方自带的性能测试工具 redis-benchmark 命令参数 图片来源https://www.runoob.com/redis/redis-benchmarks.html 一个简单的测试 # 测试100个并发连接 10万个请求 redis-benchmark -h localhost -p 6379 -c 100 -n 100000如何查看这些分析 2.5、Redis基础知识 redis默认有16个数据库默认使用的是第 0 个 可以使用select 进行切换数据库 127.0.0.1:6379 select 3 # 切换数据库 OK 127.0.0.1:6379[3] DBSIZE # 查看 db 大小 (ingeter) 0清除当前数据库flushdb 127.0.0.1:6379[3] flushdb OK 127.0.0.1:6379[3] keys * (empty list or set)清除全部数据库的内容flushall 127.0.0.1:6379[3] FLUSHALL OK 127.0.0.1:6379[3] keys * (empty list or set)思考为什么Redis是 6379粉丝效应 Redis 是单线程的 明白 Redis 是很快的官方表示Redis是基于内存操作CPU不是Redis性能瓶颈Redis的瓶颈是根据机器的内存和网络带宽既然可以使用单线程实现就使用单线程了所以就使用单线程了 Redis 是 C 语言写的官方提供的数据为 100000 的QPS完全不比同样是使用 key-value 的Memcache差 Redis 为什么单线程还这么快 误区1高性能的服务器一定是多线程的 误区2多线程CPU上下文切换耗费资源一定比单线程效率高 先对 CPU 内存 硬盘的速度有了解 核心Redis 是将所有的数据都放到内存中的所以说使用单线程操作效率是最高的多线程上下文会切换耗时的操作对于内存系统来说如果没有上下文切换效率就是最高的多次读写都是在一个CPU上的在内存情况下这个就是最佳方案 3、五大基本数据类型 Redis 是一个开源BSD许可的内存中的数据结构存储系统它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构如 字符串strings 散列hashes 列表lists 集合sets 有序集合sorted sets 与范围查询 bitmaps hyperloglogs 和 地理空间geospatial 索引半径查询。 Redis 内置了 复制replicationLUA脚本Lua scripting LRU驱动事件LRU eviction事务transactions 和不同级别的 磁盘持久化persistence 并通过 Redis哨兵Sentinel和自动 分区Cluster提供高可用性high availability。 命令要牢牢记住 3.1、Redis-Key 127.0.0.1:6379 keys * # 查看所有的key (empty list or set) 127.0.0.1:6379 set name Arbicoral # set key OK 127.0.0.1:6379 keys * 1) name 127.0.0.1:6379 set age 5 OK 127.0.0.1:6379 keys * 1) name 2) age 127.0.0.1:6379 exists name # 判断当前的key (integer) 1 127.0.0.1:6379 exists name1 (integer) 0 127.0.0.1:6379 keys * 1) name 2) age 127.0.0.1:6379 move name1 (error) ERR wrong number of arguments for move command 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 Arbicoral OK 127.0.0.1:6379 keys * 1) name 2) age 127.0.0.1:6379 get name Arbicoral 127.0.0.1:6379 expire name 10 # 设置key的过期时间单位是秒 (integer) 1 127.0.0.1:6379 ttl name # 查看key的剩余时间 (integer) 7 127.0.0.1:6379 ttl name (integer) 3 127.0.0.1:6379 ttl name (integer) -2 127.0.0.1:6379 get name (nil) 127.0.0.1:6379 type age string 127.0.0.1:6379 type name none 127.0.0.1:6379 keys * 1) age 127.0.0.1:6379 set name Arbicoral OK 127.0.0.1:6379 type name # 查看当前key的类型 string 127.0.0.1:6379 keys * 1) name 2) age3.2、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) name 2) key1 3) age 127.0.0.1:6379 append key1 hello # 追加字符串如果当前key不存在就相当于set key (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 Arbicoral (integer) 16 127.0.0.1:6379 strlen key1 (integer) 16 127.0.0.1:6379 get key1 v1helloArbicoral############################################################## # i # 步长 i127.0.0.1:6379 set views 0 # 初始浏览量0 OK 127.0.0.1:6379 get viewa (nil) 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 get views 1 127.0.0.1:6379 incrby views 10 # 可以设置步长指定增量 (integer) 11 127.0.0.1:6379 decrby views 5 (integer) 6 127.0.0.1:6379 get views 6############################################################## # 字符串范围 range 127.0.0.1:6379 keys * (empty list or set) 127.0.0.1:6379 set key1 hello,Arbicoral # 设置key1的值 OK 127.0.0.1:6379 get key1 hello,Arbicoral 127.0.0.1:6379 getrange key1 0 3 # 截取字符串[0,3] hell 127.0.0.1:6379 getrange key1 0 -1 # 获取全部的字符串 和 get key 是一样的 hello,Arbicoral############################################################## # 替换 127.0.0.1:6379 keys * (empty list or set) 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 OK 127.0.0.1:6379 ttl key3 (integer) 25 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) mykey 2) key1 3) key2 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 mget127.0.0.1:6379 keys * (empty list or set) 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 mset k1 v1 k4 v4 OK 127.0.0.1:6379 keys * 1) k3 2) k2 3) k4 4) k1 127.0.0.1:6379 msetnx k1 v2 k5 v5 # msetnx 是一个原子性的操作要么一起成功要么一起失败 (integer) 0 127.0.0.1:6379 get k5 (nil)############################################################## # 对象 set user:1 {name:Arbicoral,age:6} # 设置一个 user:1 对象值为 json 字符来保存一个对象# 这里的Key是一个巧妙的设计 user:{id}:{filed}如此设计在Redis中是完全ok的127.0.0.1:6379 mset user:1:name Arbicoral user:1:age 6 OK 127.0.0.1:6379 mget user:1:name user:1:age 1) Arbicoral 2) 6############################################################## getset # 先 get 再 set127.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数据结构是相同的 计数器统计多单位的数量 3.3、List 基本的数据类型列表 在 Redis中我们可以将 List 玩成 栈、队列、阻塞队列 所有的 list 命令都是用 l 开头的 Redis 不区分大小写命令 ############################################################## LPUSH RPUSH127.0.0.1:6379 keys * (empty list or set) 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 1 3 # 获取list中的值 1) two 2) one 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 right # 将一个值或者多个值插入到列表尾部对应上图的右 (integer) 4 127.0.0.1:6379 lrange list 0 -1 1) three 2) two 3) one 4) right############################################################## LPOP RPOP127.0.0.1:6379 lrange list 0 -1 1) three 2) two 3) one 4) right 127.0.0.1:6379 lpop list # 移除List的第一个元素 three 127.0.0.1:6379 rpop list # 移除List的最后一个元素 right 127.0.0.1:6379 lrange list 0 -1 1) two 2) one############################################################## LINDEX RINDEX127.0.0.1:6379 lrange list 0 -1 1) two 2) one 127.0.0.1:6379 lindex list 0 # 通过下标获得 list 中的某一个值 two 127.0.0.1:6379 lindex list -1 one############################################################## LLEN127.0.0.1:6379 keys * (empty list or set) 127.0.0.1:6379 lpush list onr (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############################################################## 移除指定的值 取关 uidLrem127.0.0.1:6379 lrange list 0 -1 1) three 2) three 3) two 4) onr 127.0.0.1:6379 lrem list 1 onr # 移除list中指定个数的value精确匹配 (integer) 1 127.0.0.1:6379 lrem list 1 three (integer) 1 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############################################################## trim 修剪 list 截断127.0.0.1:6379 keys * (empty list or set) 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 list 1 2 OK 127.0.0.1:6379 ltrim mylist 1 2 # 通过下标截取指定的长度这个list已经被改变了截断了只剩下截取的元素 OK 127.0.0.1:6379 lrange mylist 0 -1 1) hello1 2) hello2############################################################## rpoplpush # 移除列表的最后一个元素将它移动到新的列表中127.0.0.1:6379 keys * (empty list or set) 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 # 查看原来的list 1) hello 2) hello1 127.0.0.1:6379 lrange myotherlist 0 -1 # 查看目标列表确实存在该值 1) hello2############################################################## lset # 将List中指定下标中的值替换为另一个指定的值更新操作127.0.0.1:6379 exists list # 判断list是否存在 (integer) 0 127.0.0.1:6379 lset list 0 item # 如果不存在list我们去更新就会报错 (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############################################################## linsert # 将某个具体的value插入到list中某个元素的前面或者后面127.0.0.1:6379 rpush list hello (integer) 1 127.0.0.1:6379 rpush list hello1 (integer) 2 127.0.0.1:6379 rpush list hello2 (integer) 3 127.0.0.1:6379 linsert list before hello1 other # 插入到前面 (integer) 4 127.0.0.1:6379 lrange list 0 -1 1) hello 2) other 3) hello1 4) hello2 127.0.0.1:6379 linsert list after other new # 插入到后面 (integer) 5 127.0.0.1:6379 lrange list 0 -1 1) hello 2) other 3) new 4) hello1 5) hello2小结 实际上是一个链表before Node after left right如果 key不存在创建新的链表如果 key存在新增内容如果移除了所有的值空链表也代表不存在在两边插入获改动值效率最高中间元素相对来说效率会低一点 消息队列Lpush 、Rpop、 栈 Lpush 、Lpop 3.4、Set set 的值不能重复 ##############################################################127.0.0.1:6379 sadd myset hello # set 几个中添加元素 (integer) 1 127.0.0.1:6379 sadd myset Arbicoral (integer) 1 127.0.0.1:6379 sadd myset come on (integer) 1 127.0.0.1:6379 smembers myset # 查看指定 set 的所有值 1) come on 2) Arbicoral 3) hello 127.0.0.1:6379 sismember myset hello # 判断某一个值是不是在 set 中 (integer) 1 127.0.0.1:6379 sismember myset world (integer) 0##############################################################127.0.0.1:6379 scard myset # 获取 set 中内容得元素个数 (integer) 3############################################################## 127.0.0.1:6379 srem myset hello # 移除 set中得某个值 (integer) 1 127.0.0.1:6379 scard myset (integer) 2 127.0.0.1:6379 smembers myset 1) come on 2) Arbicoral############################################################## set 无序 不重复集合 127.0.0.1:6379 srandmember myset # 随机抽选出一个元素 come on 127.0.0.1:6379 srandmember myset come on 127.0.0.1:6379 srandmember myset Arbicoral 127.0.0.1:6379 srandmember myset 2 # 随机抽选出指定元素得个数 1) Arbicoral 2) come on############################################################## 删除指定的 key 随机删除key 127.0.0.1:6379 smembers myset 1) class 2) key 3) come on 4) Arbicoral 127.0.0.1:6379 spop myset # 随机删除set中的元素 class 127.0.0.1:6379 spop myset Arbicoral 127.0.0.1:6379 smembers myset 1) key 2) come on############################################################## 将一个指定的值移动到另外一个set中127.0.0.1:6379 sadd set1 hello (integer) 1 127.0.0.1:6379 sadd set1 world (integer) 1 127.0.0.1:6379 sadd set1 cotton (integer) 1 127.0.0.1:6379 sadd set2 test (integer) 1 127.0.0.1:6379 smove set1 set2 hello # 将一个指定的值运动到另一个set中 (integer) 1 127.0.0.1:6379 smembers set2 1) test 2) hello 127.0.0.1:6379 smembers set1 1) cotton 2) world############################################################## 微博、B站、共同关注 数字集合类 - 差集 - 并集 - 交集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) b 2) a 3) d 4) e 5) c##############################################################微博A用户将所有关注的人放在一个 set中将它的粉丝也放在一个set中 共同关注共同爱好二度好友~六度分隔理论 3.5、Hash哈希 Map集合key-map这个值是Map集合 本质和 String类型没有太大区别还是一个简单的key-value! set myhash field Arbicoral 127.0.0.1:6379 hset myhash field1 Arbicoral # set一个具体的key-value (integer) 1 127.0.0.1:6379 hget myhash field1 # 获取一个字段值 Arbicoral 127.0.0.1:6379 hmset myhash field1 hello field2 world # set多个具体的key-value 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############################################################## hlen 127.0.0.1:6379 hmset myhash f1 hello f2 world OK 127.0.0.1:6379 hgetall myhash 1) f1 2) hello 3) f2 4) world 127.0.0.1:6379 hlen myhash # 获取hash表的字段数量 (integer) 2##############################################################127.0.0.1:6379 hexists myhash f1 # 判断hash中的某个字段是否存在 (integer) 1 127.0.0.1:6379 hexists myhahs f3 (integer) 0############################################################## # 只获得所有的 field # 只获得所有的 value 127.0.0.1:6379 hkeys myhash # 只获得所有的 field 1) f1 2) f2 127.0.0.1:6379 hvals myhash # 只获得所有的 value 1) hello 2) world##############################################################127.0.0.1:6379 hset myhash f3 5 (integer) 1 127.0.0.1:6379 hincrby myhash f3 1 # 设置增量 (integer) 6 127.0.0.1:6379 hincrby myhash f3 -1 (integer) 5 127.0.0.1:6379 hsetnx myhash f4 hello # 如果不存在则可以设置 (integer) 1 127.0.0.1:6379 hsetnx myhash f4 world # 如果存在则不可以设置 (integer) 0 哈希变更的数据尤其是用户信息之类的和经常变动的信息 hash更适合对象的存储 String更适合字符串存储。 3.6、Zset有序集合 在set 基础上加了一个值 表示等级 ############################################################## # set k1 v1 # zset k1 score v1 会设置一个分数表示等级 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 zadd salary 2000 xiaohong # 添加三个用户 (integer) 1 127.0.0.1:6379 zadd salary 5000 lihua (integer) 1 127.0.0.1:6379 zadd salary 500 kuangshen (integer) 1 # 语法ZRANGEBYLEX key min max [LIMIT offset count] 最小到最大 127.0.0.1:6379 zrangebyscore salary -inf inf # 显示全部用户从小到大 1) kuangshen 2) xiaohong 3) lihua 127.0.0.1:6379 zrevrange salary 0 -1 withscores # 显示全部用户从大到小注意是 zrevrange 1) lihua 2) 5000 3) kuangshen 4) 500 127.0.0.1:6379 zrangebyscore salary -inf inf withscores # 显示全部用户并附带成绩 1) kuangshen 2) 500 3) xiaohong 4) 2000 5) lihua 6) 5000 127.0.0.1:6379 zrangebyscore salary -inf 2500 withscores # 显示工资小于2500的员工升序排序 1) kuangshen 2) 500 3) xiaohong 4) 2000############################################################## # 移除rem中的元素127.0.0.1:6379 zrange salary 0 -1 1) kuangshen 2) xiaohong 3) lihua 127.0.0.1:6379 zrem salary xiaohong # 移除有序集合中指定的元素 (integer) 1 127.0.0.1:6379 zrange salary 0 -1 1) kuangshen 2) lihua 127.0.0.1:6379 zcard salary # 获取集合中的个数 (integer) 2############################################################## # 获取指定区间的成员数量127.0.0.1:6379 zadd myset 1 hello 2 world 3 Arbicoral (integer) 3 127.0.0.1:6379 zcount myset 1 3 # 获取指定区间的成员数量 (integer) 3 127.0.0.1:6379 zcount myset 1 2 (integer) 2############################################################## ##############################################################其他API去官方文档查找即可 案例思路set 排序 存储班级成绩工资表排序 普通消息score设置为 1重要消息设置为 2带权重进行判断 再如 排行榜应用实现取 top N 实现 4、三种特殊数据类型 4.1、Geospatial 地理位置 Redis 的 Geo 在 Redis 3.2版本就推出了该功能可以推算地理位置的信息两地之间的距离方圆几公里的人 可以查询一些测试数据https://jingweidu.bmcx.com/ 只有6个命令 GEOADDGEODISTGEOHASHGEOPOSGEORADIUSGEORADIUSBYMEMBER geoadd # geoadd 添加地理位置 # 规则两极无法直接添加一般会下载城市数据直接通过Java程序一次性导入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.40 chongqing (integer) 1 127.0.0.1:6379 geoadd china:city 120.21 30.208 hangzhou (integer) 1 127.0.0.1:6379 geoadd china:city 108.93 34.23 xian (integer) 1 127.0.0.1:6379 geoadd china:city 104.101 30.65 chengdu 113.64 34.72 zhengzhou (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 chengdu 1) 1) 116.399998962879180912) 39.90000009167092543 2) 1) 104.100997745990753172) 30.6499990746355806GEODIST返回两个给定位置之间的距离。 如果两个位置之间的其中一个不存在 那么命令返回空值。 单位 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 # 查看重庆到北京的直线距离 1475.8813georadius 以给定的经纬度为中心 返回键包含的位置元素当中 与中心的距离不超过给定最大距离的所有位置元素 我附近的人获得附近所有人的地址定位通过半径来查询 获得指定数量的人最多500 所有的城市都录入到 china:city才会让结果更加精确 127.0.0.1:6379 georadius china:city 110 30 1000 km # 以110 30经纬度为中心寻找1000km内的城市 1) chongqing 2) chengdu 3) xian 4) hangzhou 5) zhengzhou 127.0.0.1:6379 georadius china:city 110 30 500 km 1) chongqing 2) xian 127.0.0.1:6379 georadius china:city 110 30 500 km withcoord # 显示他人的定位信息 1) 1) chongqing2) 1) 106.499997675418853762) 29.39999880018641676 2) 1) xian2) 1) 108.929998576641082762) 34.23000121926852302 127.0.0.1:6379 georadius china:city 110 30 500 km withcoord withdist count 1 # 筛选出指定得结果 1) 1) chongqing2) 344.65833) 1) 106.499997675418853762) 29.39999880018641676 127.0.0.1:6379 georadius china:city 110 30 500 km withdist # 显示到中间距离的位置 1) 1) chongqing2) 344.6583 2) 1) xian2) 481.1540georadiusbymember # 找出位于指定元素周围的其他元素 127.0.0.1:6379 georadiusbymember china:city beijing 1000 km 1) zhengzhou 2) beijing 3) xian 127.0.0.1:6379 georadiusbymember china:city beijing 300 km 1) beijinggeohash返回一个或多个位置元素的11个字符的Geohash字符串 # 将二维的经纬度转换为一维的字符串如果两个字符串越接近则距离越接近 127.0.0.1:6379 geohash china:city beijing chongqing 1) wx4fbxxfke0 2) wm5xr2ngmv0GEO 的底层实现原理就是 Zset 127.0.0.1:6379 zrange china:city 0 -1 # 查看地图中的全部元素 1) chongqing 2) chengdu 3) xian 4) hangzhou 5) shanghai 6) zhengzhou 7) 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) chengdu 3) xian 4) hangzhou 5) shanghai 6) zhengzhou4.2、Hyperloglog 什么是基数 — A{1,3,5,7,8,7} B{1,3,5,7,8} 基数 找不重复的元素51,3,5,7,8可以接受误差 简介 Redis Hyperloglog 基数统计的算法 网页的 UV 一个人访问一个网站多次但还算做一个人 优点占用的内存是固定的2^64不同的元素的技术只需用 12KB 内存如果从内存角度来比较的话 Hyperloglog首选 官方说有 0.81% 的错误率 测试使用 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 mykey q w e r (integer) 1 127.0.0.1:6379 pfcount mykey (integer) 13 127.0.0.1:6379 pfadd mykey2 v g d z s # # 创建第二组元素 mykey2 (integer) 1 127.0.0.1:6379 pfcount mykey2 (integer) 5 127.0.0.1:6379 pfmerge mykey3 mykey mykey2 # 合并两组 mykey mykey2到 mykey3 并集 OK 127.0.0.1:6379 pfcount mykey3 # 看并集的数量 (integer) 16如果允许容错可以使用Hyperloglog 如果不允许容错可以使用 set 或者自己的数据类型即可 4.3、Bitmap 位存储 统计疫情感染人数0 1 0 1 0 0 1 1 登录、未登录B站活跃、不活跃钉钉打卡 两个状态的都可以使用 Bitmap Bitmap位图数据结构都是操作二进制位来进行记录就只有 0 和 1状态 365天 365bit 1字节 # 使用Bitmaps 来记录周一到周日的打卡 # 周一0 # 周二1 # 周三1 #..... 127.0.0.1:6379 setbit sign 0 0 (integer) 0 127.0.0.1:6379 setbit sign 1 1 (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 1 (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 6 (integer) 0 127.0.0.1:6379 getbit sign 2 (integer) 1# 统计操作统计 打卡的天数 127.0.0.1:6379 bitcount sign # 统计这周的考勤天数 (integer) 45、事务 Redis 单条命令是保存原子性的但是Redis 的事务不保证原子性 Redis 的事务是没有隔离级别的概念 所有的命令在事务中并没有直接被执行只有发起执行命令的时候才会被执行Exec MySQL的ACID要么都成功要么都失败—原子性 事务的本质一组命令的集合一个事务中的所有命令都会被序列化在事务执行过程中会按照顺序进行 一次性、顺序性、排他性执行一系列的命令 ----- 队列 set set set 执行------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 v2 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.运行时异常1/0如果事务队列中存在语法性错误那么执行命令的时候其他命令可以正常执行错误命令抛出异常 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 面试常问Redis可以做乐观锁因为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 的乐观锁操作 # 线程1 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 # 还未执行但是线程2在此时插进来修改money的值就会执行事务失败 (nil)# 线程2 127.0.0.1:6379 get money 80 127.0.0.1:6379 set money 1000 OK如果修改失败获取最新的值就好 6、Jedis 我们要使用 Java 来操作 Redis 6.1、什么是 Jedis Jedis是 Redis官方推荐的 Java 连接工具使用 Java操作 Redis 中间件如果你要使用 Java 操作 Redis那么一定要对 Jedis 十分熟悉 6.2、Jedis连接Redis 测试 导入对应得依赖 !-- 导入 jedis的包--!-- https://mvnrepository.com/artifact/redis.clients/jedis --dependenciesdependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion3.2.0/version/dependency !-- fastjson--dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.51/version/dependency/dependencies/project编码测试 连接数据库操作命令结束连接 package org.example;import redis.clients.jedis.Jedis;/*** author: Arbicoral* create: 2023-09-07 16:46* Description: 编码测试*/ public class TestPing {public static void main(String[] args) {// 1. new Jedis对象即可Jedis jedis new Jedis(127.0.0.1,6379);// 2. Jedis所有得命令就是我们之前学习得所有指令之前得指令很重要System.out.println(jedis.ping());} }输出 6.3、常用的API String List Set Hash Zset 7、SpringBoot整合 SpringBoot 操作数据spring-data spring-data 也是和 SpringBoot 齐名的项目 说明在 SpringBoot2.X后原来使用的 Jedis都被替换成了 lettuce lettuce 有什么好的 jedis采用的直连多个线程操作的话是不安全的如果想要避免不安全就需要 jedis pool 连接池更像 BIO 模式 lettuce采用 Netty实例可以在多个线程中共享不存在线程不安全的情况可以减少线程数量更像 Nio模式 整合测试一下 底层分析、源码解析、工具封装、企业级开发 企业一般都是自己写的工具类方便调用 所有的Redis操作对于Java开发人员来说十分简单更重要的是去理解 Redis的思想和每一种数据结构的用处和作用场景 实际开发中一般都是要写自己的 redisTemplate、 redisCoonfig 8、Redis.con详解 启动的时候就是通过配置文件来启动的 行家一出手就知有没有 配置文件 unit 单位 对大小写不敏感 包含 好比 import 网络 bing 127.0.0.1 # 绑定的ip protected-mode yes # 保护模式 port 6379 # 端口设置通用 GENRENAL daemonize yes # 以守护进程的方式运行默认是 no我们需要自己开启为 yes!pidfile /var/run/redis_6379.pid # 如果以后台的方式运行我们就需要指定一个 pid 文件loglevel notice # 日志有四个级别 debug、verbose(很像debug)、notice(生产环境)、warninglogfile # 日志的文件位置名databases 16 # 数据库的数量默认16个always-show-logo yes # 是否总显示logo快照 分析 持久化在规定时间内执行了多少次操作则会持久化到文件 .rdb.aof Redis是内存数据库如果没有持久化那么数据就会断电即失 # 如果900秒内如果至少有 1 个 Key进行了修改我们即进行持久化操作 save 900 1 # 如果300秒内如果至少有 10 个 Key进行了修改我们即进行持久化操作 save 300 10 # 如果60秒内如果至少 有 10000 个 Key进行了修改我们即进行持久化操作 save 60 10000 # 我们之后学习持久化会自己定义这个测试stop-writes-on-bgsave-error yes # 持久化如果出错是否还需要继续工作rdbcompression yes # 是否压缩 rdb 文件需要消耗一些 cpu资源rdbchecksum yes # 保存rdb文件的时候进行错误检查校验dir ./ # rdb 文件保存的目录replication 主从复制 Security 安全 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 1234 # 设置 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 1234 # 使用密码进行登录 OK 127.0.0.1:6379 config get requirepass 1) requirepass 2) 1234限制 clients maxclients 10000 # 设置能连接上Redis的最大客户端的数量maxmemory bytes # Redis 配置最大的内存容量maxmemory-policy noeviction # 内存到达上限之后的处理策略1、noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。默认值2、allkeys-lru: 所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。3、volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。4、allkeys-random: 随机删除一部分 key。5、vol5atile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。6、volatile-ttl: 优先删除剩余时间(time to live,TTL) 短的key。即将过期的Append only 模式 appendonly no # 默认是不开启AOF模式的默认是使用rdb方式持久化的在大部分所有的情况下rdb完全够用appendfilename appendonly.aof # 持久化的文件的名字# appendfsync always # 每次修改都会 sync 消耗性能 appendfsync everysec # 每秒执行一次 sync可能会丢失这 1s 的数据 # appendfsync no # 不执行 sync这个时候操作系统自己同步数据速度最快9、Redis 持久化 RDB AOF 面试和工作持久化都是重点! Redis是内存数据库如果不将内存中的数据库状态保存到磁盘那么一旦服务器进程退出服务器中的数据库状态也会消失。所以Redis提供了持久化功能 9.1、RDB Redis DataBase 在主从复制中rdb是备用的在从机上 什么是RDB 在指定的时间间隔内将内存中的数据集快照写入磁盘也就是行话讲的Snapshot快照它恢复时是将快照文件直接读到内存里。 Redis会单独创建( fork )一个子进程来进行持久化会先将数据写入到一个临时文件中待持久化过程都结束了再用这个临时文件替换上次持久化好的文件。整个过程中主进程是不进行任何IO操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复且对于数据恢复的完整性不是非常敏感那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。我们默认的就是RDB一般情况下不需要修改这个配置! 有时候在生产环境我们会将这个文件备份 rdb保存的文件是dump.rdb 都是在我们的配置文件中快照中进行配置的! 触发机制 save 得规则满足得情况下会自动触发rdb规则执行 flushall 命令 也会触发我们的 rdb 规则推出 Redis也会产生 rdb 文件 备份就自动生成一个 dump.rdb 如何恢复 rdb 文件 只需要将 rdb 文件放在我们 redis启动目录下就可以redis启动的时候会自动检查 dump.rdb 恢复其中的数据查看需要存放的位置 127.0.0.1:6379 config get dir 1) dir 2) E:\\Redis # 如果在这个目录下存在 dump.rdb 文件启动就会自动恢复其中的数据几乎他自己默认的配置就够用了 优点 适合大规模的数据恢复对数据的完整性要求不高 缺点 需要一定的时间间隔进行操作如果Redis意外宕机了这个时候最后一次修改数据就没有了fork 一条进程的时候会占用一定的内存空间 9.2、AOFAppend Only File 将我们执行的所有命令都记录下来恢复的时候就把这个文件全部执行一遍 AOF是什么 以日志的形式来记录每个 写 操作将Redis执行过的所有指令记录下来不记录 读操作只许追加问文件但不可以改写文件redis启动之初会读取该文件重新构建数据换言之redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作 AOF保存的是 appendonly.aof 文件 Append 默认是不开启的需要自己手动开启我们只需要将 appendonly 改为 yes就开启了 AOF ! 重启 Redis 就可以生效 如果这个 aof 文件有错误这个时候 redis是启动不起来的我们需要修复这个 aof 文件 redis给我们提供了一个工具 redis-check-aof 如果文件正常重启就可以恢复了 redis-check-aof --fix appendonly.aofAOF的优点和 缺点 appendonly no # 默认是不开启AOF模式的默认是使用rdb方式持久化的在大部分所有的情况下rdb完全够用appendfilename appendonly.aof # 持久化的文件的名字# appendfsync always # 每次修改都会 sync 消耗性能 appendfsync everysec # 每秒执行一次 sync可能会丢失这 1s 的数据 # appendfsync no # 不执行 sync这个时候操作系统自己同步数据速度最快每一次修改都同步文件的完整性更好每秒同步一次可能会丢失上一秒的数据从不同步效率最高 缺点 相对于文件数据来说AOF 远远大于 rdb修复的速度也比 rdb慢AOF运行效率也要比 rdb 慢所以我们redis默认的配置就是 rdb持久化 扩展 1、RDB 持久化方式能够在指定的时间间隔内对你的数据进行快照存储 2、AOF 持久化方式是记录每次对服务器写的操作当服务器重启的时候会重新执行这些命令来恢复原始的数据AOF命令以 Redis协议追加保存每次写的操作到文件末尾Redis还能对 AOF文件进行后台重写使得AOF文件的体积不至于过大 3、如果Redis只做缓存如果你只希望你的数据在服务器运行的时候存在你也可以不使用任何持久化 4、同时开启两种持久化方式 在这种情况下当redis重启的时候会优先载入AOF文件来恢复原始的数据因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。RDB的数据不实时同时使用两者时服务器重启也只会找AOF文件那要不要只使用AOF呢?作者建议不要因为RDB更适合用于备份数据库(AOF在不断变化不好备份快速重启而且不会有AOF可能潜在的Bug留着作为一个万一的手段。 5、性能建议 因为RDB文件只用作后备用途建议只在Slave上持久化RDB文件而且只要15分钟备份一次就够了只保留save 900 1这条规则。如果Enable AOF好处是在最恶劣情况下也只会丢失不超过两秒数据启动脚本较简单只load自己的AOF文件就可以了代价一是带来了持续的lO二是AOF rewrite 的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可应该尽量减少AOF rewrite的频率AOF重写的基础大小默认值64M太小了可以设到5G以上默认超过原大小100%大小重写可以改到适当的数值。如果不Enable AOF仅靠Master-Slave Repllcation实现高可用性也可以能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉会丢失十几分钟的数据启动脚本也要比较两个Master/Slave 中的 RDB文件载入较新的那个微博就是这种架构。 Redis 实现订阅发布 Redis 发布订阅pub/sub是一种 消息通信模式发送者pub发送消息订阅者sub接收消息。微信、微博、关注系统都可以实现 Redis 客户端可以订阅任意数量的频道。 订阅/发布消息图 第一个消息发送者第二个频道第三个消息订阅者 下图展示了频道 channel1 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系 当有新消息通过 PUBLISH 命令发送给频道 channel1 时 这个消息就会被发送给订阅它的三个客户端 命令 这些命令被广泛用于构建即时通信应用比如网络聊天室(chatroom)和实时广播、实时提醒等。 测试 订阅端 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, Arbicoral # 消息的具体内容1) message 2) kuangshenshuo 3) hello, Redis发送端 127.0.0.1:6379 publish kuangshenshuo hello, Arbicoral # 发布者发布消息到频道 (integer) 1 127.0.0.1:6379 publish kuangshenshuo hello, Redis # 发布者发布消息到频道 (integer) 1原理 Redis是使用C实现的通过分析Redis源码里的pubsub.c文件了解发布和订阅机制的底层实现籍此加深对Redis的理解。Redis通过PUBLISH 、SUBSORIBE和PSUBSCRIBE等命令实现发布和订阅功能。 微信 通过SUBSCRIBE命令订阅某频道后redis-server里维护了一个字典字典的键就是一个个channel而字典的值则是一个链表链表中保存了所有订阅这个channel的客户端。SUBSCRIBE命令的关键就是将客户端添加到给定channel的订阅链表中。 通过PUBLSH命令向订阅者发送消息redis-server会使用给定的频道作为键在它所维护的 channel字典中查找记录了订阅这个频道的所有客户端的链表遍历这个链表将消息发布给所有订阅者。 Pub/Sub从字面上理解就是发布( Publish )与订阅( Subscribe )在Redis中你可以设定对某一个key值进行消息发布及消息订阅当一个key值上进行了消息发布后所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统比如普通的即时聊天群聊等功能。 使用场景 实时消息系统实时聊天把频道当作聊天室将信息回信给所有人订阅、关注系统都可以 稍微复杂的场景就会使用 消息中间件如 MQ、kafka 10、Redis 主从复制 10.1、基本概念 概念 主从复制是指将一台 Redis 服务器的数据复制到其他的 Redis 服务器。前者称为主节点master; leader后者称为从节点slave/follower数据的复制是单向的只能由主节点到从节点。Master 以写为主Salve 以读为主。 默认情况下每台Redis 服务器都是主节点且一个主节点可以有多个从节点或没有从节点但一个从节点只能有一个主节点 主从复制的作用主要包括 数据冗余主从复制实现了数据的热备份是持久化之外的一种数据冗余方式。故障恢复当主节点出现问题时可以由从节点提供服务实现快速的故障恢复实际上是一种服务的冗余。负载均衡在主从复制的基础上配合读写分离可以由主节点提供 写服务由从节点提供读 服务即写 Redis 数据时应用连接主节点读Redis 数据时应用连接从节点分担服务器负载尤其是在写少读多的情况下通过多个从节点分担读负载可以大大提高Redis 服务器的并发量。高可用集群基石除了上述作用以外主从复制还是哨兵和集群能够实施的基础因此说主从复制是Redis 高可用的基础。 一般来说要将Redis 运用于工程项目中只使用一台Redis 是万万不能的原因如下 从结构上单个Redis 服务器会发生单点故障并且一台服务器需要处理所有的请求负载压力较大。从容量上单个Redis 服务器内存容量有限就算一台Redis 服务器内存容量为 256G也不能将所有内存用作Redis 存储内存一般来说单台Redis 最大使用内存不应超过20G、 电商网站上的商品一般都是一次上传无数次浏览说专业点就是”多读少写“。 在这种场景下我们可以使用如下架构 主从复制读写分离80%的情况下都是在进行读 操作减缓服务器的压力架构中经常使用一主二从 只要在公司中主从复制是必须使用的在真实的项目中不可能单机使用Redis。 10.2、环境配置 只配置从库不用配置主库 127.0.0.1:6379 ping PONG 127.0.0.1:6379 info replication # 查看当前库的信息 # Replication role:master # 角色master connected_slaves:0 # 没有从机 master_replid:8f5a0ae6efccf7d88f84bdcd12b6ec6d35737534 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 (0.88s)复制3个配置文件然后修改对应的信息 端口Log名字pid名字dump.rdb名字 10.3、一主二从 默认情况下每台 Redis服务器都是主节点我们一般情况下只用配置从机就好了 认老大 一主79二从80、81 SLAVEOF host port # 设置从机的命令认谁当自己的老大如果两个都配置完了就是有两个从的 真实的主从配置应该在配置文件中配置这样的化是永久的我们这里使用的是命令只是暂时的 细节 主机负责写从机不能写只能读主机中的所有信息和数据都会自动被从机保存 测试主机断开连接从机依旧连接到主机但是没有写操作这个时候如果主机回来了从机依旧可以直接获取到主机写的信息 如果是使用命令行配置的主从这个时候如果重启了那从机就会变回主机只要变为从机立马就会从主机中获取值 复制原理 重点 Slave启动成功连接到master后会发送一个sync同步命令 Master接到命令启动后台的存盘进程同时收集所有接收到的用于修改数据集命令在后台进程执行完毕之后master将传送整个数据文件到slave并完成一次完全同步。 全量复制而slave服务在接收到数据库文件数据后将其存盘并加载到内存中。 增量复制Master继续将新的所有收集到的修改命令依次传给slave完成同步。 但是只要是重新连接master一次完全同步全量复制)将被自动执行 层层链路 上一个 M 链接下一个 S 如果没有老大这个时候能不能选择一个老大出来呢 相当于谋朝篡位 如果主机断开了连接我们可以使用 slaveof no one 让自己变成主机其他的节点就可以手动连接到最新的这个主节点手动如果这个时候老大修复了那就重新连接 slaveof no one10.4、哨兵模式 自动选举老大的模式 概述 主从切换技术的方法是当主服务器宕机后需要手动把一台从服务器切换为主服务器这就需要人工干预费事费力还会造成一段时间内服务不可用。这不是一种推荐的方式更多时候我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel (哨兵架构来解决这个问题。 **谋朝篡位的自动版**能够后台监控主机是否故障如果故障了根据投票数自动将从库转换为主库。 哨兵模式是一种特殊的模式首先Redis提供了哨兵的命令哨兵是一个独立的进程作为进程它会独立运行。其原理是哨兵通过发送命令等待Redis服务器响应从而监控运行的多个Redis实例。 这里的哨兵有两个作用 通过发送命令让Redis服务器返回监控其运行状态包括主服务器和从服务器。当哨兵监测到master宕机会自动将slave切换成master然后通过发布订阅模式通知其他的从服务器修改配置文件让它们切换主机。 然而一个哨兵进程对Redis服务器进行监控可能会出现问题为此我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控这样就形成了多哨兵模式。 假设主服务器宕机哨兵1先检测到这个结果系统并不会马上进行failover过程仅仅是哨兵1主观的认为主服务器不可用这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用并且数量达到一定值时那么哨兵之间就会进行一次投票投票的结果由一个哨兵发起进行failover [故障转移] 操作。切换成功后就会通过发布订阅模式让各个哨兵把自己监控的从服务器实现切换主机这个过程称为客观下线。 测试配置哨兵 配置哨兵配置文件 sentinel.conf # sentinel monitor 被监控的名称 host port 1 sentinel monitor myredis 127.0.0.1 6379 1后面的数字1代表主机挂了 slave投票看让谁接替成为主机票数最多的就会成为主机 启动哨兵 如果 master 断开这个时候就会从从机中随机选择要一个服务器这里有一个投票算法 哨兵日志 哨兵模式如果主机此时回来了只能归并到新的主机下当作从机这就是哨兵模式的规则 哨兵模式的优点和缺点 优点 哨兵集群一般基于主从复制模式所有的主从配置的优点它全有主从可以切换故障可以转移系统的可用性更好哨兵模式就是主从复制的升级手动到自动更加健壮 缺点 Redis 不好在线扩容集群容量一旦到达上限在线扩容就十分麻烦实现哨兵模式的配置其实是很麻烦的里面有很多选择 11、Redis缓存穿透和雪崩 面试高频 服务器的高可用 在这里我们不会详细的区分析解决方案的底层(专题) Redis缓存的使用极大的提升了应用程序的性能和效率特别是数据查询方面。但同时它也带来了一些问题。其中最要害的问题就是数据的一致性问题从严格意义上讲这个问题无解。如果对数据的一致性要求很高那么就不能使用缓存。 另外的一些典型问题就是缓存穿透、缓存雪崩和缓存击穿。目前业界也都有比较流行的解决方案。 11.1、缓存穿透查不到导致的 概念 缓存穿透的概念很简单用户想要查询一个数据发现redis内存数据库没有也就是缓存没有命中于是向持久层数据库查询。发现也没有于是本次查询失败。当用户很多的时候缓存都没有命中于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力这时候就相当于出现了缓存穿透。 解决方案 布隆过滤器 布隆过滤器是一种数据结构对所有查询的参数以 hash形式存储在控制层先进行校验不符合则丢弃从而避免了对底层存储系统的查询压力。 缓存空对象 当存储层不命中后即使返回的空对象也将其缓存起来同时会设置一个过期时间之后再访问这个数据将会从缓存中获取保护了后端数据源 。 但是这时候会存在 两个问题 如果空值能够被缓存起来这意味着缓存需要更多的空间存储更多的键因为这当中可能会有很多的空值的键即使对空值设置了过期时间还是会存在缓存层和存储层的数据会有一段时间窗口的不一致这对于需要保持一致性的业务会有影响 10.2、缓存击穿量太大缓存过期 微博服务器宕机 概述 这里需要注意和缓存击穿的区别缓存击穿是指一个key非常热点在不停的扛着大并发大并发集中对这一个点进行访问当这个key在失效的瞬间持续的大并发就穿破缓存直接请求数据库就像在一个屏障上凿开了一个洞。 当某个key在过期的瞬间有大量的请求并发访问这类数据一般是热点数据由于缓存过期会同时访问数据库来查询最新数据并且回写缓存会导使数据库瞬间压力过大。 解决方案 设置热点数据永不过期 从缓存层面来看没有设置过期时间所以不会出现热点 key过期后产生的问题。 加互斥锁 分布式锁使用分布式锁保证对于每个 key同时只有一个线程去查询后端服务其他线程没有获得分布式锁的权限因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁因此对分布式锁的考验很大。 10.3、缓存雪崩 概念 缓存雪崩是指在某一时间段缓存集中发过期失效。Redis宕机 产生缓存雪崩的原因之一比如在写文本的时候马上就要到双十二零点很快就会迎来一波抢购这波商品时间比较集中的放入了缓存假设缓存一个小时。那么到了凌晨一点钟的时候这批商品的缓存就都过期了。而对这批商品的访问查询都落到了数据库上对于数据库而言就会产生周期性的压力波峰。于是所有的请求都会达到存储层﹐存储层的调用量会暴增造成存储层也会挂掉的情况。 其实集中过期倒不是非常致命比较致命的缓存雪崩是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩一定是在某个时间段集中创建缓存这个时候数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机对数据库服务器造成的压力是不可预知的很有可能瞬间就把数据库压垮。 比如双十一停掉一些服务保证主要的服务可用 解决方案 Redis 高可用 这个思想的含义是既然redis有可能挂掉那我多增设几台redis这样一台挂掉之后其他的还可以继续工作其实就是搭建的集群。异地多活!) 限流降级在SpringCloud讲解过!) 这个解决方案的思想是在缓存失效后通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存其他线程等待。 数据预热 数据加热的含义就是在正式部署之前我先把可能的数据先预先访问一遍这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key设置不同的过期时间让缓存失效的时间点尽量均匀。 学习资料链接 极大的提升了应用程序的性能和效率特别是数据查询方面。但同时它也带来了一些问题。其中最要害的问题就是数据的一致性问题从严格意义上讲这个问题无解。如果对数据的一致性要求很高那么就不能使用缓存。 另外的一些典型问题就是缓存穿透、缓存雪崩和缓存击穿。目前业界也都有比较流行的解决方案。
http://wiki.neutronadmin.com/news/415106/

相关文章:

  • 网站建设指南 菜鸟教程怎么做私人网站
  • 甘肃肃第八建设集团网站太原自动seo
  • 仿西部数码网站网站是否含有seo收录功能
  • 统计网站建设丢了么网站
  • 2狠狠做网站app定制系统开发
  • dw可以做h5网站可以加速网页的加速器
  • 成都电子网站建设做网站有什么要求
  • 手机数码网站专业建设网站企业
  • 网站建设合同通用范本qq邮件网站建设的模块
  • 棋牌游戏网站模板app推广专员好做吗
  • 非常好的资讯网站设计上海电子手工活外发加工网
  • 如何建设手机网站设计企业
  • 做网站不用服务器做网站推广员必备的条件
  • 外贸网站虚拟空间泰安人才网首页
  • 建站目的公众号开发者权限怎么开
  • 设计的有趣的网站推荐新闻热点事件2022
  • 企业解决方案提供商seo搜索引擎优化公司
  • seo在线优化网站昆明建设网站哪家好
  • wordpress 企业网站 授权费dw网站建设的心得体会
  • 建设学院网站的通知怎么做提升网站转化率
  • 秦皇岛网站关键词推广全球十大营销策划公司
  • 网站设计班培训云南建设厅网站公示
  • 凡科建站电脑版网址网站开发用什么图片格式最好
  • 如何做网站公司名seo设计坞网站官方下载
  • ftp 企业网站建站管理域名管理绑定外部域名中
  • 购买主机可以做网站吗网页架构人才培训中心
  • 怎样做公司宣传网站网站建设 启象科技
  • 做微商那个网站好对外贸易企业网站建设流程
  • 购物网站建设的意义与目的衡水哪家制作网站好
  • 电子网站模板长沙优化网站技术厂家