【易客吧】_全网激活码总代_激活码商城

您现在的位置是:首页 > 热门资讯 > 正文

热门资讯

为高吞吐量应用程序设计和实现可扩展的 MySQL 定时任务 (高吞吐量计算)

用户投稿2024-04-18热门资讯17
为高吞吐量应用程序设计和实现可扩展的 MySQL 定时任务概述在处理高吞吐量的应用程序中,定时任务是一个经常遇到的挑战。在 MySQL 中,定时任务通常通过 [事件计划程序](来实现。随着任务数量和应用程序工作负载的增加,事件计划程序可能会成为瓶颈。本文将探讨如何设计和实现可扩展的 MySQL 定时任务,以满足高吞吐量应用程序的需求。我们将介绍各种技术,包括:利用队列系统使用工作进程池水平扩展任务监控和调整利用队列系统队列系统,如 RabbitMQ 或 Kafka,提供了将任务从数据库解耦的一种有效方法。当事件触发器激活时,它可以将任务发送到队列,而不是直接执行。工作进程池可以从队列中获取并执行任务,从而减少了 MySQL 上的负载。这种方法的好处包括:可扩展性:队列可以轻松水平扩展,以处理增加的负载。可靠性:即使 MySQL 发生故障,队列仍然可以存储任务,确保不会丢失任务。并行处理:工作进程池允许并行执行任务,进一步提高吞吐量。使用工作进程池工作进程池是一组进程或线程,它们从队列中获取并执行任务。每个工作进程处理一个任务,从而最大限度地提高资源利用率。使用工作进程池的优点包括:提高吞吐量:通过并行执行任务,工作进程池可以显著提高吞吐量。灵活性:可以根据需要轻松调整工作进程池的大小,以匹配应用程序的工作负载。故障恢复:如果工作进程失败,队列系统可以将任务重新排队,然后由另一个工作进程执行。水平扩展任务随着应用程序工作负载的增长,可能需要水平扩展定时任务。这意味着在多个服务器上分配任务。有多种方法可以实现此目的,包括:数据库分片:将数据和任务分布在多个数据库实例上。任务分片:将不同类型的任务分配给不同的服务器。分布式队列:使用分布式队列系统,如 Apache Pulsar,将任务存储在多个服务器上。通过水平扩展任务,您可以提高吞吐量并避免单点故障。监控和调整持续监控和调整定时任务至关重要,以确保它们有效地工作。以下是一些关键指标:任务处理时间:跟踪任务从排队到执行所需的时间。队列大小:监测队列中的任务数量,以识别潜在的瓶颈。工作进程池利用率:确保工作进程池得到充分利用,但又不会过度负载。通过监控这些指标,您可以根据需要调整队列大小、工作进程池参数和任务分配策略,以优化定时任务的性能。结论通过利用队列系统、工作进程池、水平扩展和监控,您可以设计和实现可扩展的 MySQL 定时任务,以满足高吞吐量应用程序的需求。这种方法将帮助您处理大量任务,提高应用程序的性能和可靠性。示例代码以下是一个使用 RabbitMQ 和 Node.js 实现的可扩展 MySQL 定时任务的示例代码: javascript // 引入依赖项 const mysql = require('promise-mysql'); const amqp = require('amqplib');// 连接到 MySQL 和 RabbitMQ const mysqlPool = awaitmysql.createPool({host: 'localhost',user: 'root',password: 'password',database: 'mydb' });const rabbitmqConnection = await amqp.connect('amqp://localhost'); const rabbitmqChannel = await rabbitmqConnection.createChannel();// 监听事件计划程序事件 rabbitmqChannel.consume('events', async (message) => {// 从消息中获取任务数据const taskData = JSON.parse(message.content.toString());// 使用 MySQL 执行任务try {const result = await mysqlPool.query(taskData.sql);// 向 RabbitMQ 发送成功响应rabbitmqChannel.ack(message);console.log('任务成功执行。');} catch (err) {// 向 RabbitMQ 发送失败响应rabbitmqChannel.nack(message);console.log('任务执行失败。');} });通过这种方法,任务可以从 MySQL事件计划程序解耦,并通过 RabbitMQ 异步执行。工作进程池可以从队列中获取并执行任务,从而提高吞吐量和可靠性。

使用Java构造高可扩展应用

当CPU 进入多核时代之后 软件的性能调优就不再是一件简单的事情 没有并行化的程序在新的硬件上可能会运行得比从前更慢 当 CPU 数目增加的时候 芯片制造商为了取得最佳的性能/功耗比 降低 CPU 的运行频率是一件非常明智的事情 相比 C/C++ 程序员而言 利用 Java 编写多线程应用已经简单了很多 然而 多线程程序想要达到高性能仍然不是一件容易的事情 对于软件开发人员而言 如果在测试时发现并行程序并不比串行程序快 那不是一件值得惊讶的事情 毕竟 在多核时代之前 受到广泛认可的并行软件开发准则通常过于简单和武断

在本文中 我们将介绍使提高Java 多线程应用性能的一般步骤 通过运用本文提供的一些简单规则 我们就能获得具有高性能的可扩展的应用程序

为什么性能没有增长?

多核能带来性能的大幅增长 这很容易通过简单的一些测试来观察到 如果我们写一个多线程程序 并在每个线程中对一个本地变量进行累加 我们可以很容易的看到多核和并行带来的成倍的性能提升 这非常容易做到 不是吗?在 参考资源 里我们给出了一个例子 然而 与我们的测试相反 我们很少在实际软件应用中看到这样完美的可扩展性 阻碍我们获得完美的可扩展性有两方面的因素存在 首先 我们面临着理论上的限制 其次软件开发过程中也经常出现实现上的问题 让我们看看 图 中的三条性能曲线

图 性能曲线

作为追求完美的软件工程师 我们希望看到随着线程数目的增长程序的性能获得线性的增长 也就是图 中的蓝色直线 而我们最不希望看到的是绿色的曲线 不管投入多少新的 CPU 性能也没有丝毫增长 (随着 CPU 增长而性能下降的曲线在实际项目中也存在) 而图中的红色线条则说明通常的 法则并不适用于可扩展性方面 假设程序中有 % 的计算只能串行进行 那么其扩展性曲线如红线所示 由图可见 当 % 的代码可以完美的并行时 在 个 CPU 存在的情况下 我们也只能获得大约 倍的性能 如果任务中具有无法并行的部分 那么在现实世界 我们的性能曲线大致上会位于图 中的灰 *** 域

在这篇文章中 我们不会试图挑战理论极限 我们希望能解释一个 Java 程序员如何能够尽可能的接近极限 这已经不是一个容易的任务

是什么造成了糟糕的可扩展性?

可扩展性糟糕的原因有很多 其中最为显著的是锁的滥用 这没有办法 我们就是这样被教育的 想要多线程安全吗?那就加一个锁吧 想想 Python 中臭名昭著的 Global Intepreter Lock 还有 Java 中的 Collections synchronizedXXXX() 系列方法 跟随巨人的做法有什么不好吗?是的 用锁来保护关键区域非常方便 也较容易保证正确性 然而锁也意味着只有一个进程能进入关键区域 而其他的进程都在等待!如果观察到 CPU 空闲而软件执行缓慢 那么检察一下锁的使用是一个明智的做法

对于 Java 程序而言 Performance Inspector 中的 Java Lock Monitor 是一个不错的开源工具

[NextPage]

对一个多线程应用进行调优

下面 我们将提供一个例子程序并展示如何在多核平台上获得更好的可扩展性 这个例子程序展示了一个假想的日志服务器 它接收来自多个源的日志信息并将其统一保存到文件系统中 为了简单起见 我们的例子代码中不包含任何的网络相关代码 Main() 函数将启动多个线程来发送日志信息到日志服务器中 对于性急的读者 让我们先看看调优的结果

图 日至服务器调优结果

在上图中 蓝色的曲线是一个基于 Lock 的老式日志服务器 而绿色的曲线是我们进行了性能调优之后的日志服务器 可以看到 LogServerBad 的性能随线程数目的增加变化很小 而 LogServerGood 的性能则随着线程数目的增加而线性增长 如果不介意使用第三方的库的话 那么来自 Project KunMing 的 LockFreeQueue 可以进一步提供更好的可扩展性

图 使用 Lock free 的数据结构

在上图中 第三条曲线表示用 LockFreeQueue 替换标准库中的 ConcurrentLinkedQueue 之后的性能曲线 可以看到 如果线程数目较少时 两条曲线差别不大 但是单线程数目增大到一定程度之后 Lock Free 的数据结构具有明显的优势

在下文中 将介绍在上述例子中使用的可以帮助我们创建高可扩展 Java 应用的工具和技巧

[NextPage]

使用 JLM 分析应用程序

JLM 提供了 Java 应用和 JVM 中锁持有时间和冲突统计 具体提供以下功能

对冲突的锁进行计数

成功获得锁的次数

递归锁的次数

申请锁的线程被阻塞等待的次数

锁被持有的累计时间 对于支持 Tier Spin Locking 的平台 还可以获得以下信息 :

请求线程在内层(spin loop)请求锁的次数

请求线程在外层(thread yield loop)请求锁的次数

使用 rtdriver 工具收集更详细的信息

jlmlitestart 仅收集计数器

jlmstart 仅收集计数器和持有时间统计

jlmstop 停止数据收集

jlmdump 打印数据收集并继续收集过程

从锁持有时间中去除废品收集(Garbage Collection GC)的时间

GC 时间从 GC 周期中所有被持有的锁的持有时间中去除

使用 AtomicInteger 进行计数

通常 在我们实现多线程使用的计数器或随机数生成器时 会使用锁来保护共享变量 这样做的弊端是如果锁竞争的太厉害 会损害吞吐量 因为竞争的同步非常昂贵

volatile 变量虽然可以使用比同步更低的成本存储共享变量 但它只可以保证其他线程能够立即看到对 volatile 变量的写入 无法保证读 修改 写的原子性 因此 volatile 变量无法用来实现正确的计数器和随机数生成器

从 JDK 开始 ncurrent atomic 包中引入了原子变量 包括 AtomicInteger AtomicLong AtomicBoolean 以及数组 AtomicIntergerArray AtomicLongArray 原子变量保证了 ++ —— += = 等操作的原子性 利用这些数据结构 您可以实现更高效的计数器和随机数生成器

加入轻量级的线程池—— Executor

大多数并发应用程序是以执行任务(task)为基本单位进行管理的 通常情况下 我们会为每个任务单独创建一个线程来执行 这样会带来两个问题 一 大量的线程(> )会消耗系统资源 使线程调度的开销变大 引起性能下降 二 对于生命周期短暂的任务 频繁地创建和消亡线程并不是明智的选择 因为创建和消亡线程的开销可能会大于使用多线程带来的性能好处

一种更加合理的使用多线程的方法是使用线程池(Thread Pool) ncurrent 提供了一个灵活的线程池实现 Executor 框架 这个框架可以用于异步任务执行 而且支持很多不同类型的任务执行策略 它还为任务提交和任务执行之间的解耦提供了标准的方法 为使用 Runnable 描述任务提供了通用的方式 Executor 的实现还提供了对生命周期的支持和 hook 函数 可以添加如统计收集 应用程序管理机制和监视器等扩展

在线程池中执行任务线程 可以重用已存在的线程 免除创建新的线程 这样可以在处理多个任务时减少线程创建 消亡的开销 同时 在任务到达时 工作线程通常已经存在 用于创建线程的等待时间不会延迟任务的执行 因此提高了响应性 通过适当的调整线程池的大小 在得到足够多的线程以保持处理器忙碌的同时 还可以防止过多的线程相互竞争资源 导致应用程序在线程管理上耗费过多的资源

Executor 默认提供了一些有用的预设线程池 可以通过调用 Executors 的静态工厂方法来创建

newFixedThreadPool 提供一个具有最大线程个数限制的线程池 newCachedThreadPool 提供一个没有最大线程个数限制的线程池 newSingleThreadExecutor 提供一个单线程的线程池 保证任务按照任务队列说规定的顺序(FIFO LIFO 优先级)执行 newScheduledThreadPool 提供一个具有最大线程个数限制线程池 并支持定时以及周期性的任务执行

使用并发数据结构

Collection 框架曾为 Java 程序员带来了很多方便 但在多核时代 Collection 框架变得有些不大适应 多线程之间的共享数据总是存放在数据结构之中 如 Map Stack Queue List Set 等 Collection 框架中的这些数据结构在默认情况下并不是多线程安全的 也就是说这些数据结构并不能安全地被多个线程同时访问 JDK 通过提供 SynchronizedCollection 为这些类提供一层线程安全的接口 它是用 synchronized 关键字实现的 相当于为整个数据结构加上一把全局锁保证线程安全

ncurrent 中提供了更加高效 collection 如 ConcurrentHashMap/Set ConcurrentLinkedQueue ConcurrentSkipListMap/Set CopyOnWriteArrayList/Set 这些数据结构是为多线程并发访问而设计的 使用了细粒度的锁和新的 Lock free 算法 除了在多线程条件下具有更高的性能 还提供了如 put if absent 这样适合并发应用的原子函数

[NextPage]

其他一些需要考虑的因素

不要给内存系统太大的压力

如果线程执行过程中需要分配内存 这在 Java 中通常不会造成问题 现代的 JVM 是高度优化的 它通常为每个线程保留一块 Buffer 这样在分配内存时 只要 buffer 没有用光 那么就不需要和全局的堆打交道 而本地 buffer 分配完毕之后 JVM 将不得不到全局堆中分配内存 这样通常会带来严重的可扩展性的降低 另外 给 GC 带来的压力也会进一步降低程序的可扩展性 尽管我们有并行的 GC 但其可扩展性通常并不理想 如果一个循环执行的程序在每次执行中都需要分配临时对象 那么我们可以考虑利用 ThreadLocal 和 SoftReference 这样的技术来减少内存的分配

使用 ThreadLocal

ThreadLocal 类能够被用来保存线程私有的状态信息 对于某些应用非常方便 通常来讲 它对可扩展性有正面的影响 它能为各个线程提供一个线程私有的变量 因而多个线程之间无须同步 需要注意的是在 JDK 之前 ThreadLocal 有着相当低效的实现 如果需要在 JDK 或更老的版本上使用 ThreadLocal 需要慎重评估其对性能的影响 类似的 目前 JDK 中的 ReentrantReadWriteLock 的实现也相当低效 如果想利用读锁之间不互斥的特性来提高可扩展性 同样需要进行 profile 来确认其适用程度

锁的粒度很重要

粗粒度的全局锁在保证线程安全的同时 也会损害应用的性能 仔细考虑锁的粒度在构建高可扩展 Java 应用时非常重要 当 CPU 个数和线程数较少时 全局锁并不会引起激烈的竞争 因此获得一个锁的代价很小(JVM 对这种情况进行了优化) 随着 CPU 个数和线程数增多 对全局锁的竞争越来越激烈 除了一个获得锁的 CPU 可以继续工作外 其他试图获得该锁的 CPU 都只能闲置等待 导致整个系统的 CPU 利用率过低 系统性能不能得到充分利用 当我们遇到一个竞争激烈的全局锁时 可以尝试将锁划分为多个细粒度锁 每一个细粒度锁保护一部分共享资源 通过减小锁的粒度 可以降低该锁的竞争程度 ncurrent ConcurrentHashMap 就通过使用细粒度锁 提高 HashMap 在多线程应用中的性能 在 ConcurrentHashMap 中 默认构造函数使用 个锁保护整个 Hash Map 用户可以通过参数设定使用上千个锁 这样相当于将整个 Hash Map 划分为上千个碎片 每个碎片使用一个锁进行保护

结论

通过选择一种合适的 profile 工具 检查 profile 结果中的热点区域 使用适合多线程访问的数据结构 线程池 细粒度锁减小热点区域 并重复此过程不断提高应用的可扩展性

lishixinzhi/Article/program/Java/gj//

2019数据架构选型必读:1月数据库产品技术解析

本期目录

DB-Engines数据库排行榜

新闻快讯

一、RDBMS家族

为高吞吐量应用程序设计和实现可扩展的 MySQL 定时任务 (高吞吐量计算) 第1张

二、NoSQL家族

三、NewSQL家族

四、时间序列

五、大数据生态圈

六、国产数据库概览

七、云数据库

八、推出dbaplus Newsletter的想法

九、感谢名单

为方便阅读、重点呈现,本期Newsletter(2019年1月)将对各个板块的内容进行精简。需要阅读全文的同学可点击文末 【阅读原文】 或登录Newsletter

如何设计和实现高可用的MySQL

王甲坤,腾讯高级工程师、腾讯云关系型数据库MySQL负责人,拥有多年客户端、数据库研发经验。 在IOS客户端、MySQL、PostgreSQL、SQL Server等产品有丰富的研发和产品策划经验。 下面开始我们今天的主要内容,今天主要是通过什么、为什么、怎么做,这条思路跟大家呈现MySQL的高可用。 首先介绍一下什么是高可用?在我看来就是业务在高质量的情况下,对用户提供服务的可运行的总时长。 其实我们从事MySQL相关的工作,大家对9这个数字比较敏感,大家选择云厂商云产品的时候,首先会看它的数据库有几个9。 目前腾讯云MySQL可以做到99.95,全年在25分钟的样子。 据我了解,高可用最高是能做到3个9,1个6,做到4个9很困难,做到5个9就是极限了。 为什么我们要做高可用?因为我们不可控的因素太多了,比如说,挖挖机,我记得基本上每隔一年都会出现这种类似的事件,让我记忆犹新的是2015年杭州萧山的某个主干网被刮断,导致阿里的部分服务不可用。 另外,还有类似的一些停电,或者一些天灾等等。 值得一提是,运维人员的一些操作失误案例,rm整个目录或者drop表,民间有说法叫从删库到跑路。 不可控制的因素很多,你的数据、用户是你的,如果不可控的话,你的业务上不去。 一般来说,有两个指标会被当作衡量的标准,第一是RPO,第二是RTO。 RPO从故障开始到业务恢复所丢失的数据量,RTO就是从故障开始到业务恢复所耗费的时长,两者都是越短越好。 我们怎么做呢?一般来说业界有三种方式,左边是基于单机存储方式,这种方式在游戏场景比较多,大家上层是用单独的计算机节点,下层用三副本保证数据的可靠性。 在计算节点发生故障以后可以快速迁移到另一个计算节点,当然我们腾讯云的MySQL已经推出了这种模式,相对来说非常廉价,是基础版,大家在官网都可以购买到这种模式。 第二种是基于共享存储方式,也叫share disk模式,这种比较典型的是oracle的RAC架构。 底层基于共享存储的方式,上层采用多个计算节点,某个计算节点故障可立即从ip列表中提出,不影响用户访问。 第三种就是基于数据复制模式,也就share nothing模式,通过数据传输、复制协议达到两台主机数据一致性,也是本次讲解的重点。 另外,除了存储节点的高可用,其整个链路也需要高可用,比如,咱们的IDC机房,交换机,以及主机服务器等。 下面我们介绍下基础设施的高可用。 大家经常听到几个术语,第一是同城双活,第二是两地三中心,两地三中心对于金融相关的场景是个强需求,其实说白了就是说我们在同城两个节点相差十公里之外有两个数据中心,在100公里异地以外有另个灾备中心,保证了机房的高可用。 另外包括网络、主机,其实架构上是这样的,至少说你的交换机网络都有备份,一个倒了以后,另一个需要替换上去。 下面进入我们的重点,基于数据复制的高可用,首先介绍一下备份,备份确实是非常重要的,而且备份是一个实在没办法最后的一个保障,所以说建议大家不管是在云上用的业务,还是自己的IDC尽量做好备份。 MySQL备份基本上是这两种:逻辑备份、物理备份。 逻辑备份通常使用官方的MySQLDump与第三方工具MyDumper,MyDumper优势在于多线程备份,速率快。 物理备份使用Percona的xtrabackup,可以不落盘,通过基于流式并发与压缩,生产出成功率较高、速率较快并且暂用存储空间较低的备份。 最后一种就是快照,我们腾讯云的基础版的备份就是通过快照生成的。 那基于数据复制方式,一般是主从两个节点,数据怎么保证一致性呢?其实是通过复制协议进行数据传输,通过Switch切换保证故障以后服务能够尽快恢复。 右边的图基本和腾讯云MySQL差不多的架构,我们采用了一主一从的方式,从节点只负责故障的转移,当主节点挂了以后,通过自动故障探测与自动切换,从而做到业务尽快恢复。 另外针对读写分离,腾讯云MySQL现可以支持一主挂5个只读节点。 下面介绍一下复制,在介绍复制之前有必要介绍一个重要的概念:binlog,binlog是二进制文件,主要记录用户对数据库更新的sql信息,binlog是什么样子呢?它是在磁盘上是这个样子,使用show binlog events后它是这样的,里面会记录一些元信息,比如位点、事件等等,我们通过MySQL官方解析工具mysqlbinlog解析后是这样的,里面sql语句是使用base64编码的,解码后是这样的,可以看到这里是条插入语句。 那什么时候写binlog呢?大家来看这个图,我们知道事务提交有两个阶段:prepare与commit,请问是哪个阶段写binlog呢?binlog其实是在prepare后commit前写入的,同时写事务过程中,会产生redolog与undolog,那这两者有什么区别呢?我们知道MySQL是多引擎的关系型数据库,binlog是MySQL Server层的日志,而redolog是MySQL引擎InnoDB层的日志;另外一个不同是两者写入时机不同,redolog是prepare阶段每执行sql语句就写redo了,而binlog是在prepare完commit前写的。 那MySQL在主从架构下怎么保证数据一致性呢?众所众知,MySQL为了保证性能,数据是先写内存后落盘的。 当你数据库运行的时候,发生了宕机,机器再次恢复的时候可能是部分数据落盘了,部分未落盘。 这时,mysql是找到binlog最新同步的位点或GTID,来确定redolog或者undolog中哪些实例需要回滚,哪些事务需要重做。 另外,在写日志的时候,比如redolog或binlog,MySQL为保证高性能,也是先写内存后落盘的,所以日志的落盘策略也会影响数据的一致性。 为保证数据的一致性,建议大家将涉及日志的参数配置为“双1”,也就是如图上所示。 下面我们来看看复制整个流程,其实很简单,Master通过dump线程将binlog落盘,在Slave上会有两个线程,分别是IO线程和SQL线程。 IO线程接受来自Master的binlog并落地形成Relaylog,SQL线程并行读取relaylog中的sql信息,执行回放动作。 一般来说, 复制分三种:异步复制、半同步、强同步。 这三者的区别在于何时将sql执行的结果反馈给客户端。 异步复制,Master不管Slave,Master执行sql完毕后立即返回给客户端,这种方式性能最好,但是存在数据不一致的可能;强同步呢,Master完全关心Slave,等待Slave将relaylog回放后才返回给客户端,这种方式能够保证数据强一致,但是其性能有一定损耗;半同步则是Master部分关心Slave,认为只要binlog传输到Slave侧,落为relaylog后,即可以返回给客户端了。 半同步是一种兼顾的实现,一方面保证数据一致性,另一方面兼顾了数据库的性能。 在复制过程中,我们经常遇到延迟问题,大家看图中所示,复制经历三个阶段:Dump线程落盘binlog、IO线程落盘relaylog、以及SQL线程回放,请问三个步骤里面哪个步骤是一个瓶颈?是SQL线程,是因为SQL线程在回放日志过程中是串行执行sql的,而Master对外是并行提供服务的。 所以这里瓶颈是SQL线程。 大家可用通过开启并行复制来解决延迟问题,MySQL5.6基于库级别并行复制;MySQL 5.7基于逻辑时钟并行复制,也就是表级别的并行;而MySQL8.0则是行级别的并行复制,粒度更细,复制效率更高。 刚才是说在协议级别进行复制,其实还有一种方式是块级别的数据复制,其不关心上层是什么,只需要保证在磁盘层面数据复制即可。 当然这种方式的话,应用的比较少。 说完复制后,咱们来说一下切换,其实MySQL官方之前并没有提供故障自动发现与转移的能力,基本上靠第三方工具来实现。 第一种是Keepalived,Master和Slave相互探测对方,时刻询问对方存活状态。 当出现网络抖动或者网络出现问题的时候,可能会出现脑裂问题,变成了两主,数据就写错乱了。 第二种就是MMM的方式, M1M2互为主备,再加上一个Slave节点做冗余。 从图上看,虽然是双主,但该模式下同一时间点下只能有一个节点可以写,当发现这个主写节点出现故障,会将vip切换到另一个主上比。 整体看,这种方式比较老,问题比较多。 第三种是MHA,其应用广泛,这种方式是由复制组与管理节点组成,每个复制组里是由至少三个数据节点组成,数据节点上部署监控agent,定时上报到管理节点,当主节点出现问题时,由管理节点裁决是否切换到从节点。 腾讯云是自己实现了一套故障检测,结构如右边的图,由高可用保证的Monitor节点来进行故障检测与切换。 另外,目前我们还在做MySQL高可用的重构,届时能够做到故障检测恢复30秒钟以内,大大提高了高可用。 下面我们来说下集群的高可用架构,比较有名的就是PXC、MGC、MGR,PXC和MGC是结构比较类似,MGR是官方提供的,具有故障转移的高可用架构。 大体的层级是这样的,MGR以插件的形式存在的,MGR主要是把复制协议进行改造,因为MGR支持多活,所以这里另一个重点是冲突检测,若多个节点同时写同一主键时,依照哪个为准呢?MGR是采用基于Paxos协议实现的冲突检测。 下面,我们大致看下结构,MGR是支持多个节点写,即多活,支持某个节点挂了后自动剔除,恢复后自动加入集群。 这张图是介绍一下MGR数据流逻辑,图上有三个节点构成最小MGR集群。 假设DB1有一次写提交,在Prepare阶段,MGR插件会生成一个叫WriteSet的集合,并将其广播给其他节点。 这个WriteSet集合包含此次提交的binlog和更新的唯一键,此唯一键由db名、表名和主键组成。 这里可以看出MGR有个限制,表中必须要有主键,要不无法进行冲突检测。 我们再说回来当节点收到这一信息时,会进行比对,每个节点都有一个缓存,保存当前同步情况,即唯一键对应的GTID SET。 通过比对后将结果返回给DB1,只要多于半数的节点返回说OK,可以提交,那DB1接下来就会执行binlog的落盘操作,然后返回OK到客户端。 其他节点则执行写Relaylog的动作,接下来进行回放的动作。 若多数节点返回冲突,DB1则执行回滚操作,其他节点会drop掉复制过来的binlog。 其实PXC和MGC思路是差不多,应该说是MGR借鉴的,因为PXC和MGC是比较早就出来的,这里大同小异,主节点将WriteSet写集合广播出去,广播完后进行验证与裁决。 最后我们说一下NewSQL高可用架构,首先对AWS表示致敬,孵化出非常优秀的NewSQL产品-Aurora。 那Aurora是怎么产生出来的呢?这与AWS数据库架构有关。 我们来看看这个图,AWS数据库是架构在虚拟机与云盘上的,我们都知道MySQL的log比较多,所以很多IO是通过耗时较高的网络来完成的,因此AWS这种架构网络IO是它的瓶颈,性能也跑不上去。 在此基础上,我们来认识下Aurora。 Aurora是计算与存储分离的架构,典型的share disk 的结构。 底层存储采用6副本,部署在三个不同的AZ上,可以保证一个AZ挂了,或者至多两个AZ的一个副本丢失的情况下数据不丢失,业务可以正常对外服务。 Aurora的理念是“日志即数据库”,其把MySQL存储层进行了彻底的改造,摒弃了很多LOG,只留下了Redolog,具备将redolog转换到Innodb page的能力。 通过这种方式,Aurora宣称其减少至少85%比例的IO。 另外其把备份和回档下沉到存储节点,使得备份恢复更快并得到保障。 Aurora整体感觉相对比较接地气,成本相对比较低。 另一个就是阿里云的Polar,理念和AWS不同,阿里云觉得未来网络不是问题,未来网络可以接近总线的质量,所以是架构在RDMA网络的机房里,日志方面大动作较少,保证后续MySQL社区新特性可快速迭代近来。 Polardb也是share disk的架构,其存储节点是通ParallelRaft协议保证数据的完备性。 可见这也是个伟大的架构,但是相对来说成本比较高一些。 我们腾讯云自己的NewSQL在研发中,只是目前还没有正式上线,我们的名字叫CynosDB,相比来说我们的理念是兼顾两者,未来在高网络新硬件的基础实施下,会发挥更大的性能,更稳健的服务和更高的可用性。 请大家拭目以待。 本次我的分享就到此为止。 Q & AQ:我想问一下在腾讯游戏的高并发行业里面,我们主要采用哪种架构?A:腾讯内部有很多自研项目,但基本上我们是基于数据复制的方式。 内部有phxsql等分布式集群架构。 Q:如何在高并发情况下,保证总库的定延时呢?A:可以开启并行复制,业务做分库分表,分散到多个实例上。 Q:比如说像游戏类的,在游戏高峰期的话会有很多人同时在线,这种情况下怎么在后台看数据呢?A:可以对比较热的数据进行分层,前一层可以通过KV方式缓存,比如Redis,来提高热数据的读取,后一层使用MySQL,定期将数据同步落盘。 Q:这种情况下怎么保证数据库是一致的呢?A:写数据可以不经过KV缓存,直接写MySQL数据库,读取时,缓存内没有数据,需要从DB中捞取出来。 另外,KV缓存也有落地能力,非关键数据也可以不使用MySQL落地。 相关阅读【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识此文已由作者授权腾讯云+社区发布,更多原文请点击搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!海量技术实践经验,尽在云加社区!如何设计和实现高可用的MySQL标签:负责人基础问题特性目录三种方式共享完全ali

若对本页面资源感兴趣,请点击下方或右方图片,注册登录后

搜索本页相关的【资源名】【软件名】【功能词】或有关的关键词,即可找到您想要的资源

如有其他疑问,请咨询右下角【在线客服】,谢谢支持!

为高吞吐量应用程序设计和实现可扩展的 MySQL 定时任务 (高吞吐量计算) 第2张

发表评论

评论列表

  • 这篇文章还没有收到评论,赶紧来抢沙发吧~
欢迎你第一次访问网站!