小知识点:MySQL 的 redo log、undo log、binlog 以及 Java 监控 binlog

news2024/11/26 2:37:23

SQL 入库流程

  • 服务器与 MySQL 建立连接
  • 依次经过 MySQL 服务器内存中 Server 层的分析器、优化器、执行器
  • 执行器根据执行计划操作 InnoDB 引擎
  • InnoDB 从磁盘数据文件中将 data 读到缓冲池中
  • 修改之前,会写入 undo log 将 data 存起来
  • 然后将缓冲池中的 data 改成 new_data
  • 写入一条 redo log 将修改后的 new_data 存起来
  • 写入一条 binlog 将修改后的值 new_data 存起来
  • 后台 IO 线程将缓冲池中被修改的值刷入磁盘

目录

    • 一、Buffer Pool
    • 二、redo log
    • 三、undo log
    • 四、binlog
    • 五、总结
    • 六、Java 监控 MySQL binlog
      • 6.1 环境准备
      • 6.2 Java 代码

一、Buffer Pool

  • InnoDB 里的重要结构,一块用于缓存 MySQL 磁盘数据的内存空间
  • 没有 Buffer Pool 每次数据修改都要进行磁盘 IO 操作,有了 Buffer Pool 就可以将磁盘 IO 转换成内存操作,节省时间提高效率
  • 如果断电,数据会全部丢失,这就需要用到 redo log、undo log、binlog

二、redo log

redo log 就是重做日志的意思

  • 保证数据不丢失
    • 再修改之后,先将修改的数据记录到磁盘上的 redo log 中,就算断电后 Buffer Pool 的数据丢失,也可以从 redo log 中恢复
  • WAL(Write-ahead loggin)预写式日志
    • 先预写日志后再将数据刷盘的机制
    • redo log 是磁盘顺序写,数据刷盘是随机写,顺序写比随机写效率高
  • redo log buffer
    • 磁盘顺序写的效率已经很高效了,但是和内存操作还是有一定的差距,添加一个内存 buffer 可以优化
    • MySQL 是运行在操作系统上的,MySQL 挂了 Buffer Pool 会丢失,这时候 OS 的 caceh 没有丢失可以恢复,如果操作系统也挂了,OS 的 cache 也会丢失,天意不可违,该咋办咋办
  • 落盘机制
    • innodb_flush_log_at_trx_commit = 1:实时写,实时刷
      • 每次事务提交之前,每次都会将数据从 redo log 刷到磁盘中
      • 效率最低,丢数据风险也低
    • innodb_flush_log_at_trx_commit = 0:延迟写,延迟刷
      • 每次事务提交时,只写数据到 redo log buffer 中,然后让后台线程定时将数据刷盘
      • 效率最高,丢数据风险最高
    • innodb_flush_log_at_trx_commit = 2:实时写,延迟刷
      • 每次事务提交之前,redo log 写到 OS cache 中
      • 效率比较高,丢失数据风险比较低,只要操作系统不挂,基本不会丢数据,推荐

三、undo log

  • InnoDB 支持事务,事务可以回滚
  • 在记录修改之前的数据过程,叫做记录 undo log
  • undo 撤销、回滚,undo log 主要作用就是回滚数据
  • undo log 默认存在全局表空间里面,可以简单理解为 undo log 也是记录在一个 MySQL 表里面,插入一条 undo log 和插入普通数据是类似的,也需要写 redo log

四、binlog

  • redo log 记录的是修改之后的数据,提供崩溃恢复的能力
  • undo log 记录修改之前的数据,提供回滚能力
  • binlog 记录的是修改之后的数据,用于归档
  • binlog sync_binlog 刷盘策略
    • sync_binlog = 0:每次提交事务前将 binlog 写入 OS cache,由操作系统控制刷盘
    • sync_binlog = 1:采用同步写磁盘的方式来写 binlog,不使用 OS cache
    • sync_binlog = N:每进行 n 次事务提交之后,调用一次 fsync 将 OS cache 中的 binlog 强制刷到磁盘
  • redo log 和 binlog 区别
    • binlog 是逻辑日志,记录的是对哪一个表的哪一行做了什么修改
    • redo log 是物理日志,记录的是对哪个数据页中的哪个记录做了什么修改
    • binlog 是追加写,redo log 是循环写,日志文件有固定大小,会覆盖之前的数据
    • binlog 是 Server 层的日志,redo log 是 InnoDB 的日志

五、总结

  • Buffer Pool 是 MySQL 进程管理的一块内存空间,有减少磁盘 IO 次数的作用
  • redo log 是 InnoDB 存储引擎的一种日志,主要是崩溃恢复,innodb_flush_log_at_trx_commit 控制三种刷盘策略,推荐 2
  • undo log 是 InnoDB 存储引擎的一种日志,主要作用就是回滚
  • binlog 是 MySQL Server 层的一种日志,主要作用是归档
  • MySQL 挂了有两种情况
    • 操作系统挂了,MySQL 进程跟着挂
    • 操作系统没挂,MySQL 进程挂了

六、Java 监控 MySQL binlog

6.1 环境准备

  • 查看 MySQL 是否开启 binlog
    • show variables like ‘log_bin’;
    • 默认是不开启的,会报 ERROR 1381 - You are not using binary loggin

在这里插入图片描述

  • 开启 binlog
    • 修改 my.cnf(有些是 my.ini)

在这里插入图片描述

  • 重启 MySQL

6.2 Java 代码

  • 引入依赖
<dependency>
    <groupId>com.github.shyiko</groupId>
    <artifactId>mysql-binlog-connector-java</artifactId>
    <version>0.21.0</version>
</dependency>
  • MySQL 消息类
public class MySQLRecord {

    private String database;
    private String table;
    private final List<UpdateRecord> records = new LinkedList<>();

    public MySQLRecord() {
    }

    public MySQLRecord(String database, String table) {
        this.database = database;
        this.table = table;
    }

    @Override
    public String toString() {
        return "{\"database\"=\"" + database + "\"," +
                "\"table\"=" + table + "\"," +
                "\"records\"=" + records + "}";
    }

    public void setRecord(UpdateRecord record) {
        records.add(record);
    }

    public void setRecords(List<UpdateRecord> records) {
        this.records.addAll(records);
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public void setTable(String table) {
        this.table = table;
    }

    public static class UpdateRecord {
        public String before;
        public String after;

        public UpdateRecord(String before, String after) {
            this.before = before;
            this.after = after;
        }

        @Override
        public String toString() {
            return "{\"before\"=\"" + before + "\"," +
                    "\"after\"=" + after + "\"}";
        }
    }

}
  • 监控执行类
public class mysql {
    private static final Map<Long, HashMap<String, String>> dbMap = new HashMap<>();

    public static void main(String[] args) {

        BinaryLogClient client = new BinaryLogClient("127.0.0.1", 3306, "root", "123456");
        client.setServerId(1);

        client.registerEventListener(event -> {
            EventData data = event.getData();
            if (data instanceof TableMapEventData) {
                TableMapEventData tableMapEventData = (TableMapEventData) data;
                if (!dbMap.containsKey(tableMapEventData.getTableId())) {
                    dbMap.put(tableMapEventData.getTableId(), new HashMap<String, String>(){{
                        put("database",tableMapEventData.getDatabase());
                        put("table", tableMapEventData.getTable());
                    }});
                }
            }
            if (data instanceof UpdateRowsEventData) {
                format(((UpdateRowsEventData) data).getTableId(), 0, ((UpdateRowsEventData) data).getRows());
            } else if (data instanceof WriteRowsEventData) {
                format(((WriteRowsEventData) data).getTableId(), 1, ((WriteRowsEventData) data).getRows());
            } else if (data instanceof DeleteRowsEventData) {
                format(((DeleteRowsEventData) data).getTableId(), -1, ((DeleteRowsEventData) data).getRows());
            }
        });

        try {
            client.connect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 0 update, 1 insert, -1 delete
    public static void format(Long tableId, int type,  List<?> data) {
        MySQLRecord records = new MySQLRecord(dbMap.get(tableId).get("database"), dbMap.get(tableId).get("table"));
        for (Object row : data) {
            records.setRecord(new MySQLRecord.UpdateRecord(
                    type == 0 ? Arrays.toString((Object[]) ((Map.Entry<?, ?>) row).getKey()) :
                            type == 1 ? null : Arrays.toString((Object[]) row),
                    type == 0 ? Arrays.toString((Object[]) ((Map.Entry<?, ?>) row).getValue()) :
                            type == 1 ? Arrays.toString((Object[]) row) : null));
        }
        System.out.println(records);
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/332982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构复习(三)顺序表oj

目录 27. 移除元素 26. 删除有序数组中的重复项 88. 合并两个有序数组 27. 移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外…

多数据库学习之GBase8s查询数据库表元信息常用SQL

多数据库学习之GBase8s查询数据库表元信息常用SQL简介常用SQL创建用户创建数据库及模式获取表元数据其他参考链接简介 背景介绍 GBase 8t是基于IBM informix源代码、编译和测试体系自主研发的交易型数据库产品。 南大通用安全数据库管理系统&#xff08;简称 GBase 8s&#xff…

Linux基础命令2(常见的文件相关命令)

目录 查找文件命令 pwd 显示当前所在的工作目录&#xff08;Print working directory&#xff09; cd 切换命令&#xff08;change directory&#xff09; ls 查看目录下的文件&#xff08;list&#xff09; tree 查看目录下的子目录&#xff08;查看目录结构&#…

Grafana 系列文章(十二):如何使用Loki创建一个用于搜索日志的Grafana仪表板

概述 创建一个简单的 Grafana 仪表板, 以实现对日志的快速搜索. 有经验的直接用 Grafana 的 Explore 功能就可以了. 但是对于没有经验的人, 他们如何能有一个已经预设了简单的标签搜索的仪表板&#xff0c;以帮助一些团队在排除故障时快速找到他们正在寻找的东西。虽然 Expl…

云仓仓储的运行模式是什么?

仓库能够简单地定义为一个规划空间&#xff0c;通常是一个用于处置和贮存货物的大型商业建筑。因而&#xff0c;仓储是指在这样一个规划空间中存储和处置货物所触及的一切过程。仓库中常见的货物包括&#xff1a;;机械零配件、建筑资料、废品农产品、家具和电子产品。仓库中的一…

【面试题】经典面试题:让 a == 1 a == 2 a == 3 成立?

一、问题解析 if (a == 1 && a == 2 && a == 3) {console.log(Win) } 复制代码 如何打印除Win? 看到题目的第一眼,我是蒙蔽的.怎么可能会有如此矛盾的情况发生呢?就相当于一个人怎么可能即是小孩,又是成年人,还是老年人呢? 冷静下来,发现一些端倪。

VHDL语言基础-组合逻辑电路-概述

目录 概述&#xff1a; 组合逻辑电路&#xff1a;——电路无记忆功能 组合逻辑电路的设计方法&#xff1a; 传统的设计方法&#xff1a;采用标准组件进行设计 组合逻辑电路的设计方法&#xff1a; 两种设计方法的比较&#xff1a; 概述&#xff1a; 数字电路按其完成逻辑…

[Android]图片加载库Glide

目录 Glide的介绍 Glide的基本使用 指定图片的格式 Glide占位符 指定图片的大小 过渡动画 图片变换 Generated API Glide的介绍 Glide是一个快速高效的Android图片加载库&#xff0c;可以自动加载网络&#xff0c;本地文件&#xff0c;app资源中的文件&#xff0c;注重于平…

数据存储技术复习(二)未完

module3存储是数据中心内的核心元素。请说明常用的存储选项及其特点。磁盘驱动器&#xff1a;具有很大的存储容量&#xff0c;随机读/写访问闪存驱动器&#xff1a;使用半导体介质&#xff0c;提供高性能&#xff0c;低功耗2&#xff0e;若某磁盘驱动器显示每个磁道有八个扇区&…

标准舆情监测平台解决方案及流程,TOOM舆情监测工作计划有哪些?

舆情监测流程一般包括&#xff1a;数据收集、数据分析、信息汇报三个部分。首先&#xff0c;通过多种途径收集舆情数据&#xff0c;如网络媒体、社交媒体、博客、论坛等;其次&#xff0c;对收集的数据进行分析&#xff0c;统计舆情趋势、舆情类型等;最后&#xff0c;根据舆情分…

【Java】TCP的三次握手和四次挥手

三次握手 TCP三次握手是一个经典的面试题&#xff0c;它指的是TCP在传递数据之前需要进行三次交互才能正式建立连接&#xff0c;并进行数据传递。&#xff08;客户端主动发起的&#xff09;TCP之所以需要三次握手是因为TCP双方都是全双工的。 什么是全双工&#xff1f; TCP任何…

Print: Entry, “:CFBundleIdentifier“, Does Not Exist解决办法

首先执行react-native info查看我的电脑环境是&#xff1a; React Native Environment Info: System: OS: macOS 10.15.5 CPU: (8) x64 Intel(R) Core(TM) i7-4870HQ CPU 2.50GHz Memory: 103.91 MB / 16.00 GB Shell: 5.7.1 - /bin/zsh Binaries: Node: 12.22.12 - ~/.nvm/ve…

vulnhub靶机试验DC-1

按照大佬的文章学习了一 遍&#xff1a;https://blog.csdn.net/ierciyuan/article/details/127282461 前言 参考大佬的blog进行一次实践&#xff0c;入门级的学习&#xff0c;写得不好请见谅&#xff01; 本次靶场实战涉及信息收集、漏洞查找与利用、getshell、数据库渗透、密…

MySQL进阶篇之视图(view)

04、视图/存储过程/触发器 4.1、视图(view) 4.1.1、简介及基本语法 1、介绍 视图&#xff08;View&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来自定义视图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。 通…

源码级别的讲解JAVA 中的CAS

没有CAS之前实现线程安全 多线程环境不使用原子类保证线程安全&#xff08;基本数据类型&#xff09; public class T3 {volatile int number 0;//读取public int getNumber(){return number;}//写入加锁保证原子性public synchronized void setNumber(){number;} }多线程环…

代码随想录【Day09】|28. 找出字符串中第一个匹配项的下标、459. 重复的子字符串、《字符串总结》

28. 找出字符串中第一个匹配项的下标 题目链接 题目描述&#xff1a; 实现 strStr() 函数。 给定一个 haystack 字符串和一个 needle 字符串&#xff0c;在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在&#xff0c;则返回 -1。 示例 1: 输…

计算机图形学:改进的中点BH算法

作者&#xff1a;非妃是公主 专栏&#xff1a;《计算机图形学》 博客地址&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录专栏推荐专栏系列文章序一、改进缘由二、…

qt连接mysql,自编译生成驱动文件

CMakeninja编译qt所需的mysql驱动文件 想用qt连接mysql数据库&#xff0c;但是在qt6.0版本之后都不自带驱动需要自己编译&#xff0c;过程中由于不熟悉cmake以及ninja&#xff0c;踩了一百个坑&#xff0c;简单记录一下。 写在前面 csdn上也有很多大佬写得用cmake-gui来编译…

代码随想录算法训练营第43天DP动态规划62不同路径63 不同路径2

文章目录LeetCode 62不同路径题目讲解思路LeetCode 63 不同路径ii题目讲解思路小结LeetCode 62不同路径 题目讲解 思路 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 根据题意来看机器人只能进行向右…

单链表的基本操作

此代码不可运行&#xff0c;含伪代码。一、 定义数据域typedef struct{ char num[8];char name[8];int score;}ElemType;二、 定义一个链表typedef struct LNode{ElemType data; //链表中结点的数据域 struct Lnode *next; //为指向下一个结点的指针域&#xff0c;并且所指向的…