海山数据库(He3DB)线程池方案详解

news2024/10/6 19:27:29

前言

对于应用开发人员来说肯定听说过连接池,却不一定听说过线程池,虽然二者都是池化的概念,但还是有所不同的:

连接池面向的是数据库连接,是针对数据库Client侧的优化。连接池可将数据库连接数固定在一定范围内,避免业务端创建过多连接、达到server端最大连接数导致后续连接失败的问题;同时,由于保留了一定数量的连接,当业务端新请求到达时可直接复用、无需新建连接,节省业务侧建连时间。

线程池面向的是数据库内的工作线程,是针对数据库Server侧的优化。线程池将工作线程数量固定在一定范围内(当连接数过多时会涉及排队),可避免并发过高时频繁上下文切换、缓存失效等问题,有效提升CPU利用率及数据库吞吐。

背景                                                                       

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

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

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

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

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

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

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

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

   当连接多、并发低时,通过连接复用,避免创建大量空闲线程,减少系统资源开销。

   当连接多、并发高时,通过限制同时运行的线程数,将其控制在合理的范围内,可避免线程调度工作过多和大

量缓存失效,减少线程池间上下文切换和热锁争用,从而对OLTP场景产生积极影响。

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

适用场景                                                               

线程池采用一定数量的工作线程来处理连接请求,在查询相对较短且工作负载受CPU限制的情况下效率最高,通常 适应于 OLTP 工作负载的场景:

   对于大量连接的OLTP短查询场景有较大收益;

   对于大量连接的只读短查询也有明显收益;

   可有效避免大量连接高并发下数据库性能衰减。

如果工作负载不受CPU限制,那么仍然可以通过限制线程数量来节省数据库内存缓冲区所占用的内存。

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

   具有突发工作负载的场景。在这种场景下,许多用户往往长时间处于非活跃状态,但个别时候又处于特别活跃 的状态,同时,对延迟的容忍度较低,因此,线程池节流效果不太理想。不过,即使在这种情况下,也可以通 过调整线程的退役频率(  thread_pool_idle_timeout 参数)来提高性能。

   高并发、长耗时语句的场景。在这种场景下,并发较多,且都是执行时间较长的语句,会导致工作线程堆积,  一旦达到上限,完全阻止后续语句的执行,比如最常见的数据仓库场景。当然这样的场景下,不管是否使用线 程池,数据库的表现都是不够理想的,  需要应用侧控制慢查询的并发度

   有较严重的锁冲突的场景。如果处于锁等待的工作线程数超过总线程数,也会堆积起来,阻止无锁等待的处理 请求。比如某个会话执行 FLUSH TABLES WITH READ LOCK 语句获得全局锁后暂停 那么其他执行写操作的  客户端连接就会阻塞,当阻塞的数量超过线程池的上限时,整个 server 都会阻塞。当然这样的场景下,不管   是否使用线程池,数据库的表现都是不够理想的,  需要应用侧进行优化

  极高并发的Prepared Statement请求。使用Prepared Statement时,会使用MySQL Binary Protocol,会 增加很多的网络开销,比如参数的绑定、结果集的返回,在极高请求压力下会给epoll监听进程带来一定的压 力,处于事务状态中时,可能会让普通请求得不到执行机会。

为了应对上述的阻塞问题,一般会允许配置

来管理连接。

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

行业方案

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

腾讯云TXSQL整合了percona的线程池方案,在此基础上实现了线程池的动态切换(动态开启或关闭线程

池)、负载均衡优化(percona分配线程组时采用的轮询算法,TXSQL做了改进

阿里云AliSQL一定程度上也借鉴了percona的线程池方案,主要不同在于其采用了两层队列,第一层为网  络请求队列(区分为普通队列、高优先级队列),第二层为工作任务队列(区分为查询队列、更新队列、事 务队列)。

Percona

Percona 的实现移植自MariaDB,并在此基础上支持优先级队列,是现在主流的开源线程池方案。其基本原理为:

预先创建一定数量的工作线程(worker线程)。在线程池监听线程(listener线程)从现有连接中监听到新请求时,判断当前请求是否属于高优先级队列,若属于,则放入高优先级队列,反之,则放入低优先级队列;之后,由工作线程按照先高优后低优的顺序来处理请求。工作线程在服务结束之后不销毁线程(处于 idle 状态一段时间后会退出),而是保留在线程池中继续等待下一个请求来临。

MariaDB vs Percona                                                                  

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

   MariaDB 10.2 版本的参数  thread_pool_priority=auto,high,low 对应于 Percona 

   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_listener   thread_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_GROUPS  THREAD_POOL_QUEUES  THREAD_POOL_STATS  THREAD_POOL_WAITS ),便 于监控线程池状态。

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:原生线程池

○    Linux epoll

   Solaris ( event ports )

   FreeBSD and OSX   kevent )

    MySQL 企业版只在 Linux 上才使用优化过的 IO 多路复用机  epoll ,其他平台则用  poll  

移动云方案

概述                                                                                           

核心功能与 percona 线程池方案类似,优先级调度算法 及 避免低优先级队列语句饿死的策略也有所参考除此之外,额外做了一些改进:

   使用插件方式实现。

·  借鉴了 MariaDB 的实现,添加了参数  thread_pool_dedicated_listener ,即支持固定 listener 功能。

   借鉴了 MariaDB 的实现,在  information_schema 中新增了四张表

 THREAD_POOL_GROUPS  THREAD_POOL_QUEUES  THREAD_POOL_STATS  THREAD_POOL_WAITS ),便 于监控线程池状态。

   一些优化点:

   添加参数 thread_pool_toobusy ,表示线程组是否过于忙碌的线程数阈值。当线程组中活跃的工作线 程数+锁或IO等待中的工作线程数>该阈值加1时,认为线程组过于忙碌,不再处理低优先级的任务,等  待当前执行的任务和高优先级队列中的任务被处理,直到线程组回到非忙碌的状态。  该优化能避免

percona的问题——极端高并发场景下,随着工作线程的持续创建,退化为每线程模式

  高优先级 session 独占 worker 线程:在连接数很大,高负载时,对于一些事务取得了锁等资源时,可 优先处理

.  percona/mariadb的处理逻辑是此类连接发生可读事件后,会被线程组加到优先队列中,等待空闲 worker线程优先处理。

.  移动云优化后的逻辑,   需要优先处理的session不将当前worker还给线程池,继续独占当前

worker线程,类似每线程每连接的模式,独占worker线程专用于处理该优先连接之后的所有语 句,直到该连接释放了优先资源转为普通连接,例如该连接事务执行结束释放锁资源。

   listener 线程调用 io_poll_wait 后,只要线程组不繁忙,则按需批量唤醒或创建一批 worker 线程(根据 本次获得的 event 数量、活跃线程数来决定worker数量)。     

设计方案                                                                                                                               

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

1. 线程池的架构

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

线程组的数量是线程池并发的上限,通常而言线程组的数量需要配置成数据库实例的CPU核心数量 (通过参

 thread_pool_size 设置),从而充分利用CPU。线程组之间通过 线程ID % 线程组数 的方式分配连接,线程组 内通过竞争方式处理连接。

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

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

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

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

·  如果该线程所在组中没有listener线程,则该worker线程将成为listener线程,通过epoll的方式监听数据,并 将监听到的event放到线程组中的队列。

   worker线程数目动态变化,并发较大时会创建更多的worker线程,当从队列中取不到event时, work线程将 休眠,超过一定时间后结束线程。

   一个worker线程只属于一个线程组。

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

高低优先级队列:为了提高性能,将队列分为高优先队列和普通队列。这里采用引入两个新变量

thread_pool_high_prio_tickets  thread_pool_high_prio_mode 。由它们控制高优先级队列策略。对每 个新连接分配可以进入高优先级队列的ticket

2. 新连接的创建与分配

新连接接入时,线程池按照新连接的线程id取模线程组个数来确定新连接归属的线程组(

 group_count

)。

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

3. listener线程

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

线程池的listener采用epoll实现。当epoll监听到请求事件时,  listener会根据请求事件的类来决定将其 放入哪个优先级事件队列。  将事件放入高优先级队列的条件如下

   当前线程池的工作模式为高优先级模式,在此模式下只启用高优先级队列

   当前线程池的工作模式为事务模式,在此模式下每个连接的event最多被放入高优先级队

 threadpool_high_prio_tickets 次。超过 threadpool_high_prio_tickets 次后,该连接的请求事件 只能被放入低优先级同时,也会重置票数。  以下条件只需要满足其一即可

   连接持有表锁

   连接持有mdl

   连接持有全局读锁

   连接持有backup

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

只有当高优先级队列为空且当前线程组不繁忙的时候才处理低优先级队列中的事件。线程组繁忙的判断条件是当前组内活跃工作线程数+组内处于等待状态的线程数大于线程组工作线程额定值 thread_pool_oversubscribe+1 )。

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

线程池中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线程总数接近最大连接数(max_connections)的情况,相当于退化为每线程模式

线程组活跃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 时间进行一次所有线程组的扫描。

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

   停滞的主要原因可能是长时间执行的非阻塞请求

   timer线程会通过唤醒或创建新的worker线程来让停滞的线程组恢复工作。

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

性能结果

移动云优化后的线程池会将工作线程数控制在一定范围内,随着并发数的增加,性能基本与最高点持平,无明显下降趋势。

总结

最后,总结下本文中几种方案在使用方面的区别。

功能

MySQL 企业版

MariaDB

Percona

移动云

功  能  实      

插件

非插件

非插件

插件

  

5.5 版本引入

5.5 版本引入,   10.2  本完善

5.5-5.7/8.0

5.7/8.0

借  鉴    

-

-

MariaDB

Percona +

MariaDB 10.2 及之 后版本

线

插件式,不支持

不支持

不支持

插件式,不支持

优  先          

设定高低优先级,且低 优先级事件等待一段时 间可升为高优先级队列

设定高低优先级,且低 优先级事件等待一段时 间可升为高优先级队列

设定高低优先级,  且限制每个连接在 高优先级队列中的 票数

设定高低优先级,  且限制每个连接在 高优先级队列中的 票数

  

-

2个状态变量

2个状态变量

4张状态信息表

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

MySQL 8.0.14 以前的版本使用 admin_port 功能。

功能(percona & mariadb), 8.0.14及之后版本官方支持了

参数                                                                                           

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

注意: MySQL 企业版核心方案与 MariaDB 类似,且关于差异点,官方描述较少,因此,不做对比。

监控

Percona只有两个状态变量:

移动云借鉴了MariaDB的实现方式,在 information_schema 中增加了四张状态信息表

  THREAD_POOL_GROUPS 查询线程组相关信息。

  THREAD POOL_QUEUES 查询线程组队列中连接的信息。

  THREAD_POOL_STATS 查询线程组状态信息的统计值,比如线程组由于check_stall创建的线程数、由listener 线程poll到的任务数等。

  THREAD_POOL_WAITS 提供线程组的worker线程在执行SQL语句时,各类等待原因的统计数据。   等待原因   有: UNKNOWN SLEEP DISKIO ROW_LOCK GLOBAL_LOCK META_DATA_LOCK TABLE_LOCK USER_LOCK BINLOG GROUP_COMMIT SYNC NET

参考链接                                                               

1.  Percona

1.  Thread pool - Percona Server for MySQL

2.  SimCity outages, traffic control and Thread Pool for MySQL (percona.com)

3. 线程池详解

2.  MariaDB

1.  Thread Pool in MariaDB - MariaDB Knowledge Base

3.  MySQL 企业版:

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

作者                                                                                          

卢文双,中国移动云能力中心数据库产品部 - MySQL内核研发工程师

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

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

相关文章

Unity3D读取Excel表格写入Excel表格

系列文章目录 unity工具 文章目录 系列文章目录👉前言👉一、读取Excel表格👉二、写入Excel表格👉三、Fileinfo和Directoryinfo的操作👉四、壁纸分享👉总结 👉前言 有时候难免会遇到读取文件写…

基于STM32看Cotex-M内核中断向量表重定向

文章目录 ARM处理器的启动流程嵌套中断向量控制器NVIC向量表和向量表重定位IAP过程中的重定向没有VTOR寄存器的情况 中断向量表重定向在芯片IAP(或OTA)升级过程中,是不可避免的问题。 在Cotex-M3/M4内核中有向量表偏移寄存器VTOR 在Cortex-M0内核中没有向量表偏移寄…

什么是住宅IP代理?为什么需要家庭 IP 代理

家庭代理 IP 允许您选择特定位置(国家、城市或移动运营商)并作为代理上网该区域的真实用户。住宅代理 IP 可以定义为保护用户免受一般网络流量影响的中介。它们在隐藏您的 IP 地址的同时充当缓冲区。住宅代理 IP 是服务提供商分配给用户的替代 IP 地址。…

Windows部署Jar包到系统服务(Service)

使用WinSW工具 1、工具下载地址:https://github.com/winsw/winsw/releases 选择最新版本下载 根据机器32位或者64位分别下载exe,再下载sample-minimal.xml文件 2、修改文件名 将两个文件名称修改为服务名,如: test.exe 和 test…

Nodejs+Socket.io+Web端完成聊天

前言 源码获取:nodeexpresssocket.ioweb: 聊天demo (gitee.com) 目录结构 后端依赖 启动方式 前端是html正常启动 后端是node app.js 后端app.js核心代码 const express require(express) const app express() var http require(http).Server(app) var io require(so…

Ping32和IPguard两款文件透明加密软件进行实测分享

透明加密软件在现代企业的数据安全保护中扮演着至关重要的角色。它们通过自动加密和解密文件,确保数据在存储、传输和使用过程中的安全性,从而防止敏感信息泄露。本文将介绍几种常见的透明加密软件,并对Ping32和IPguard两款加密软件进行实测分…

压铸模具适合采用3D打印随形水路吗

3D打印随形水路是一种基于3D打印技术的新型模具冷却水路设计。这种设计方式可以很好地贴合产品形状,有效提升产品良率和冷却效率,3D打印随形水路最初多应用在注塑模具上,而随着3D打印技术的发展和新材料的不断丰富,压铸模具在逐步…

DOS学习-目录与文件应用操作经典案例-more

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 二.使用 三.案例 一.前言 DOS系统的more命令是一个用于查看文本文件内容的工具。…

一个典型的分布式缓存系统是什么样的?no.32

分布式 Redis 服务 由于本课程聚焦于缓存,接下来,我将以微博内的 分布式 Redis 服务系统为例,介绍一个典型的分布式缓存系统的组成。 微博的 Redis 服务内部也称为 RedisService。RedisService 的整体架构如图所示。主要分为Proxy、存储、集…

日处理100吨污水处理设备安装需要多久

日处理100吨污水处理设备的安装时间取决于多种因素,包括设备的复杂性、安装地点的条件、所需的基础设施建设、以及安装团队的经验和效率等。以下是一个大致的安装时间框架和相关的考虑因素: 前期准备: 现场勘查和设计:1-2周&#…

【科研小小白】Faster R-CNN论文阅读笔记+与FAST RCNN区别对比+个人补充知识

论文阅读笔记 网络结构 整个Faster R-CNN可以分为三部分: **backbone:**共享基础卷积层,用于提取整张图片的特征。例如VGG16,或Resnet101,去除其中的全连接层,只留下卷基层,输出下采样后的特征…

SMERF,使用SD地图来增强模型的拓扑感知

论文链接 2311.04079v1 (arxiv.org)https://arxiv.org/pdf/2311.04079v1 研究背景 理解道路的拓扑关系是自动驾驶中很重要的一个环节,以往这个部分都是通过HD地图,及高精度地图的数据训练来实现的。高精度地图具备很多的标注信息和很明确的语义信息&a…

docker 指定jdk11镜像执行jar

dockerfile :下载jdk11 并将上传的jar 放入jdk11容器/root,改名为app.jar vi dockerfile 。。。。内容见下图 # 构建jdk11镜像 docker build -t demo . # 也可以通过jdk11镜像(前提有jdk11镜像)外挂载目录方式运行jar docker run --name d…

使用小技巧:PREEvision权限管理进阶篇

Review 在《浅谈PREEvision权限管理》一文中,我们介绍了如何在PREEvision中初始化一个权限模型,但只有模型还不够,我们需要对各个用户在不同Project中进行权限的配置,以及在EEA工程中对各个Package配置权限。 Roles and Right …

成都青年AI人才崭露头角,知了汇智科技助力孵化营大放异彩

5月18日-19日,为期两天的成都国际商贸城青年(大学生)AI应用孵化营活动在热烈的氛围中圆满落幕。本次活动由成都国际商贸城、成都成商数字科技有限公司、成都知了汇智科技有限公司及成都电商职教集团联合举办,旨在为青年&#xff0…

Project Reactor 响应式编程

Project Reactor 响应式编程 什么是响应式编程 响应式编程(Reactive Programming)是一种编程范式,致力于处理异步数据流和变化。它的核心思想是构建响应于变化的系统,即当数据流或事件发生变化时,系统能够自动地调整…

iOS单元测试覆盖率报告导出功能实现

一、插件安装 在Mac电脑上,安装slather插件。插件地址:https://github.com/SlatherOrg/slather 安装命令: gem install slather二、在Xcode上设置Code Coverage,Targets指定XXX 三、在终端切换到项目根目录下,执行单…

HTML静态网页成品作业(HTML+CSS)——魅族商城首页网页(1个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有1个页面。 二、作品演示 三、代…

Nginx - 常用的控制请求处理和响应生成的指令的高阶用法和最佳实践

文章目录 指令列表returnbreakrewriteifproxy_passtry_files 执行顺序基础用法高阶使用最佳实践 指令列表 return 作用:用于立即结束当前请求的处理并生成响应。用法:return code [text]; code 是 HTTP 状态码,如 200、301、404 等。text 是…

GitLab集成DingTalk(超级详细)

目录 参考文档1 简介2 集成方法2.1 钉钉测操作2.2 极狐GitLab侧操作2.3 钉钉群内操作 参考文档 钉钉集成 1 简介 极狐GitLab集成钉钉,可以在群组中机器人或者直接与机器人创建一对一的聊天框发送消息。当您未将钉钉账户和极狐GitLab 账户进行绑定时,机…