隋唐演义

隋唐演义

redis从入门到高可用完整版

双十一 0

手机淘宝搜:天降红包55 5月20日开始,每天领红包。
京示搜:天降红包369,5月28日开始


一个问题:如何在MySQL有记录改动了(增删改操作),立刻同步反映到redis?

【【微信】】能够记录MySQL的变更

有一种技术方案,能够监听到mysql的变动且能够通知给redis,类似中介

1、Canal

1.1、canal是什么

Home ・ 【【微信】】nal Wiki ・ GitHubGitHub地址

阿里巴巴 MyS【【微信】】 增量订阅&消费组件

canal [k?’n?l],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费

1.2、能干什么
  • 数据库镜像
  • 数据库实时备份
  • 索引构建和实时维护(拆分异构索引、倒排索引等)
  • 业务cache刷新
  • 带业务逻辑的增量数据处理
1.3、下载

地址:Release v1.1.6 ・ 【【微信】】nal ・ GitHub

1.4、工作原理

先看一下传统的MySQL主从复制工作原理

步骤详解

  1. 当master主服务器上的数据发生改变时,则将其改变写入二进制事件日志文件中;
  2. salve 从服务器会在一定时间间隔内对 master主服务器上的二进制日志进行探测,探测其是否发生过改变,如果探测到master主服务器的二进制事件日志发生了改变,则开起一个I/O Thread 请求master二进制事件日志;
  3. 同时 master主服务器为每个IO Thread启动一个dump Thread,用于向其发送二进制事件日志;
  4. slave 从服务器将接收到的二进制事件日志保存至自己本地的中继日志文件中;
  5. salve 从服务器将启动S【【微信】】 从中继日志中读取二进制日志,在本地重放,使得其数据和主服务器保持一致;

canal工作原理

  • canal 模拟 MyS【【微信】】 的交互协议,伪装自己为 MyS【【微信】】 ,向 MyS【【微信】】 发送 dump 协议
  • MyS【【微信】】 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
  • canal 解析 binary log 对象(原始为 byte 流)

2、mys【【微信】】双写一致性Coding

ClientExample ・ 【【微信】】nal Wiki ・ GitHubcanal.exxample

2.1、MySQL

查看一下数据库的主机二进制日志

查看当前主机的【【微信】】是否让人查看,默认是关着的

打开MySQL的安装文件夹,找到my.ini文件,打开添加以下三行

? ROW模式除了记录sq悟句之外,还会记录每个字段的变化情况,能够清楚的记录每行数据的变化历史,但会占用较多的空间

? STATEMENT模式只记录了sql语句,但是没有记录上下文信息,在进行数据恢复的时候可能会导致数据的丢失情况;

? MIX模式比较灵活的记录,理论上说当遇到了表结构变更的时候,就会记录为statement模式。当遇到了数据更新或者删除情况下就会变为row模式;

重启MySQL

再次查看【【微信】】是否打开让访问

授权canal连接MySQL账号

mysql默认的用户在mysql库的user表里

默认没有canal账户,此处新建+授权

2.2、canal服务端

下载并解压

下载的是1.1.6的版本

canal.deployer-1.1.6.tar.gz (github.com)

去虚拟机使用wget下载到/mycanal目录下

配置

修改/mycanal/conf/example路径下instance.properties文件

instance.properties

  • 换成自己的mysql主机master的IP地址

    确保能ping的通

  • 换成自己的在mysql新建的canal账户

    默认的就是canal

启动

在/mycanal/bin下有启动的脚本

查看

在/root/mycanal/logs/canal下有canal.log,使用cat查看一下看是否已经运行

在/mycanal/logs/example下还有example.log查看有成功启动的信息

两个日志文件都显示成功就代表canal客户端启动成功了

2.3、canal客户端(Java编写业务程序)

随便找个数据库新建user表

创建一个maven项目(在原来的redis项目上新建的maven模块)

添加canal依赖

创建【【微信】】.properties

业务类

RedisUtils

RediscanalClientExample

启动

就行增删改查操作,到redis中查看效果

1、面试题,需求

  • 抖音电商直播,主播介绍的商品有评论,1个商品对应了1系列的评论,排序+展现+取前10条记录
  • 用户在手机App上的签到打卡信息:1天对应1系列用户的签到记录,新浪微博、钉钉打卡签到,来没来如何统计?
  • 应用网站上的网页访问信息∶1个网页对应1系列的访问点击,淘宝网首页,每天有多少人浏览首页?
  • 你们公司系统上线后,说一下UV、PV、DAU分别是多少?

亿级数据的收集+清洗+统计+展现

2、统计的类型有哪些

亿级系统中常见的四种统计

聚合统计

统计多个集合元素的聚合结果,就是之前的交差并等集合统计

命令:

应用:qq中可能认识的人,好友的推广

排序统计

抖音短视频最新评论留言的场景,请你设计一个展现列表。考察你的数据结构和设计思路

能够排序+分页显示的redis数据结构是什么合适?

在面对需要展示最新列表、排行榜等场景时,如果数据更新频繁或者需要分页显示,建议使用ZSet

二值统计

0 和1 【【微信】】>

集合元素的取值就只有0和1两种。在钉钉上班签到打卡的场景中,我们只用记录有签到⑴或没签到0)

基数统计

去重统计

3、HyPerLogLog

名词

  • UV

    Unique Visitor,独立访客,一般理解为客户端IP ,需要去重考虑

  • PV

    Page View,页面浏览量 不用去重

  • DAU

    Daily Active User

    日活跃用户量

    登录或者使用了某个产品的用户数(去重复登录的用户)

    常用于反映网站、互联网应用或者网络游戏的运营情况

  • MAV

    Monthly Active User

    月活跃用户量

看需求:

很多计数类场景,比如每日注册IP数、每日访问IP数、页面实时访问数PV、访问用户数UV等。因为主要的目标高效、巨量地进行计数,所以对存储的数据的内容并不太关心。

也就是说它只能用于统计巨量数量,不太涉及具体的统计对象的内容和精准性。大差不差就行了

统计单日一个页面的访问量(PV),单次访问就算一次。

统计单日一个页面的用户访问量(UV),即按照用户为维度计算,单个用户一天内多次访问也只算一次。多个key的合并统计,某个门户网站的所有模块的PV聚合统计就是整个网站的总PV。

基本的命令

在Java中最能想到的就是HashSet,Redis中有【【微信】】>

概率算法

通过牺牲准确率来换取空间,对于不要求绝对准确率的场景下可以使用,因为概率算法不直接存储数据本身,通过一定的概率统计方法预估基数值,同时保证误差在一定范围内,由于又不储存数据故此可以大大节约内存。

HyperLogLog就是一种概率算法的实现。

HyperLogLog原理

只是进行不重复的基数统计,不是集合也不保存数据,只记录数量而不是具体内容。

他是有误差的,牺牲准确率来换取空间,误差仅仅只是0.81%左右

模拟淘宝网站首页亿级UV的Redis统计方案

需求:

  • UV的统计需要去重,一个用户一天内的多次访问只能算作一次
  • 淘宝、天猫首页的UV,平均每天是1~1.5个亿左右
  • 每天存1.5个亿的IP,访问者来了后先去查是否存在,不存在加入
  1. 用redis的hash结构存储

    说明,redis―hash = <keyDay,<ip,1>…<ip,n>>

    按照IP v4结构来说,每一个IP v4的地址最多是15个字节

    某一天的1.5忆 * 15字节= 2G 那一个月就是60G,redis就炸了

  2. HyPerLogLog

    HyPerLogLogService

    HyPerLogLogController

4、GEO

面试题

移动互联网时代LBS应用越来越多,交友软鹤中附近的小姐姐、外卖软件中附近的美食店铺、打车软件附近的车辆等等。那这种附近各种形形色色的XXX地址位置选择是如何实现的?

会出现的问题

1.查询性能问题,如果并发高,数据量大这种查询是要搞垮mysql数据库的 2.一般mysql查询的是一个平面矩形访问,而叫车服务要以我为中心N公里为半径的圆形覆盖。 3.精准度的问题,我们知道地球不是平面坐标系,而是一个圆球,这种矩形计算在长距离计算时会有很大误差,mysql不合适

GEO的命令

  • GEOADD添加经纬度坐标

  • 【【微信】】返回经纬度

  • GEOHASH返回坐标的geohash表示

  • GEODIST两个位置之间距离

  • GEORADIUS用的最多

    georadius 以给定的经纬度为中心,返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有位置元素。

    • WITHDIST:在返回位置元素的同时,将位置元素与中心之间的距离也一并返回。距离的单位和用户给定的范围单位保持一致。

    • WITHCOORD:将位置元素的经度和维度也一并返回。

    • WITHASH:以.52位有符号整数的形式,返回位置元素经过原始 geohash编码的有序集合分值。这个选项主要用于底层应用或者调试,实际中的作用并不大

    • COUNT限定返回的记录数。

  • GEORADIUSBYMEMBER

美团地图位置附近的酒店推送

关键命令:GEORADIUS 以给定的经纬度为中心,找出某一半径内的元素

GeoController

GeoService

5、【【微信】】

面试题

  • 日活统计
  • 连续签到打卡
  • 最近一周的活跃用户
  • 统计指定用户一年之中的登陆天数
  • 某用户按照一年365天,哪几天登陆过?哪几天没有登陆?全年中登录的天数一共多少?

【【微信】】就是由O和1状态表现的二进制位的bit数组

布隆过滤器BloomFilter

一些问题

  • 现有50亿个电话号码,现有10万个电话号码, 如何要快速准确的判断这些电话号码是否已经存在?
  • 判断是否存在,布隆过滤器了解过吗?
  • 安全连接网址,全球数10亿的网址判断
  • 黑名单校验,识别垃圾邮件
  • 白名单校验,识别出合法用户进行后续处理

布隆过滤器是干啥的?

由一个初值都为零的bit数组和多个哈希函数构成,用来快速判断集合中是否存在某个元素

布隆过滤器是一种类似set的数据结构,只是统计结果在巨量数据下有点小瑕疵,不够完美

布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。

它实际上是一个很长的二进制数组(0000oo00)+一系列随机hash算法映射函数,主要用于判断一个元素是否在集合中。

? 通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,一般想到的是将集合中所有元素保存起来,然后通过比较确定。 ? 链表、树、哈希表等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间也会呈现线性增长,最终达到瓶颈。同时检索速度也越来越慢,上述三种结构的检索时间复杂度分别为o(n),0(logn),O(1)。这个时候,布隆过滤器(Bloom Filter)就应运而生

能干什么?

高效地插入和查询,占用空间少,返回的结果是不确定性+不够完美。不保存数据信息,只是在内存中做一个是否存在的标记flag

一个元素如果判断结果:存在时,元素不一定存在,可能有哈希冲突的(不一定这个坑里有多少意思),但是判断结果为不存在时,则一定不存在。

布隆过滤器可以添加元素,但是不能删除元素,由于涉及hashcode判断依据,删掉元素会导致误判率增加。

  • 添加key时

    使用多个hash函数对key进行hash运算得到一个整数索引值,对位数组长度进行取模运算得到一个位置,每个hash函数都会得到一个不同的位置,将这几个位置都置1就完成了add操作。

  • 查询key时

    只要有其中一位匙零就表示这个key不存在,但如果都是1,则不一定存在对应的key。

查询某个变量的时候我们只要看看这些点是不是都是1,就可以大概率知道集合中有没有它了,==如果这些点,有任何一个为零则被查询变量一定不在,==如果都是1,则被查询变量很可能存在。

? 正是基于布隆过滤器的快速检测特性,我们可以在把数据写入数据库时,使用布隆过滤器做个标记。当缓存缺失后,应用查询数据库时,可以通过查询布隆过滤器快速判断数据是否存在。如果不存在,就不用再去数据库中查询了。这样一来,即使发生缓存穿透了,大量请求只会查询Redis和布隆过滤器,而不会积压到数据库,也就不会影响数据库的正常运行。布隆过滤器可以使用Redis实现,本身就能承担较大的并发访问压力。

哈希函数的概念

哈希函数的概念是:将任意大小的输入数据转换成特定大小的输出数据的函数,转换后的数据称为哈希值或哈希编码,也叫散列值。

建议:

  • 使用时最好不要让实际元素数量远大于初始化数量,一次给够避免扩容。
  • 当实际元素数量超过初始化数量时,应该对布隆过滤器进行重建,重新分配一个size更大的过滤器,再将所有的历史元素批量add进行

将布隆过滤器放在redis前,请求先在布隆过滤器中查一遍,如果有就可能是有再去redis查,如果没有就是没有直接拦截过滤掉。

布隆过滤器实例

二进制数值构建过程:

1 预加载符合条件的记录

2 计算每条记录的hash值

3 计算hash值对应的【【微信】】数组位置

4 修改值为1

查找元素的存在过程:

1 计算元素的hash值

2 计算hash值对应二进制数组的位置

3 找到数组中对应位置的值,1就是存在,0就是不存在。

搭建测试环境

  • t_customer用户表SQL

  • 建【【微信】】的Module

  • 改POM

  • mgb配置相关src\main\resources路径下新建

    • config.properties

    • generatorConfig.xml

  • 一键生成

生成出来的

SpringBoot + Mybatis + Redis缓存实战编码

更改配置文件

在resource目录下新建【【微信】】文件夹,然后复制Custo【【微信】】.xml

将之前一键生成的实体类和【【微信】】复制过来

使用了mybatis在主启动类上添加注解扫描【【微信】】包

业务类

【【微信】】

CustomerService

接下来编写布隆过滤器

BloomFilterInit(白名单)

CheckUtils 检查单元

CustomerService 更改

【【微信】】更改

布隆过滤器的优缺点

优点

高效地插入和查询,内存占用bit空间少

缺点

不能删除元素。 因为删掉元素会导致误判率增加,因为hash冲突同一个位置可能存的东西是多个共有的,你删除一个元素的同时可能也把其它的删除了。

存在误判,不能精准过滤

1、面试题

  • 缓存预热、雪崩、穿透、击穿分别是什么?你遇到过那几个情况?
  • 缓存预热你是怎么做的?
  • 如何避免或者减少缓存雪崩?
  • 穿透和击穿有什么区别?他两是一个意思还是截然不同?
  • 穿透和击穿你有什么解决方案?如何避免?
  • 假如出现了缓存不一致,你有哪些修补方案?

2、缓存预热

假设MySQL有100条数据,现在是MySQL有了,但是redids中没有缓存,这就需要操作让redis也有这100条数据。

可以的办法

  • 最简单的就是利用redis回写,第一个人全部查询一遍都去MySQL查然后回写到redis,redis就有了,但是这第一个人最好是自己人,开发和测试人员完成,别让客户等
  • 通过中间件或者程序自动完成,这边MySQL新增数据
    ..淘宝互助一天有几次,淘宝互助一天有几次,淘宝可以互助几次啊,加入了一个互帮互助的2023 618天猫年中大促淘宝商家交流群互助群,成员们都愿意分享,快来加入,我们一起互相帮助吧!