GVKun编程网logo

万字长文 | 业内 MySQL 线程池主流方案详解 - MariaDB/Percona/AliSQL/TXSQL/MySQL企业

1

本篇文章给大家谈谈万字长文|业内MySQL线程池主流方案详解-MariaDB/Percona/AliSQL/TXSQL/MySQL企业,同时本文还将给你拓展4.56-MariaDB的密码重置4.57M

本篇文章给大家谈谈万字长文 | 业内 MySQL 线程池主流方案详解 - MariaDB/Percona/AliSQL/TXSQL/MySQL企业,同时本文还将给你拓展4.56-MariaDB 的密码重置 4.57 MariaDB 慢查询日志 4.58 Tomcat_JDK 部署 4.59 zrlog 安装 4.60 Nginx 代理 Tomcat、AliSQL (MySQL 分支) 二次开发编译安装 (Centos)、AliSQL 20170716版本发布 Invisible Indexes 功能和 SELECT FROM UPDATE 语法、AliSQL 20171010版本发布 Sequence兼容PostgreSQL/Oracle语法和升级TLSv1.2等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

万字长文 | 业内 MySQL 线程池主流方案详解 - MariaDB/Percona/AliSQL/TXSQL/MySQL企业

万字长文 | 业内 MySQL 线程池主流方案详解 - MariaDB/Percona/AliSQL/TXSQL/MySQL企业

作者:卢文双 资深数据库内核研发

本文首发于 2023-05-04 22:07:40
https://dbkernel.com

本文主要从功能层面对比 percona-server、mariadb、阿里云 AliSQL、腾讯 TXSQL、MySQL 企业版线程池方案,都基于 MySQL 8.0。

至于源码层面,腾讯、阿里云、MySQL 企业版不开源,percona 借鉴了 mariadb 早期版本的实现,但考虑到线程池代码只有 2000 行左右,相对简单,本文就不做深入阐述。

版本:
MariaDB 10.9,
Percona-Server-8.0.32-24

背景

社区版的 MySQL 的连接处理方法默认是为每个连接创建一个工作线程的one-thread-per-connectionPer_thread)模式。这种模式存在如下弊端:

  • 由于系统的资源是有限的,随着连接数的增加,资源的竞争也增加,连接的响应时间也随之增加,如 response time 图所示。

  • 在资源未耗尽时,数据库整体吞吐随着连接数增加。一旦连接数超过了某个耗尽系统资源的临界点,由于各线程互相竞争,CPU 时间片在大量线程间频繁调度,不同线程上下文频繁切换,徒增系统开销,数据库整体吞吐反而会下降,如下图所示。

Q:如何避免 在连接数暴增时,因资源竞争而导致系统吞吐下降的问题呢?

MariaDB & Percona 中给出了简洁的答案:线程池

线程池的原理在percona blog 中有生动的介绍,其大致可类比为早高峰期间大量汽车想通过一座大桥,如果采用one-thread-per-connection的方式则放任汽车自由行驶,由于桥面宽度有限,最终将导致所有汽车寸步难行。线程池的解决方案是限制同时行驶的汽车数,让桥面时刻保持最大吞吐,尽快让所有汽车抵达对岸。

数据库内核月报文章 《MySQL · 最佳实践 · MySQL 多队列线程池优化》中举了一个高铁买票的例子,也很形象,由于售票员(类比为 CPU 的核数)有限,当有 1000 个用户(类比为数据库连接)都想买票时,如果采用 one-thread-per-connection 的方式,则每个人都有一个专用窗口,需要售票员跑来跑去(CPU 上下文切换,售票窗口越多,跑起来越费力)来为你服务,可以看到这是不够合理的,特别是售票员比较少而购票者很多的场景。如果采用线程池的思想,则不再是每个人都有一个专用的售票窗口(每个客户端对应一个后端线程),而是通过限定售票窗口数,让购票者排队,来减少售票员跑来跑去的成本。

回归到数据库本身,MySQL 默认的线程使用模式是会话独占模式(one-thread-per-connection),每个会话都会创建一个独占的线程。当有大量的会话存在时,会导致大量的资源竞争,同时,大量的系统线程调度和缓存失效也会导致性能急剧下降

线程池线程池功能旨在解决以上问题,在存在大量连接的场景下,通过线程池实现线程复用

  • 当连接多、并发低时,通过连接复用,避免创建大量空闲线程,减少系统资源开销。
  • 当连接多、并发高时,通过限制同时运行的线程数,将其控制在合理的范围内,可避免线程调度工作过多和大量缓存失效,减少线程池间上下文切换和热锁争用,从而对 OLTP 场景产生积极影响。

当连接数上升时,在线程池的帮助下,将数据库整体吞吐维持在一个较高水准,如图所示。

适用场景

线程池采用一定数量的工作线程来处理连接请求,线程池在查询相对较短且工作负载受 CPU 限制的情况下效率最高,通常比较适应于 OLTP 工作负载的场景。如果工作负载不受 CPU 限制,那么您仍然可以通过限制线程数量来为数据库内存缓冲区节省内存。

线程池的不足在于当请求偏向于慢查询时,工作线程阻塞在高时延操作上,难以快速响应新的请求,导致系统吞吐量反而相较于传统 one-thread-per-connection 模式更低。

线程池适用的场景

  • 对于大量连接的 OLTP 短查询的场景将有最大收益。
  • 对于大量连接的只读短查询也有明显收益。
  • 有效避免大量连接高并发下数据库性能衰减。

不太适合用线程池的场景:

  • 具有突发工作负载的场景。在这种场景下,许多用户往往长时间处于非活跃状态,但个别时候又处于特别活跃的状态,同时,对延迟的容忍度较低,因此,线程池节流效果不太理想。不过,即使在这种情况下,也可以通过调整线程的退役频率来提高性能(使用 thread_pool_idle_timeout 参数)。
  • 高并发、长耗时语句的场景。在这种场景下,并发较多,且都是执行时间较长的语句,会导致工作线程堆积,一旦达到上限,完全阻止后续语句的执行,比如最常见的数据仓库场景。当然这样的场景下,不管是否使用线程池,数据库的表现都是不够理想的,需要应用侧控制大查询的并发度
  • 有较严重的锁冲突,如果处于锁等待的工作线程数超过总线程数,也会堆积起来,阻止无锁待的处理请求。比如某个会话执行 FLUSH TABLES WITH READ LOCK语句获得全局锁后暂停,那么其他执行写操作的客户端连接就会阻塞,当阻塞的数量超过线程池的上限时,整个 server 都会阻塞。当然这样的场景下,不管是否使用线程池,数据库的表现都是不够理想的,需要应用侧进行优化
  • 极高并发的 Prepared Statement 请求。使用 Prepared Statement(Java 应用不算)时,会使用 MySQL Binary Protocol,会增加很多的网络来回操作,比如参数的绑定、结果集的返回,在极高请求压力下会给 epoll 监听进程带来一定的压力,处于事务状态中时,可能会让普通请求得不到执行机会。

为了应对这种阻塞问题,一般会允许配置 extra_portadmin_port 来管理连接。

总结一句话,线程池更适合短连接或短查询的场景。

行业方案:Percona 线程池实现

由于市面上的线程池方案大多都借鉴了 percona、mariadb 的方案,因此,首先介绍下 percona 线程池的工作机制,再说明其他方案相较于 percona 做了什么改进。

0. 基本原理

线程池的基本原理为:预先创建一定数量的工作线程(worker 线程)。在线程池监听线程(listener 线程)从现有连接中监听到新请求时,从工作线程中分配一个线程来提供服务。工作线程在服务结束之后不销毁线程(处于 idle 状态一段时间后会退出),而是保留在线程池中继续等待下一个请求来临。

下面我们将从线程池架构、新连接的创建与分配、listener 线程、worker 线程、timer 线程等几个方面来介绍 percona 线程池的实现。

1. 线程池的架构

线程池由多个线程组(thread group)timer 线程组成,如下图所示。

线程组的数量是线程池并发的上限,通常而言线程组的数量需要配置成数据库实例的 CPU 核心数量(可通过参数thread_pool_size设置),从而充分利用 CPU。线程组之间通过线程ID % 线程组数的方式分配连接,线程组内通过竞争方式处理连接。

线程池中还有一个服务于所有线程组的timer 线程,负责周期性(检查时间间隔为threadpool_stall_limit毫秒)检查线程组是否处于阻塞状态。当检测到阻塞的线程组时,timer 线程会通过唤醒或创建新的工作线程(wake_or_create_thread 函数)来让线程组恢复工作。

创建新的工作线程不是每次都能创建成功,要根据当前的线程组中的线程数是否大于线程组中的连接数,活跃线程数是否为 0,以及上一次创建线程的时间间隔是否超过阈值(这个阈值与线程组中的线程数有关,线程组中的线程数越多,时间间隔越大)。

线程组内部由多个 worker 线程、0 或 1 个动态 listener 线程、高低优先级事件队列(由网络事件 event 构成)、mutex、epollfd、统计信息等组成。如下图所示:

worker 线程:主要作用是从队列中读取并处理事件。

  • 如果该线程所在组中没有 listener 线程,则该 worker 线程将成为 listener 线程,通过 epoll 的方式监听数据,并将监听到的 event 放到线程组中的队列。
  • worker 线程数目动态变化,并发较大时会创建更多的 worker 线程,当从队列中取不到 event 时,work 线程将休眠,超过一定时间后结束线程。
  • 一个 worker 线程只属于一个线程组。

listener 线程:当高低队列为空,listen 线程会自己处理,无论这次获取到多少事务。否则 listen 线程会把请求加入到队列中,如果此时active_thread_count=0,唤醒一个工作线程

高低优先级队列:为了提高性能,将队列分为优先队列和普通队列。这里采用引入两个新变量thread_pool_high_prio_ticketsthread_pool_high_prio_mode。由它们控制高优先级队列策略。对每个新连接分配可以进入高优先级队列的 ticket。

2. 新连接的创建与分配

新连接接入时,线程池按照新连接的线程 id 取模线程组个数来确定新连接归属的线程组(thd->thread_id() % group_count)。这样的分配逻辑非常简洁,但由于没有充分考虑连接的负载情况,繁忙的连接可能会恰巧被分配到相同的线程组,从而导致负载不均衡的现象,这是 percona 线程池值得被优化的点

选定新连接归属的线程组后,新连接申请被作为事件放入低优先级队列中,等待线程组中 worker 线程将高优先级事件队列处理完后,就会处理低优先级队列中的请求。

3. listener 线程

listener 线程是负责监听连接请求的线程,每个线程组都有一个listener 线程

percona 线程池的 listener 采用epoll实现。当 epoll 监听到请求事件时,listener 会根据请求事件的类型来决定将其放入哪个优先级事件队列。将事件放入高优先级队列的条件如下(见函数connection_is_high_prio),只需要满足其一即可

  • 当前线程池的工作模式为高优先级模式,在此模式下只启用高优先级队列。(mode == TP_HIGH_PRIO_MODE_STATEMENTS
  • 当前线程池的工作模式为高优先级事务模式,在此模式下每个连接的 event最多被放入高优先级队列threadpool_high_prio_tickets次。超过threadpool_high_prio_tickets次后,该连接的请求事件只能被放入低优先级(mode == TP_HIGH_PRIO_MODE_TRANSACTIONS),同时,也会重置票数。
  • 连接持有表锁
  • 连接持有mdl 锁
  • 连接持有全局读锁
  • 连接持有backup 锁
inline bool connection_is_high_prio(const connection_t &c) noexcept {
  const ulong mode = c.thd->variables.threadpool_high_prio_mode;

  return (mode == TP_HIGH_PRIO_MODE_STATEMENTS) ||
         (mode == TP_HIGH_PRIO_MODE_TRANSACTIONS && c.tickets > 0 &&
          (thd_is_transaction_active(c.thd) ||
           c.thd->variables.option_bits & OPTION_TABLE_LOCK ||
           c.thd->locked_tables_mode != LTM_NONE ||
           c.thd->mdl_context.has_locks() ||
           c.thd->global_read_lock.is_acquired() ||
           c.thd->backup_tables_lock.is_acquired() ||
           c.thd->mdl_context.has_locks(MDL_key::USER_LEVEL_LOCK) ||
           c.thd->mdl_context.has_locks(MDL_key::LOCKING_SERVICE)));
}

被放入高优先级队列的事件可以优先被 worker 线程处理。

只有当高优先级队列为空,并且当前线程组不繁忙的时候才处理低优先级队列中的事件。线程组繁忙(too_many_busy_threads)的判断条件是当前组内活跃工作线程数+组内处于等待状态的线程数大于线程组工作线程额定值thread_pool_oversubscribe+1)。这样的设计可能带来的问题是在高优先级队列不为空或者线程组繁忙时低优先级队列中的事件迟迟得不到响应,这同样也是 percona 线程池值得被优化的一个点

listener 线程将事件放入高低优先级队列后,如果线程组的活跃 worker 数量为 0,则唤醒或创建新的 worker 线程来处理事件。

percona 的线程池中listener 线程和 worker 线程是可以互相切换的,详细的切换逻辑会在「worker 线程」一节介绍。

  • epoll 监听到请求事件时,如果高低优先级事件队列都为空,意味着此时线程组非常空闲,大概率不存在活跃的 worker 线程。
  • listener 在此情况下会将除第一个事件外的所有事件按前述规则放入高低优先级事件队列,然后退出监听任务,亲自处理第一个事件
  • 这样设计的好处在于当线程组非常空闲时,可以避免 listener 线程将事件放入队列,唤醒或创建 worker 线程来处理事件的开销,提高工作效率。

上图来源于腾讯数据库技术公众号

4. worker 线程

worker 线程是线程池中真正干活的线程,正常情况下,每个线程组都会有一个活跃的 worker 线程。

worker 在理想状态下,可以高效运转并且快速处理完高低优先级队列中的事件。但是在实际场景中,worker 经常会遭遇 IO、锁等等待情况而难以高效完成任务,此时任凭 worker 线程等待将使得在队列中的事件迟迟得不到处理,甚至可能出现长时间没有 listener 线程监听新请求的情况。为此,每当 worker 遭遇 IO、锁等等待情况,如果此时线程组中没有 listener 线程或者高低优先级事件队列非空,并且没有过多活跃 worker,则会尝试唤醒或者创建一个 worker。

为了避免短时间内创建大量 worker,带来系统吞吐波动,线程池创建 worker 线程时有一个控制单位时间创建 worker 线程上限的逻辑,线程组内连接数越多则创建下一个线程需要等待的时间越长。

线程组活跃 worker 线程数量大于等于too_many_active_threads+1时,认为线程组的活跃 worker 数量过多。此时需要对 worker 数量进行适当收敛,首先判断当前线程组是否有 listener 线程:

  • 如果没有 listener 线程,则将当前 worker 线程转化为 listener 线程。
  • 如果当前有 listener 线程,则在进入休眠前尝试通过epoll_wait获取一个尚未进入队列的事件,成功获取到后立刻处理该事件,否则进入休眠等待被唤醒,等待threadpool_idle_timeout时间后仍未被唤醒则销毁该 worker 线程。

worker 线程与 listener 线程的切换如下图所示:

上图来自于腾讯数据库技术公众号

5. timer 线程

timer 线程每隔threadpool_stall_limit时间进行一次所有线程组的扫描(check_stall)。

当线程组高低优先级队列中存在事件,并且自上次检查至今没有新的事件被 worker 消费,则认为线程组处于停滞状态。

  • 停滞的主要原因可能是长时间执行的非阻塞请求, 也可能发生于线程正在等待但 wait_begin/wait_end (尝试唤醒或创建新的 worker 线程)被上层函数忘记调用的场景。
  • timer 线程会通过唤醒或创建新的 worker 线程来让停滞的线程组恢复工作。

timer 线程为了尽量减少对正常工作的线程组的影响,在check_stall时采用的是try_lock的方式,如果加不上锁则认为线程组运转良好,不再去打扰。

timer 线程除上述工作外,还负责终止空闲时间超过wait_timeout秒的客户端。

下面是 Percona 的实现:

check_stall 函数:

check_stall
|-- if (!thread_group->listener && !thread_group->io_event_count) {
|--   wake_or_create_thread(thread_group); // 重点函数
|-- }
|-- thread_group->io_event_count = 0; // 表示自上次 check 之后,当前线程组新获取的 event 数
|-- if (!thread_group->queue_event_count && !queues_are_empty(*thread_group)) { // 重点函数
|--   thread_group->stalled = true;
|--   wake_or_create_thread(thread_group); // 重点函数
|-- }
|-- thread_group->queue_event_count = 0;

static bool queues_are_empty(const thread_group_t &tg) noexcept {
return (tg.high_prio_queue.is_empty() && // 重点函数
(tg.queue.is_empty() || too_many_busy_threads(tg))); // 重点函数
}
  • io_event_count:当 Listen 线程监听到事件时++
  • queue_event_count :当 work 线程从队列中获取事件时++

行业主流方案对比

MySQL 企业版 vs MariaDB

MySQL 企业版是在 5.5 版本引入的线程池,以插件的方式实现的。

相同点:

  • 都具备线程池功能,都支持 thread_pool_size 参数。
  • 都支持专有 listener 线程(thread_pool_dedicated_listeners 参数)。
  • 都支持高低优先级队列,且在避免低优先级队列事件饿死方面,二者采用了相同方案,即低优先级队列事件等待一段时间(thread_pool_prio_kickup_timer 参数)即可移入高优先级队列。
  • 都使用相同的机制来探测处于停滞(stall)状态的线程,都提供了 thread_pool_stall_limit 参数(MariaDB 单位是 ms,MySQL 企业版单位是 10ms)。

不同点: Windows 平台实现方式不同。

  • MariaDB 使用 Windows 自带的线程池,而 MySQL 企业版的实现用到了 WSAPoll() 函数(为了便于移植 Unix 程序而提供),因此,MySQL 企业版的实现将不能使用命名管道和共享内存。
  • MariaDB 为每个操作系统都使用最高效的 IO 多路复用机制。

    • Windows:原生线程池
    • Linuxepoll
    • Solaris (event ports)
    • FreeBSD and OSX (kevent)
  • 而 MySQL 企业版只在 Linux 上才使用优化过的 IO 多路复用机制 epoll,其他平台则用 poll

MariaDB vs Percona

Percona 的实现移植自 MariaDB,并在此基础上添加了一些功能。特别是 Percona 在 5.5-5.7 版本添加了优先级调度。而 MariaDB 10.2 也支持了优先级调度,和 Percona 的工作方式类似,只是细节有所不同。

  • MariaDB 10.2 版本的参数 thread_pool_priority=auto,high,low 对应于 Percona 的 thread_pool_high_prio_mode=transactions,statements,none
  • MariaDB 10.2 版本中只有处于事务中的连接才是高优先级,而 Percona 中符合高优先级的情况包括:1)处于事务中;2)持有表锁;3)持有 MDL 锁;4)持有全局读锁;5)持有 backup 锁
  • 关于避免低优先级队列语句饿死的问题:

    • Percona 有一个 thread_pool_high_prio_tickets 参数,用于指定每个连接在高优先级队列中的 tickets 数量,而 MariaDB 没有相应参数。
    • MariaDB 有一个 thread_pool_prio_kickup_timer 参数,可让低优先队列中的语句在等待指定时间后移入高优先级队列,而 Percona 没有相应参数。
  • MariaDB 有参数thread_pool_dedicated_listenerthread_pool_exact_stats,而 Percona 没有。

    • thread_pool_dedicated_listener :可用于指定专有 listener 线程,其只负责epoll_wait等待网络事件,不会变为 worker 线程。默认为 OFF,表示不固定 listener。
    • thread_pool_exact_stats :是否使用高精度时间戳。
  • MariaDB (比如 10.9 版本)在 information_schema 中新增了四张表(THREAD_POOL_GROUPSTHREAD_POOL_QUEUESTHREAD_POOL_STATSTHREAD_POOL_WAITS),便于监控线程池状态。

AliSQL vs Percona

AliSQL 线程池也一定程度借鉴了 Percona 的机制,但也有自己的特色:

  • AliSQL 线程池给予管理类的 SQL 语句更高的优先级,保证这些语句优先执行。这样在系统负载很高时,新建连接、管理、监控等操作也能够稳定执行
  • AliSQL 线程池给予复杂查询 SQL 语句相对较低的优先级,并且有最大并发数的限制。这样可以避免过多的复杂 SQL 语句将系统资源耗尽,导致整个数据库服务不可用
  • AliSQL 支持动态开关线程池
  • 从官网手册及内核月报公开资料,无法获知 AliSQL 是否支持线程组专职 listener 。

AliSQL 虽然也使用了队列,但没有直接采用 percona 或 mariadb 的高低优先级调度策略,结合官方手册和数据库内核月报 2019 年 2 月份的文章 《MySQL 多队列线程优化》,推测是使用了两层队列:

  • 第一层队列为网络请求队列,可以区分为请求队列(不在事务状态中的请求)和高优先级队列(已经在事务状态中的请求,收到请求后会马上执行,不进入第二队列)。
  • 第二层队列为工作任务队列,可以区分为查询队列、更新队列和事务队列

第一层请求队列的请求经过快速的处理和分析进入第二层队列。如果是管理操作,则直接执行(假定所有管理操作都是小操作)。

对第二层队列,可以分别设置一个允许的并发度(可以接近 CPU 的个数),以实现总线程数的控制。只要线程数大于四类操作的设计并发度之和,则不同类型的操作不会互相干涉(在这里是假定同一操作超过各自并发度而进行排队是合理的)。任何一个队列超过一定的时间,如果没有完成任何语句,处于阻塞模式,则可以考虑放行,在 MySQL 线程池中有thread_pool_stall_limit变量来控制这个间隔,以防止任何一个队列挂起。

可以从配置参数的变化来了解优化后的线程池工作机制:

  • thread_pool_enabled :线程池开关。
  • thread_pool_idle_timeout :线程最大空闲时间,超过则退出。
  • thread_pool_max_threads :线程池最大工作线程数。
  • thread_pool_oversubscribe:每个 Thread Group 的目标线程数。
  • thread_pool_normal_weights(相较 percona 新加):查询、更新操作的目标线程比例(假定这两类操作的比重相同),即并发度 = thread_pool_oversubscribe * 目标比例/100
  • thread_pool_trans_weights(相较 percona 新加):事务操作的目标线程比例,即并发度 = thread_pool_oversubscribe * 目标比例/100
  • thread_pool_stall_limit:阻塞模式检查频率(同时检查 5 个队列的状态)
  • thread_pool_size:线程组的个数(在优化锁并发后,线程组的个数不是很关键,可以用来根据物理机器的资源配置情况来软性调节处理能力)

另外,AliSQL 新增了 6 个状态变量:thread_pool_active_threadsthread_pool_big_threadsthread_pool_dml_threadsthread_pool_qry_threadsthread_pool_trx_threadsthread_pool_wait_threads 。还有 2 个状态变量与 percona 线程池含义相同,只是名字不同。

TXSQL vs Percona

腾讯云 TXSQL 线程池核心方案与 Percona 完全一样,额外支持的功能如下:

1. 支持线程池动态切换

线程池采用一定数量的工作线程来处理用户连接请求,通常比较适应于 OLTP 工作负载的场景。但线程池并不是万能的,线程池的不足在于当用户请求偏向于慢查询时,工作线程阻塞在高时延操作上,难以快速响应新的用户请求,导致系统吞吐量反而相较于 one-thread-per-connection(简称为 Per_thread)模式更低。

Per_thread 模式与 Thread_pool 模式各有优劣,系统需要根据用户的业务类型灵活切换两种模式。在业务高峰时段切换模式,重启服务器,会严重影响用户业务。为了解决此问题,TXSQL 提出了线程池动态切换的优化,即在不重启数据库服务的情况下,动态开启或关闭线程池。

通过参数 thread_handling_switch_mode 控制,可选值及含义如下:

可选值含义
disabled禁止模式动态迁移
stable只有新连接迁移
fast新连接 + 新请求都迁移,默认模式
sharpkill 当前活跃连接,迫使用户重连,达到快速切换的效果

在了解了 TXSQL 动态线程池的使用方法后,我们再来了解一下其具体的实现。

mysql 的thread_handling参数代表了连接管理方法。

在原生 mysql 中,thread_handling 是只读参数,不允许在线修改

thread_handling 参数对应的底层实现对象是Connection_handler_manager,后者是 mysql 提供连接管理服务的单例类,可对外提供多种连接管理服务:

  • Per_thread : 参数值是 one-thread-per-connection
  • No_threads : 参数值是 no-threads
  • Thread_pool : 新加
  • Plugin_connection_handler : 参数值是 loaded-dynamically

在 mysql 启动时Connection_handler_manager只需要按照thread_handling初始化一种连接管理方法即可。

为了支持动态线程池,允许用户连接从 Per_thread 和 Thread_pool 模式中来回切换,我们需要允许多种连接管理方法同时存在。因此,在 mysql 初始化阶段,TXSQL 初始化了所有连接管理方法

在支持thread_handlingPer_thread 和 Thread_pool 模式中来回切换后,我们需要考虑的问题主要有以下几个:

1.1. 活跃用户连接的 thread_handling 切换

Per_thread 模式下,每个用户连接对应一个handle_connection线程,handle_connection线程既负责用户网络请求的监听,又负责请求的处理。

Thread_pool 模式下,每个 thread_group 都用epoll来管理其中所有用户连接的网络事件,监听到的事件放入事件队列中,交予 worker 处理。

不论是哪种模式,在处理请求的过程中(do_command)切换都不是一个好选择,而在完成一次 command 之后,尚未接到下一次请求之前是一个较合适的切换点。

  • 为实现用户连接从 Per_thread 到 Thread_pool 的切换,需要在请求处理完(do_command)之后判断thread_handling是否发生了变化。
    如需切换则立刻按照 2.2 中介绍的逻辑,通过thread_id % group_size选定目标 thread_group,将当前用户连接迁移至 Thread_pool 的目标 thread_group 中,后续该用户连接的所有网络事件统一交予 thread_group 的 epoll 监听。在完成连接迁移之后,handle_connection 线程即可完成退出或者缓存至下一次 Per_thread 模式处理新连接时复用(此为原生 mysql 支持的逻辑,目的是避免 Per_thread 模式下频繁地创建和销毁 handle_connection 线程)。

    • handle_connection 函数被 Per_thread_connection_handler::add_connection 函数调用。
  • 为实现用户连接从 Thread_pool 到 Per_thread 的切换,需要在请求处理完(threadpool_process_request)后,将用户线程网络句柄重新挂载到 epollstart_io)之前判断 thread_handling 是否发生了变化。如需切换则先将网络句柄从 epoll 中移除以及将连接的信息从对应 thread_group 中清除。由于 Per_thread 模式下每个连接对应一个 handle_connection 线程,还需为当前用户连接创建一个 handle_connection 线程,后续当前用户连接的网络监听和请求处理都交予该 handle_connection 线程处理。
1.2. 新连接的处理

由于 thread_handling 可能随时动态变化,为了使得新连接能被新 thread_handling 处理,需要在新连接处理接口Connection_handler_manager::process_new_connection中,读取最新的 thread_handling,利用其相应的连接管理方法添加新连接

  • 对于 Per_thread 模式,需要为新连接创建handle_connection线程;
  • 对于 Thread_pool 模式,则需要为新连接选定 thread_group 和将其网络句柄绑定到 thread_group 的epoll中。
1.3. thread_handling 切换的快速生效

从前文的讨论中可以看到,处于连接状态的用户线程需要等到一个请求处理结束才会等到合适的切换点

如果该用户连接迟迟不发送网络请求,则连接会阻塞在 do_command 下的get_command的网络等待中,无法及时切换到 Thread_pool。如何快速完成此类线程的切换呢?

一种比较激进的方法就是迫使此类连接重连,在重连后作为新连接自然地切换到 Thread_pool 中,其下一个网络请求也将被 Thread_pool 应答。

线程池动态切换对性能的影响

  • pool-of-threads 切换为 one-thread-per-connection 过程本身不会带来 query 堆积,以及性能影响
  • one-thread-per-connection 切换为 pool-of-threads 过程,由于之前线程池处于休眠状态,在 QPS 极高并且有持续高压的情况下,可能存在一定的请求累积。解决方案如下:

    • 方案 1:适当增大 thread_pool_oversubscribe,并适当调小 thread_pool_stall_limit,快速激活线程池。待消化完堆积 SQL 再视情况还原上述修改。
    • 方案 2:出现 SQL 累积时,短暂暂停或降低业务流量几秒钟,等待 pool-of-threads 完成激活,再恢复持续高压业务流量。

2. 线程池负载均衡优化

如前文所述,新连接按照线程 id 取模线程组个数来确定新连接归属的线程组(thd->thread_id() % group_count)。这样的分配方式未能将各线程组的实际负载考虑在内,因此可能将繁忙的连接分配到相同的线程组,使得线程池出现负载不均衡的现象。为了避免负载不均衡的发生,TXSQL 提出了线程池负载均衡优化。

2.1. 负载的度量

在提出负载均衡的算法之前,我们首先需要找到一种度量线程组负载状态的方法,通常我们称之为"信息策略“。下面我们分别讨论几种可能的信息策略。

1) queue_length

queue_length代表线程组中低优先级队列和高优先级队列的长度。此信息策略的最大优势在于简单,直接用在工作队列中尚未处理的 event 的数量描述当前线程组的工作负载情况。此信息策略的不足是 无法将每个网络事件 event 的处理效率纳入考量。由于每个 event 的处理效率并不相同,简单地以工作队列长度作为度量标准会带来一些误判。

2) average_wait_usecs_in_queue

average_wait_usecs_in_queue表示最近 n 个 event 在队列中的平均等待时间。此信息策略的优势在于能够直观地反映线程组处理 event 的响应速度。某线程组average_wait_usecs_in_queue明显高于其他线程组说明其工作队列中的 event 无法及时被处理,需要其他线程组对其提供帮助。

3) group_efficiency

group_efficiency表示一定的时间周期内,线程组处理完的 event 总数占(工作队列存量 event 数+新增 event 数)的比例。此信息策略的优势在于能够直观反映出线程组一定时间周期内的工作效率,不足在于对于运转良好的线程组也可能存在误判:当时间周期选择不合适时,运转良好的线程组可能存在时而 group_efficiency 小于 1,时而大于 1 的情况。
上述三种信息策略只是举例说明,还有更多信息策略可以被采用,就不再一一罗列。

2 .2. 负载均衡的实现介绍

在明确了度量线程组负载的方法之后,我们接下来讨论如何均衡负载。我们需要考虑的问题主要如下:

1) 负载均衡算法的触发条件

负载均衡操作会将用户连接从一个线程组迁移至另一个线程组,在非必要情况下触发用户连接的迁移反而会导致用户连接的性能抖动。为尽可能避免负载均衡算法错误触发,我们需要为触发负载均衡算法设定一个负载阈值 M,以及负载比例 N。只有线程组的负载阈值大于 M,并且其与参与均衡负载的线程组的负载比例大于 N 时,才需要启动负载均衡算法平衡负载

2) 负载均衡的参数对象

Q:当线程组触发了负载均衡算法后,该由哪些线程组参与平衡高负载线程组的负载呢?

很容易想到的一个方案是我们维护全局的线程组负载动态序列,让负载最轻的线程组负责分担负载。但是遗憾的是为了维护全局线程组负载动态序列,线程组每处理完一次任务都可能需要更新自身的状态,并在全局锁的保护下更新其在全局负载序列中的位置,如此一来对性能的影响势必较大,因此全局线程组负载动态序列的方案并不理想

为了避免均衡负载对线程池整体性能的影响,需改全局负载比较为局部负载比较。一种可能的方法为当当前线程组的负载高于阈值 M 时,只比较其与左右相邻的 X 个(通常 1-2 个)线程组的负载差异,当当前线程组的负载与相邻线程组的比例也高于 N 倍时,从当前线程组向低负载线程组迁移用户连接。需要注意的是当当前线程组的负载与相邻线程组的比例不足 N 倍时,说明要么当前线程组还不够繁忙、要么其相邻线程组也较为忙碌,此时为了避免线程池整体表现恶化,不适合强行均衡负载。

3) 均衡负载的方法

讨论完负载均衡的触发条件及参与对象之后,接下来我们需要讨论高负载线程组向低负载线程组迁移负载的方法。总体而言,包括两种方法:新连接的优化分配、旧连接的合理转移

在掌握了线程组的量化负载之后,较容易实现的均衡负载方法是在新连接分配线程组时特意避开高负载线程组,这样一来已经处于高负载状态的线程组便不会因新连接的加入进一步恶化。但仅仅如此还不够,如果高负载线程组的响应已经很迟钝,我们还需要主动将其中的旧连接迁移至合适的低负载线程组,具体迁移时机在 3.1 中已有述及,为在请求处理完(threadpool_process_request)后,将用户线程网络句柄重新挂载到epoll(start_io)之前,此处便不再展开讨论。

3. 线程池断连优化

3.1. percona 线程池问题

如前文所述,线程池采用 epoll 来处理网络事件。当 epoll 监听到网络事件时,listener 会将网络事件放入事件队列或自己处理,此时相应用户连接不会被 epoll 监听。percona 线程池需要等到请求处理结束之后才会使用 epoll 重新监听用户连接的新网络事件。percona 线程池这样的设计通常不会带来问题,因为用户连接在请求未被处理时,也不会有发送新请求的需求。但特殊情况下,如果用户连接在重新被 epoll 监听前自行退出了,此时用户连接发出的断连信号无法被 epoll 捕捉,因此在 mysql 服务器端无法及时退出该用户连接。这样带来的影响主要有两点:

  1. 用户连接客户端虽已退出,但 mysql 服务器端却仍在运行该连接,继续消耗 CPU、内存资源,甚至可能继续持有锁,只有等到连接超时才能退出;
  2. 由于用户连接在 mysql 服务器端未及时退出,连接数也并未清理,如果用户业务连接数较多,可能导致用户新连接数触达最大连接数上限,用户无法连接数据库,严重影响业务。

为解决上述问题,TXSQL 提出了线程池断连优化。

3.2. 断连优化的实现介绍

断连优化的重点在于及时监听用户连接的断连事件并及时处理。为此需要作出的优化如下:

  1. 在 epoll 接到用户连接的正常网络事件后,立刻监听该用户连接的断连事件
  2. 所有用户连接退出从同步改为异步,所有退出的连接先放入quit_connection_queue,后统一处理;
  3. 一旦 epoll 接到断连事件后立刻将用户连接 thd->killed 设置为`THD::KILL_CONNECTION 状态,并将连接放入 quit_connection_queue 中异步退出
  4. listener 每隔固定时间(例如 100ms)处理一次 quit_connection_queue,让其中的用户连接退出

4. 新增用于监控的状态变量

  • 新增指令 show threadpool status ,可展示 25 个线程池状态变量。
  • show full processlist 中新增如下状态变量:

    • Moved_to_per_thread 表示该连接迁移到 Per_thread 的次数。
    • Moved_to_thread_pool 表示该连接迁移到 Thread_pool 的次数。

性能结果

由于腾讯 TXSQL、Percona 官方手册都没有性能数据,因此仅列出其他几种方案的性能结果。

MariaDB 5.5 - 无优先级队列

本小节内容来源于官网手册。

MariaDB 官网是基于 5.5 版本线程池测试的,也就是不支持高低优先级队列的版本。

采用 Sysbench 0.4,以pitbull (Linux, 24 cores) 的情况来说明在不同场景下的 QPS 情况。

OLTP_RO

并发数163264128256512102420484096
per_thread67547905815279487924758753133827208
threadpool656677258108807979767793742965234456

OLTP_RW

并发数163264128256512102420484096
per_thread456153165332351228742476138026553
threadpool45045382569455675302451425481186484

POINT_SELECT

并发数163264128256512102420484096
per_thread1486731615471697471720836903642041217754368282
threadpool143222167069167270165977164983158410148690147107143934

UPDATE_NOKEY

并发数163264128256512102420484096
per_thread652137168019418130081115587425645635332
threadpool649027023670037689266993069929670996237617766

AliSQL

如下是开启线程池和不开启线程池的性能对比。从测试结果可以看出线程池在高并发的情况下有着明显的性能优势。

update_non_index

write_only

read_write

point_select

总结

功能区别

MySQL 企业版MariaDBPercona腾讯 TXSQL阿里云 AliSQL
功能实现方式插件非插件非插件非插件推测是非插件
版本5.5 版本引入5.5 版本引入,10.2 版本完善5.5-5.7/8.05.7/8.05.6/5.7/8.0
是否开源
动态开关线程池插件式,不支持不支持不支持支持支持
优先级处理策略设定高低优先级,且低优先级事件等待一段时间可升为高优先级队列设定高低优先级,且低优先级事件等待一段时间可升为高优先级队列设定高低优先级,且限制每个连接在高优先级队列中的票数设定高低优先级,且限制每个连接在高优先级队列中的票数控制事务、非事务语句的比例
各线程组之间负载均衡优化不支持不支持不支持支持-
线程池断连优化-不支持不支持支持-
监控-2 个状态变量2 个状态变量27 个状态变量8 个状态变量
借鉴方案--MariaDBPerconaMariaDB 5.5
跨平台Windows/UnixWindows/Unix/MacOSWindows/Unix--

Q:如果线程池阻塞了,怎么处理?

MySQL 8.0.14 以前的版本使用 extra_port 功能(percona & mariadb),8.0.14 及之后版本官方支持了 admin_port 功能。

参数区别

由于业内线程池方案基本都会参考 MariaDB 或 Percona,因此,以 Percona 和 MariaDB 的参数为准,基于 MySQL 8.0,总结其他方案是否有相同或类似参数。

注意:MySQL 企业版核心方案与 MariaDB 类似,且关于差异点,官方描述较少,因此,不做对比。
MariaDBPercona腾讯 TXSQL阿里云 AliSQL
thread_handling 线程池开关有类似参数 thread_handling_switch_mode (支持动态开关)有类似参数 thread_pool_enabled(支持动态开关)
thread_pool_idle_timeout 线程最大空闲时间,超过则退出。
thread_pool_high_prio_mode 高优先级队列调度策略,支持 transactions,statements,none 三种策略有类似参数 thread_pool_priority,支持 high, low, auto 三种策略
thread_pool_high_prio_tickets 控制每个连接在高优先级中的票数,仅在调度模式是事务模式时生效
thread_pool_max_threads 线程池最大工作线程数
thread_pool_oversubscribe 每个线程组中的最大工作线程数
thread_pool_size 线程组数,一般推荐设为 CPU 核心数
thread_pool_stall_limit timer 线程判断线程组是否停滞(定期调用 check_stall )的时间间隔
thread_pool_prio_kickup_timer 低优先队列中的语句在等待该值指定的时间后,则移入高优先级队列
thread_pool_dedicated_listener 是否启用专用 listener 线程。若关闭,则 listener 有可能变为 worker。
thread_pool_exact_stats 是否使用高精度时间戳
thread_pool_normal_weights:查询、更新操作的目标线程比例(假定这两类操作的比重相同),即并发度= thread_pool_oversubscribe * 目标比例/100
thread_pool_trans_weights:事务操作的目标线程比例,即并发度= thread_pool_oversubscribe * 目标比例/100

可见

  1. 阿里云 AliSQL 线程池资料较少,虽然有些参数不具备,但并不说明未实现对应机制,比如专用 listener 线程。

监控区别

Percona、MariaDB:

只有两个状态变量:

  • Threadpool_threads
  • Threadpool_idle_threads

阿里云 AliSQL

新增了一些状态变量:

状态名状态说明
thread_pool_active_threads线程池中的活跃线程数
thread_pool_big_threads线程池中正在执行复杂查询的线程数。复杂查询包括有子查询、聚合函数、group by、limit 等的查询语句。
thread_pool_dml_threads线程池中的在执行 DML 的线程数
thread_pool_idle_threads线程池中的空闲线程数
thread_pool_qry_threads线程池中正在执行简单查询的线程数
thread_pool_total_threads线程池中的总线程数
thread_pool_trx_threads线程池中正在执行事务的线程数
thread_pool_wait_threads线程池中正在等待磁盘 IO、事务提交的线程数

腾讯云 TXSQL

新增 show threadpool status 指令,展示的相关状态如下:

状态名状态说明
groupid线程组 id
connection_count线程组用户连接数
thread_count线程组内工作线程数
havelistener线程组当前是否存在 listener
active_thread_count线程组内活跃 worker 数量
waiting_thread_count线程组内等待中的 worker 数量(调用 wait_begin 的 worker)
waiting_threads_size线程组中无网络事件需要处理,进入休眠期等待被唤醒的 worker 数量(等待 thread_pool_idle_timeout 秒后自动销毁)
queue_size线程组普通优先级队列长度
high_prio_queue_size线程组高优先级队列长度
get_high_prio_queue_num线程组内事件从高优先级队列被取走的总次数
get_normal_queue_num线程组内事件从普通优先级队列被取走的总次数
create_thread_num线程组内创建的 worker 线程总数
wake_thread_num线程组内从 waiting_threads 队列中唤醒的 worker 总数
oversubscribed_num线程组内 worker 发现当前线程组处于 oversubscribed 状态,并且准备进入休眠的次数
mysql_cond_timedwait_num线程组内 worker 进入 waiting_threads 队列的总次数
check_stall_nolistener线程组被 timer 线程 check_stall 检查中发现没有 listener 的总次数
check_stall_stall线程组被 timer 线程 check_stall 检查中被判定为 stall 状态的总次数
max_req_latency_us线程组中用户连接在队列等待的最长时间(单位毫秒)
conns_timeout_killed线程组中用户连接因客户端无新消息时间超过阈值(net_wait_timeout)被 killed 的总次数
connections_moved_in从其他线程组中迁入该线程组的连接总数
connections_moved_out从该线程组迁出到其他线程组的连接总数
connections_moved_from_per_thread从 one-thread-per-connection 模式中迁入该线程组的连接总数
connections_moved_to_per_thread从该线程组中迁出到 one-thread-per-connection 模式的连接总数
events_consumed线程组处理过的 events 总数
average_wait_usecs_in_queue线程组内所有 events 在队列中的平均等待时间

show full processlist 中新增如下状态:

  • Moved_to_per_thread 表示该连接迁移到 Per_thread 的次数。
  • Moved_to_thread_pool 表示该连接迁移到 Thread_pool 的次数.

参考链接

  1. 腾讯 TXSQL:

    1. 原创|线程池详解 (qq.com)")
    2. 云数据库 MySQL 动态线程池-自研内核 TXSQL-文档中心-腾讯云 (tencent.com)")
  2. Percona:

    1. Thread pool - Percona Server for MySQL
    2. SimCity outages, traffic control and Thread Pool for MySQL (percona.com)")
    3. 关于 MySQL 线程池,这也许是目前最全面的实用帖 - MySQL - dbaplus 社群
  3. MariaDB:

    1. Thread Pool in MariaDB - MariaDB Knowledge Base
  4. 阿里云 AliSQL:

    1. MySQL · 特性分析 · 线程池 (taobao.org)")
    2. MySQL · 最佳实践 · MySQL 多队列线程池优化 (taobao.org)")
  5. MySQL 企业版:

    1. MySQL :: MySQL 8.0 Reference Manual :: 5.6.3 MySQL Enterprise Thread Pool

欢迎关注我的微信公众号【数据库内核】:分享主流开源数据库和存储引擎相关技术。

标题网址
GitHubhttps://dbkernel.github.io
知乎https://www.zhihu.com/people/dbkernel/posts
思否(SegmentFault)https://segmentfault.com/u/dbkernel
掘金https://juejin.im/user/5e9d3ed251882538083fed1f/posts
CSDNhttps://blog.csdn.net/dbkernel
博客园(cnblogs)https://www.cnblogs.com/dbkernel

4.56-MariaDB 的密码重置 4.57 MariaDB 慢查询日志 4.58 Tomcat_JDK 部署 4.59 zrlog 安装 4.60 Nginx 代理 Tomcat

4.56-MariaDB 的密码重置 4.57 MariaDB 慢查询日志 4.58 Tomcat_JDK 部署 4.59 zrlog 安装 4.60 Nginx 代理 Tomcat

4.56-MariaDB 的密码重置

如果记得 root 的密码:

mysqladmin -uroot -paminglinux password "aming-linux"

如果不记得 root 密码:

1)编辑/etc/my.cnf
	增加:skip-grant
	重启服务
2)登录进MariaDB,执行
	use mysql  切换到mysql库
	desc user  查看user表的所有字段
	update user set authentication_string=password("aming-linux") where user=''root'';
3)退出MariaDB,删除/etc/my.cnf里面的skip-grant, 重启服务
4)用新密码登录即可

常识:

mysql在5.7.36版本之后把密码字段存到了authentication_string字段里,在之前版本存在password字段里。
update user set password=password("aming-linux") where user=''root'';

4.57 MariaDB 慢查询日志

为什么要配置慢查询日志?

目的是为了帮助我们分析MariaDB的瓶颈点。

如何配置?

1)进入MariaDB里面执行:
	show variables like ''slow%'';
	show variables like ''datadir'';
	show variables like ''long%'';

2)打开配置文件/etc/my.cnf,编辑,增加:
	slow_query_log = ON
	slow_query_log_file = /data/mysql/aminglinux01-slow.log
	long_query_time = 2

3)重启服务

4)模拟慢查询
	select sleep(5);

5)查看慢查询日志:
	cat /data/mysql/aminglinux01-slow.log

扩展:

show processlist;
show full processlist;

mysql -uroot -pxxxx -e "show processlist"

 

 

4.58 Tomcat_JDK 部署

 

JAVA 应用要运行起来,需要一个 JVM(JAVA 虚拟机)

JVM --> JDK

Oracle 官方 JDK 下载地址: https://www.oracle.com/technetwork/java/javase/downloads/index.html

CentOS7 上 yum 安装 openjdk

yum install -y java-1.8.0-openjdk

Tomcat 官方网站:

http://tomcat.apache.org/

Tomcat 版本:

7.0  8.5  9.0

下载地址:

https://tomcat.apache.org/download-90.cgi
wget https://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.14/bin/apache-tomcat-9.0.14.tar.gz

安装 Tomcat

tar zxf apache-tomcat-9.0.14.tar.gz
mv apache-tomcat-9.0.14 /usr/local/tomcat

启动

/usr/local/tomcat/bin/startup.sh

查看端口

netstat -lntp |grep java 
8080为WEB端口
8005 shutdown(管理端口)
8009 AJP端口(第三方的应用连接这个接口,和Tomcat结合起来)

查看进程

ps aux |grep java   ; ps aux |grep tomcat

  4.59 zrlog 安装

 

zrlog 是一款开源的 JAVA 应用,博客系统 官网: https://www.zrlog.com/

下载:

wget ''http://dl.zrlog.com/release/zrlog-2.1.0-3617b2e-release.war?attname=ROOT.war&ref=index''
mv zrlog-2.1.0-3617b2e-release.war\?attname\=ROOT.war\&ref\=index  zrlog-2.1.0.war

安装:

mv zrlog-2.1.0.war  /usr/local/tomcat/webapps/
cd !$
mv ROOT ROOT.bak
mv zrlog-2.1.0 ROOT

浏览器访问:

添加防火墙规则: firewall-cmd --add-port=8080/tcp --permanent
		firewall-cmd --reload

http://ip:8080/ 开始安装

数据库操作:

mysql -uroot -paming-linux -e "create database zrlog"
mysql -uroot -paming-linux -e "grant all on zrlog.* to ''zrlog''@''127.0.0.1'' identified by ''zrlog-pass''"

4.60 Nginx 代理 Tomcat

为什么要为 Tomcat 配置反向代理?

1)如果同一台机器又有Nginx又有Tomcat,则会产生端口冲突。

2)我们需要把8080端口变成80端口

3)Nginx对于静态的请求速度上要优于Tomcat,Tomcat不擅长做高并发的静态文件请求处理

如何配置?

server {

	server_name z.aminglinux.cc;
	
        location /
        {
            proxy_pass http://127.0.0.1:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

 

代码后续慢慢补齐

4.56 MariaDB密码重置

如果不记得mysql的root密码
[root@test01 ~]# vi /etc/my.cnf

[mysqld]
datadir=/data/mysql
socket=/tmp/mysql.sock
skip-grant


[root@test01 ~]# /etc/init.d/mysqld restart    重启
Restarting mysqld (via systemctl):                         [  确定  ]

[root@test01 ~]# mysql -uroot     此时就不需要再输入密码了
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.12-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type ''help;'' or ''\h'' for help. Type ''\c'' to clear the current input statement.

MariaDB [(none)]> 

MariaDB [(none)]> use mysql      切换到mysql库下面去
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mysql]> desc user;       看一下
+------------------------+-----------------------------------+------+-----+----------+-------+
| Field                  | Type                              | Null | Key | Default  | Extra |
+------------------------+-----------------------------------+------+-----+----------+-------+
| Host                   | char(60)                          | NO   | PRI |          |       |
| User                   | char(80)                          | NO   | PRI |          |       |
| Password               | char(41)                          | NO   |     |          |       |
| Select_priv            | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Insert_priv            | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Update_priv            | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Delete_priv            | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Create_priv            | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Drop_priv              | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Reload_priv            | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Shutdown_priv          | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Process_priv           | enum(''N'',''Y'')                     | NO   |     | N        |       |
| File_priv              | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Grant_priv             | enum(''N'',''Y'')                     | NO   |     | N        |       |
| References_priv        | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Index_priv             | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Alter_priv             | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Show_db_priv           | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Super_priv             | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Create_tmp_table_priv  | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Lock_tables_priv       | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Execute_priv           | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Repl_slave_priv        | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Repl_client_priv       | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Create_view_priv       | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Show_view_priv         | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Create_routine_priv    | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Alter_routine_priv     | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Create_user_priv       | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Event_priv             | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Trigger_priv           | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Create_tablespace_priv | enum(''N'',''Y'')                     | NO   |     | N        |       |
| Delete_history_priv    | enum(''N'',''Y'')                     | NO   |     | N        |       |
| ssl_type               | enum('''',''ANY'',''X509'',''SPECIFIED'') | NO   |     |          |       |
| ssl_cipher             | blob                              | NO   |     | NULL     |       |
| x509_issuer            | blob                              | NO   |     | NULL     |       |
| x509_subject           | blob                              | NO   |     | NULL     |       |
| max_questions          | int(11) unsigned                  | NO   |     | 0        |       |
| max_updates            | int(11) unsigned                  | NO   |     | 0        |       |
| max_connections        | int(11) unsigned                  | NO   |     | 0        |       |
| max_user_connections   | int(11)                           | NO   |     | 0        |       |
| plugin                 | char(64)                          | NO   |     |          |       |
| authentication_string  | text                              | NO   |     | NULL     |       |
| password_expired       | enum(''N'',''Y'')                     | NO   |     | N        |       |
| is_role                | enum(''N'',''Y'')                     | NO   |     | N        |       |
| default_role           | char(80)                          | NO   |     |          |       |
| max_statement_time     | decimal(12,6)                     | NO   |     | 0.000000 |       |
+------------------------+-----------------------------------+------+-----+----------+-------+
47 rows in set (0.022 sec)

新版本的MariaDB 密码文件是这个authentication_string
MariaDB [mysql]> update user set authentication_string=password("champin") where user=''root'';
Query OK, 4 rows affected (0.001 sec)
Rows matched: 4  Changed: 4  Warnings: 0


MariaDB [mysql]> Bye
[root@test01 ~]# vi /etc/my.cnf

删除
skip-grant

[root@test01 ~]# /etc/init.d/mysqld restart    重启

[root@test01 ~]# mysql -uroot -pchampin    重新登录
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.12-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type ''help;'' or ''\h'' for help. Type ''\c'' to clear the current input statement.

MariaDB [(none)]> 

MariaDB [(none)]> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mysql]> select user,host from user;    我们可以看一下有很多用户
+---------+-----------+
| user    | host      |
+---------+-----------+
| bbs     | 127.0.0.1 |
| blogtop | 127.0.0.1 |
| root    | 127.0.0.1 |
| root    | ::1       |
|         | localhost |
| root    | localhost |
|         | test01    |
| root    | test01    |
+---------+-----------+
8 rows in set (0.000 sec)



4.57 MariaDB慢查询日志


MariaDB [(none)]> show variables like ''slow%'';   查看它的slow相关的
+---------------------+-----------------+
| Variable_name       | Value           |
+---------------------+-----------------+
| slow_launch_time    | 2               |
| slow_query_log      | OFF             |
| slow_query_log_file | test01-slow.log |
+---------------------+-----------------+
3 rows in set (0.002 sec)

MariaDB [(none)]> show variables like ''datadir'';查看它的datadir
+---------------+--------------+
| Variable_name | Value        |
+---------------+--------------+
| datadir       | /data/mysql/ |
+---------------+--------------+
1 row in set (0.003 sec)

MariaDB [(none)]> show variables like ''long%'';  查看它的超时时间
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.004 sec)

MariaDB [(none)]> Bye

[root@test01 ~]# vi /etc/my.cnf
增加如下
slow_query_log = ON
slow_query_log_file = /data/mysql/test01-slow.log
long_query_time = 2

[root@test01 ~]# /etc/init.d/mysqld restart
Restarting mysqld (via systemctl):                         [  确定  ]


[root@test01 ~]# mysql -uroot -pchampin    进入MariaDB里面
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.12-MariaDB-log MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type ''help;'' or ''\h'' for help. Type ''\c'' to clear the current input statement.

MariaDB [(none)]> select sleep(5);   模拟慢查询
+----------+ 
| sleep(5) |
+----------+
|        0 |
+----------+
1 row in set (5.001 sec)

MariaDB [(none)]> Bye
[root@test01 ~]# cat /data/mysql/t
tc.log           test/            test01.pid       test01-slow.log  
[root@test01 ~]# cat /data/mysql/test01-slow.log       查看慢查询日志
/usr/local/mysql/bin/mysqld, Version: 10.3.12-MariaDB-log (MariaDB Server). started with:
Tcp port: 0  Unix socket: /tmp/mysql.sock
Time		    Id Command	Argument
# Time: 190311 23:12:52
# User@Host: root[root] @ localhost []
# Thread_id: 9  Schema:   QC_hit: No
# Query_time: 5.000687  Lock_time: 0.000000  Rows_sent: 1  Rows_examined: 0
# Rows_affected: 0  Bytes_sent: 63
SET timestamp=1552317172;
select sleep(5);

扩展

[root@test01 ~]# mysql -uroot -pchampin
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 10.3.12-MariaDB-log MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type ''help;'' or ''\h'' for help. Type ''\c'' to clear the current input statement.

MariaDB [(none)]> show processlist;    查看所有的队列(跟查看所有的进程一个道理)
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
| Id | User        | Host      | db   | Command | Time | State                    | Info             | Progress |
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
|  1 | system user |           | NULL | Daemon  | NULL | InnoDB purge worker      | NULL             |    0.000 |
|  2 | system user |           | NULL | Daemon  | NULL | InnoDB purge coordinator | NULL             |    0.000 |
|  3 | system user |           | NULL | Daemon  | NULL | InnoDB purge worker      | NULL             |    0.000 |
|  4 | system user |           | NULL | Daemon  | NULL | InnoDB purge worker      | NULL             |    0.000 |
|  5 | system user |           | NULL | Daemon  | NULL | InnoDB shutdown handler  | NULL             |    0.000 |
| 10 | root        | localhost | NULL | Query   |    0 | Init                     | show processlist |    0.000 |
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
6 rows in set (0.001 sec)

MariaDB [(none)]> show  rull processlist;   显示完整的语句
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''rull processlist'' at line 1
MariaDB [(none)]> show full processlist;
+----+-------------+-----------+------+---------+------+--------------------------+-----------------------+----------+
| Id | User        | Host      | db   | Command | Time | State                    | Info                  | Progress |
+----+-------------+-----------+------+---------+------+--------------------------+-----------------------+----------+
|  1 | system user |           | NULL | Daemon  | NULL | InnoDB purge worker      | NULL                  |    0.000 |
|  2 | system user |           | NULL | Daemon  | NULL | InnoDB purge coordinator | NULL                  |    0.000 |
|  3 | system user |           | NULL | Daemon  | NULL | InnoDB purge worker      | NULL                  |    0.000 |
|  4 | system user |           | NULL | Daemon  | NULL | InnoDB purge worker      | NULL                  |    0.000 |
|  5 | system user |           | NULL | Daemon  | NULL | InnoDB shutdown handler  | NULL                  |    0.000 |
| 10 | root        | localhost | NULL | Query   |    0 | Init                     | show full processlist |    0.000 |
+----+-------------+-----------+------+---------+------+--------------------------+-----------------------+----------+
6 rows in set (0.000 sec)



4.58 Tomcat_JDK部署


[root@test01 ~]# yum install -y java-1.8.0-openj

[root@test01 ~]# cd /usr/local/src/
[root@test01 src]# wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-9/v9.0.16/bin/apache-tomcat-9.0.16.tar.gz

[root@test01 src]# ls
apache-tomcat-9.0.16.tar.gz                 nginx-1.14.2
apache-tomcat-9.0.16.tar.gz.1               nginx-1.14.2.tar.gz
mariadb-10.3.12-linux-x86_64.tar.gz         php-7.3.1
mysql-5.7.23-linux-glibc2.12-x86_64.tar.gz  php-7.3.1.tar.bz2
[root@test01 src]# tar zxf apache-tomcat-9.0.16.tar.gz
[root@test01 src]# ls
apache-tomcat-9.0.16           mariadb-10.3.12-linux-x86_64.tar.gz         nginx-1.14.2.tar.gz
apache-tomcat-9.0.16.tar.gz    mysql-5.7.23-linux-glibc2.12-x86_64.tar.gz  php-7.3.1
apache-tomcat-9.0.16.tar.gz.1  nginx-1.14.2                                php-7.3.1.tar.bz2

[root@test01 src]# mv apache-tomcat-9.0.16 /usr/local/tomcat

[root@test01 src]# /usr/local/tomcat/bin/startup.sh 启动Tomcat
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.

[root@test01 src]# ps aux |grep java 查看进程
root       7340 10.9  7.8 2289972 78204 pts/3   Sl   23:39   0:03 /usr/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
root       7356  0.0  0.0 112728   976 pts/3    R+   23:39   0:00 grep --color=auto java


[root@test01 src]# netstat -ltnp |grep java  查看监听端口,有3个端口
8080为WEB端口
8005 shutdown(管理端口)
8009 AJP端口(第三方的应用连接这个接口,和Tomcat结合起来)

tcp6       0      0 :::8080                 :::*                    LISTEN      7340/java           
tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      7340/java           
tcp6       0      0 :::8009                 :::*                    LISTEN      7340/java           
         



4.59 安装zrlog

[root@test01 src]# cd 
[root@test01 ~]# wget http://dl.zrlog.com/release/zrlog-2.1.0-3617b2e-release.war?attname=ROOT.war&ref=index
[root@test01 ~]# ls
11.txt  2.txt  anaconda-ks.cfg  startingup.sh
1.txt   3.txt  DiscuzX          zrlog-2.1.0-3617b2e-release.war?attname=ROOT.war


[root@test01 ~]# du -sh zrlog-2.1.0-3617b2e-release.war\?attname\=ROOT.war 也属于一种压缩包
不用管怎么解压,至于要放到某个目录下就可以,会自动解压
9.9M	zrlog-2.1.0-3617b2e-release.war?attname=ROOT.war

[root@test01 ~]# mv zrlog-2.1.0.war /usr/local/tomcat/webapps/
[root@test01 ~]# cd !$
cd /usr/local/tomcat/webapps/
[root@test01 webapps]# ls
docs  examples  host-manager  manager  ROOT  zrlog-2.1.0  zrlog-2.1.0.war
[root@test01 webapps]# mv zrlog-2.1.0 zrlog 改个名字,不需要带版本号了。因为等访问的时候要带目录
[root@test01 webapps]# ls
docs  examples  host-manager  manager  ROOT  zrlog  zrlog-2.1.0.war


用浏览器访问tomcat默认界面 192.168.28.107:8080   如果不能访问,检查是不是防火墙阻拦了8080

[root@test01 webapps]# iptables -nvL |grep 8080   检查有没有8080端口,结果没有


[root@test01 webapps]# firewall-cmd --add-port=8080/tcp --permanent  添加防火墙规则,8080端口
success
[root@test01 webapps]# firewall-cmd --reload   还要重载一下
success

然后再用浏览器访问tomcat默认界面 192.168.28.107:8080 
要想访问zrlog,这样192.168.28.107:8080/zrlog
也就是说zrlog在/usr/local/tomcat/webapps这个目录   访问8080实际访问的是/usr/local/tomcat/webapps这个目录

下面这两步不太建议做。访问不了tomcat默认主页
[root@test01 webapps]# mv ROOT ROOT.bak
[root@test01 webapps]# mv zrlog ROOT


[root@test01 webapps]# mysql -uroot -pchampin -e "create database zrlog" 创建库
[root@test01 webapps]# mysql -uroot -pchampin -e "grant all on zrlog.* to ''zrlog''@''127.0.0.1''identified by ''champin''"   创建用户及密码
浏览器访问192.168.28.107:8080/zrlog
填入数据库,安装完成


 4.60 Nginx代理Tomcat


[root@test01 webapps]# cd /etc/nginx/conf.d/
[root@test01 conf.d]# ls
2.conf  bbs.champin.top.conf  default.conf  www.champin.top.conf
[root@test01 conf.d]# vi z.champinlinux.cc.conf

server {
        server_name z.chamlinux.cc;

        
        location /
        {
            proxy_pass http://127.0.0.1:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

[root@test01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@test01 conf.d]# nginx -s reload

还是因为是本机测试,要再windows绑定一个hosts  去ping一下 z.chamlinux.cc
然后在用浏览器访问z.chamlinux.cc去访问,可以去里面做一些细节的设置

 

AliSQL (MySQL 分支) 二次开发编译安装 (Centos)

AliSQL (MySQL 分支) 二次开发编译安装 (Centos)

答开源创业 15 问:选协议、维权、公关、找钱・・・・・・

源代码开发环境:

 

MySQL 架构文档

https://dev.mysql.com/doc/refman/5.6/en/

 

 

 

 

 

AliSQL 20170716版本发布 Invisible Indexes 功能和 SELECT FROM UPDATE 语法

AliSQL 20170716版本发布 Invisible Indexes 功能和 SELECT FROM UPDATE 语法

摘要: 在传统的关系数据库中,想要在堆表或者索引组织表中快速的检索到目标数据,添加索引是一个常用的手段,但过多的索引不但增加空间的开销, 还会带来写入性能的衰减,如何降低在线删除索引的风险,Invisible Indexes 提供了一个风险可控的方法。

Abstract

在传统的关系数据库中,想要在堆表或者索引组织表中快速的检索到目标数据,添加索引是一个常用的手段,但过多的索引不但增加空间的开销,

还会带来写入性能的衰减,如何降低在线删除索引的风险,Invisible Indexes 提供了一个风险可控的方法。

在面临一个常见的业务场景,比如更新某行记录,然后查询变更后的记录内容的时候,通常都是UPDATE + SELECT 两条语句来完成,

AliSQL 扩展了语法,提供SELECT...FROM UPDATE语句,在完成update变更的同时,返回整行记录内容,减少一次网络调用。

AliSQL REPO:https://github.com/alibaba/AliSQL

AliSQL Release Notes:https://github.com/alibaba/AliSQL/wiki/Changes-in-AliSQL-5.6.32-(2017-07-16)

1. Invisible Indexes

概要

AliSQL 为 index 增加了两个新的属性,visible/invisible,保存在FRM文件中,这两个属性决定了这个索引是否能够被优化器使用,索引默认是visible,当变更为invisible的时候,无论是否使用了force index hint,这个索引不再会被优化器使用。

在引擎层面,这个索引属性是透明的,即引擎会继续维护索引记录变更。

注意区分disabled index属性。

语法和使用方法

新增的语法例如:



场景使用

在DBA的日常运维中,为了加速SQL查询响应,随着业务的发展在表中积累了比较多的索引,而随着业务的变更,有部分索引可能已经不再需要,需要做删除处理。

在线删除索引,变成了一个风险极高的操作,如何降低删除索引的风险,主要评估两点:

需要统计信息展示索引的使用情况

当删除索引后,出现异常,如何快速的回滚

针对这两个点,AliSQL提供了较完善的方法进行评估:

1. 统计信息

AliSQL提供了一个内存统计表index_statistics,来统计每张表的索引使用统计信息,如下:

这表明 t 表中的 b_visible 索引被拿来检索了3条记录, 而t表中的其他index没有被使用过,基于这样的统计信息,DBA可以评估一段时间,某些索引没有被使用过,就可以相对安全的进行删除。


2. 回滚

当对index进行删除的时候, 可以分两步操作:

先invisible这个索引:

完成后,这个索引就不会再被optimizer使用,观察一段使用,确认没有影响后,再进行安全删除:


在真正的删除之前,如果出现异常,可以快速的回滚:


所以,通过index statistic 和 index invisible 功能,可以安全对索引进行在线删除。


2. SELECT FROM UPDATE

概要

为了优化在业务中使用 UPDATE + SELECT 两次调用的开销,AliSQL提供了 SELECT...FROM UPDATE 语法,在一次SQL请求中,完成UPDATE变更和行记录返回。

语法和使用

通过 SELECT...FROM UPDATE 语法,减少一次网络调用,在核心业务集群上,收益是非常可观的。


3. InnoDB Crash

概要

InnoDB在进行表结构变更的时候,如果是online操作,并且变更过程中失败,那么对于数据字典的dirty清理会延迟清理,但master thread在淘汰长时间未使用的Dictionary Object 的时候,因为对象未清理干净,导致实例crash。

详细的bug复现过程和修复方法,可以参考:http://mysql.taobao.org/monthly/2017/06/05/

MySQL官方的BUG跟踪:https://bugs.mysql.com/bug.php?id=86607

MariaDB的BUG跟踪:https://jira.mariadb.org/browse/MDEV-13051

4. Semisync优化

概要

Semisync的 ACK receiver 线程使用了 select() 系统库调用来监听slave线程,但由于 select() 方法存在多种限制,所以,使用 poll() 替换原来的监听方法。

其他

除了AliSQL外,你还可以看看云数据库 MySQL 版

更多技术干货敬请关注阿里云云栖社区:阿里云云栖社区

AliSQL 20171010版本发布 Sequence兼容PostgreSQL/Oracle语法和升级TLSv1.2

AliSQL 20171010版本发布 Sequence兼容PostgreSQL/Oracle语法和升级TLSv1.2

点击有惊喜

Abstract

为了增加Sequence使用的灵活性,以及方便从不同数据库进行迁移,Alisql增加了Sequence的兼容性,兼容了Postgresql和Oracle的Sequence语法。

为了保障数据传输安全,Alisql使用OpenSSL来代替社区版的yaSSL,并把默认的,已经被PCI DSS v3.1标准废弃的TLSv1.0升级到TLSv1.2版本。

并修复了一个Semisync的未合理处理信号的bug,
感谢boonie81提交的bugissue#68

Alisql REPO:https://github.com/alibaba/AliSQL
Alisql Release Notes:https://github.com/alibaba/AliSQL/wiki/Changes-in-AliSQL-5.6.32-(2017-10-10)

1. Sequence兼容Postgresql和Oracle使用语法

概要

为了增加sequence使用的用户体验,以及满足用户的使用习惯,Sequence新增了使用语法支持:

Sequence创建语法保持不变:

CREATE SEQUENCE [IF NOT EXISTS] schema.seqName
   [START WITH <constant>]
   [MINVALUE <constant>]
   [MAXVALUE <constant>]
   [INCREMENT BY <constant>]
   [CACHE <constant> | NOCACHE]
   [CYCLE | NOCYCLE]
  ;

SHOW Syntax:
  SHOW CREATE SEQUENCE schema.seqName;
  SHOW CREATE TABLE schema.seqName;

除了原有支持的查询方法:

SELECT [nextval | currval | *] FOR schema.seqName;
 SELECT [nextval | currval | *] FROM schema.seqName;

新增了函数和dual表方法:

SELECT nextval(seqName);  
 SELECT currval(seqName);

 SELECT seqName.nextval from dual;
 SELECT seqName.currval from dual;

2. 升级TLSv1.2

概要

原有的官方社区版 MysqL 只支持到 TLSv1.0 版本,但 TLSv1.0 已经证明是非安全的,存在漏洞,并已经被 PCI DSS v3.1 标准废弃了,考虑到社区的yaSSL只能最高支持TLSv1.1版本, 并且方便部署,减少依赖,Alisql直接静态编译了OpenSSL,提供TLSv1.2版本。 新增了编译方式和参数:

新增支持cmake编译参数:
-DWITH_SSL=openssl 即静态编译openSSL。

新增参数tls_version:
如果使用yaSSL编译:tls_version的默认值是:TLSv1,TLSv1.1
如果使用OpenSSL编译:tls_version的默认值是:TLSv1,TLSv1.1,TLSv1.2

例如:使用OpenSSL编译的Alisql:

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MysqL> show global variables like '%tls_%'; +---------------+-----------------------+
| Variable_name | Value | +---------------+-----------------------+
| have_tlsv1_2  | YES                   |
| tls_version | TLSv1,TLSv1.2 | +---------------+-----------------------+
2 rows in set (0.00 sec)

配置证书进行连接来查看当前连接的tls版本:

MysqL> show global variables like '%ssl%'; +---------------+--------------------------------------------+
| Variable_name | Value | +---------------+--------------------------------------------+
| have_openssl | YES | | have_ssl      | YES                                        |
| ssl_ca | /u01/ca.pem | | ssl_capath    |                                            |
| ssl_cert | /u01/server-cert.pem | | ssl_cipher    |                                            |
| ssl_crl | | | ssl_crlpath   |                                            |
| ssl_key | /u01/server-key.pem | +---------------+--------------------------------------------+

使用ca证书进行连接:
MysqL -h127.0.0.1 -ussl_user --ssl-ca=/u01/ca.pem --ssl-cert=/u01/client-cert.pem --ssl-key=/u01/client-key.pem

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MysqL> \s --------------
MysqL  Ver 14.14 distrib 5.6.32,for Linux (x86_64) using EditLine wrapper Connection id:          4
Current database:
Current user:           ssl_user@127.0.0.1 SSL: Cipher in use is DHE-RSA-AES128-GCM-SHA256 Current pager: stdout Using outfile: '' Using delimiter: ; Server version: 5.6.32 Source distribution Protocol version: 10 Connection: 127.0.0.1 via TCP/IP Server characterset: latin1 Db characterset: latin1 Client characterset: utf8 Conn. characterset: utf8 TCP port: 3306 Uptime: 1 hour 35 min 31 sec Threads: 1 Questions: 16 Slow queries: 0 Opens: 70 Flush tables: 1 Open tables: 63 Queries per second avg: 0.002 --------------


MysqL> show status like 'ssl_version'; +---------------+---------+
| Variable_name | Value | +---------------+---------+
| Ssl_version | TLSv1.2 | +---------------+---------+
1 row in set (0.00 sec)

为了使用TLSv1.2版本,也必须升级客户端使用openSSL编译,其兼容性如下:

Compatibility

The TLS Protocol version matrix: -----------------------------------------------------------------------
 Pre_Server Post_yaSSL_Server Post_openSSL_Server
Pre_Client TLSv1.0 TLSv1.0 TLSv1.0 Post_yaSSL_Client TLSv1.0 TLSv1.1 TLSv1.1 Post_openSSL_Client TLSv1.0 TLSv1.1 TLSv1.2 ----------------------------------------------------------------------- 

3.Semisync的bug修复

概要

在系统启动过程中,Semisync模块的ACK Receiver线程在系统屏蔽信号之前boot,导致当有信号的时候,
ACK Receiver 线程接收到了信号,而不是专有信号处理线程,导致不能正常的Shut down。

再次感谢Github社区的boonie81同学提交的bug report。

点击有惊喜

关于万字长文 | 业内 MySQL 线程池主流方案详解 - MariaDB/Percona/AliSQL/TXSQL/MySQL企业的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于4.56-MariaDB 的密码重置 4.57 MariaDB 慢查询日志 4.58 Tomcat_JDK 部署 4.59 zrlog 安装 4.60 Nginx 代理 Tomcat、AliSQL (MySQL 分支) 二次开发编译安装 (Centos)、AliSQL 20170716版本发布 Invisible Indexes 功能和 SELECT FROM UPDATE 语法、AliSQL 20171010版本发布 Sequence兼容PostgreSQL/Oracle语法和升级TLSv1.2的相关信息,请在本站寻找。

本文标签: