Sybase数据库中自旋锁和CPU使用率

本文探讨了SAP ASE中自旋锁如何影响CPU使用率,并提供了识别和解决自旋锁竞争问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

翻译整理自文章《Spinlocks and CPU usage in SAP ASE》

目的

这篇文章的目的是清楚的了解SAP ASE怎样使用自旋锁及对整体CPU使用率可能产生的影响。

简介

通常,SAP ASE中CPU高可以归因为自旋锁的使用。这篇文章将要展示怎样识别这些条件和推荐的ASE调优方法。

什么是自旋锁?

  • 在一个多引擎的服务中需要使用同步机制保护共享资源。
    ASE使用自旋锁作为它同步机制的一种
    自旋锁是一种只能被原子性更新的数据结构(就是在同一个时刻只能有一个引擎修改它)

  • 当一个任务修改一个共享的数据项,它必须先持有自旋锁。
    共享数据项是类似于运行队列、数据缓存页列表、锁结构等

  • 自旋锁阻止同一时刻另外一个任务修改它的值。
    这当然是假设另外一个任务也在自旋锁的保护机制下执行访问

  • 一个需要获取自旋锁的任务在被授予之前将要“自旋”(阻塞)
    当同一时刻多个引擎在自旋时CPU使用率会大大升高

  • 自旋锁必须尽可能的快和高效
    为了减小竞争一个进程通常在不断的循环请求和释放他的自旋锁
    因此自旋锁使用平台相关的汇编语言编写

自旋锁和其他同步机制的比较

类型复杂度CPU 开销等待时间
自旋锁非常低
闩锁中等比较小
表、页、行地址锁可能有很大差别

自旋锁和CPU 使用率

  • spid 在获取自旋锁之前不会让出引擎
    所以一个正在等待自旋锁的spid,在获取这个自旋锁之前会引起该引擎用户态100%

  • 自旋锁竞争百分比是用等待/抢占来度量的
    比如:10000抢占中3000次等待=30% 竞争

  • 为了查找性能问题,使用总自旋数,不是竞争比
    比如:两个自旋锁

    • 一个100次抢占中40次等待但是200次自旋 = 40% 竞争
    • 第二个10000次抢占中400次等待但是20000次自旋 = 4%竞争

    第二个虽然竞争度很低,但是使用了更多CPU周期自旋。
    我们应该关注第二个例子的调优,而不是第一个。

解决自旋锁问题

  • 自旋锁的竞争和自旋是CPU高的一个主要原因
  • 第一步是判断实际上CPU高是不是由自旋锁使用引起的。
  • 第二步是判断哪一个或哪一些自旋锁引起了这种情况。
  • 第三步是判断使用哪种调优来减小这个问题。

注意 你永远也不可能得到0%自旋锁竞争除非在只有一个引擎的服务上运行。就是说,不要去想消除自旋锁竞争。它只能被尽可能的减小。

第一步 - 检查自旋锁竞争和自旋

  • 使用sp_sysmon去判断是否CPU高是因为自旋锁
  • 检查“CPU Busy”(或者“User Busy” 在15.7线程模式中)。
  • 如果引擎没有显示出高busy%那么自旋锁不是一个大问题。
  • 在“Data Cache Management”中检查"Total Cache Hits"
    如果每秒缓存命中率高并且和cpu busy%一起上升,那么你应该查找全表扫描和查询计划问题而不是自旋锁。
  • 通常,如果CPU使用率增加但是事务提交量、缓存命中数、锁请求数、扫描数等在下降,那么自旋锁使用可能是一个问题。

第二步 - 哪一个或哪一些自旋锁引起竞争?

  • 使用sp_sysmon
  • 这里列出了几种自旋锁,但是只展示了竞争百分比
  1. Object Manager Spinlock Contention
  2. Object Spinlock Contention
  3. Index Spinlock Contention
  4. Index Hash Spinlock Contention
  5. Partition Spinlock Contention
  6. Partition Hash Spinlock Contention
  7. Lock Hashtables Spinlock Contention
  8. Data Cache Spinlock Contention
  • 这些中的任何一个竞争高可能暗示一个问题
    但是,你可能有其他的自旋锁竞争并没有在sp_sysmon报告中显示

  • 使用MDA表 monSpinlockActivity
    这张表在15.7 ESD#2版本加入

  • 使用标准SQL查询
    一个根据一分钟间隔内的自旋次数展示前10条自旋锁的查询可能是这样的

   select * into #t1 from monSpinlockActivity
   waitfor delay "00:01:00"
   select * into #t2 from monSpinlockActivity
   select top 10 convert(char(30),a.SpinlockName) as SpinlockName,
   (b.Grabs - a.Grabs) as Grabs,(b.Spins - a.Spins) as Spins,
   case when a.Grabs = b.Grabs then 0.00 else convert(numeric(5,2),(100.0 * (b.Waits - a.Waits))/(b.Grabs-a.Grabs)) end as Contention 
   from #t1 a,#t2 b where a.SpinlockName = b.SpinlockName 
   order by 3 desc   

使用monSpinlockActivity可能的问题

  • 多个引擎的自旋锁将被聚集计算
    例如,所有的数据缓存分区自旋锁将被显示成一行
    这可能使仅一个缓存分区引起问题的情况不能被发现
  • 必须设置’enable spinlock monitoring’ 配置参数
    测试显示对于繁忙的服务这又增加了大约1%的开销
  • monSpinlockActivity 显示当前和最后一个拥有者的KPIDs。这可能是有用的对检查的进程是否是造成特定自旋锁。

第三步 - 做什么调优会对减小这个问题

  • 这要依据哪些自旋锁是高度自旋的大量判断
  • 注意这也有可能降低了一个自旋锁的竞争然后又增加了另一个

一些更通用的自旋锁和可能的解决办法

  • Object Manager Spinlock(Resource ->rdesmgr_spin)

    1. 确定配置了充足的’number of open objects’
    2. 用monOpenObjectActivity识别热点对象
    3. 使用 dbcc ture(des_bing)将热点对象绑定到DES缓存
    4. 修改起作用的原因是用来保护DES 不被使用的自旋锁知道确切数目。当DES被绑定整个进程将跳过。
  • Data Cache spinlocks

    1. 减少data cache spinlock 利用率最简单的方法是增加data cache 分区的数量。
    2. 注意如果data cache 被设置成了"relaxed LRU",自旋锁使用率可能会大幅减小。这是因为relaxed LRU缓存不用维护LRU->MRU链,所以不需要抢占自旋锁去移动页到MRU端。
    3. 有一些定义条件使用这个帮助(一个周转率非常高的缓存是不适合relaxed LRU的)
  • Procedure Cache Spinlock (Resource ->rproccache_spin)

    1. 从全局过程缓存内存池(包括语句缓存)中分配和释放页需要是用自旋锁。
    2. 一些可能的原因包括:
      过程缓存太小, 存储过程和语句经常被移出和替换
      存储过程重新编译
      Large scale 分配
    3. 减小这个自旋锁的压力
    4. 消除存储过程重新编译的原因
    5. 如果运行一个比ASE 15.7ESD#4低的版本,需要升级。ASE 15.7 ESD#4和4.2有一些修改,减小了持有自旋锁的时间。
    6. trace flags 753和757可以减小 large-scale的分配
    7. 在ASE15.7 SP100之后的版本,使用配置参数"enable large chunk elc"
    8. 使用dbcc proc_cache(free_unused) 作为临时的减小自旋锁和CPU使用率的方法。
  • Procedure Cache Manager Spinlock( Resource ->rprocmgr_spin)

    1. 动态SQL和存储过程进入和移出过程缓存时使用自旋锁
  1. ASE15.7 ESD#1之前的版本当更新内存计数结构时使用自旋锁
    原因是创建另外一个自旋锁的竞争
    3. 高竞争比的原因包括:
    大量使用动态SQL
    过程缓存太小
  2. 可能的解决措施和rproccache_spin 一样
  • Lock Manager spinlocks(fglockspins,addrlockspins,tablockspins)

    1. 这些自旋锁用来保护 lock manager hashtables
    2. 如果lock HWMs 设置的太高,意为着更多的锁和竞争
    3. 达到目标的主要方式是调节配置
      lock spinlock ratio
      lock address spinlock ratio
      lock table spinlock ratio
      lock hashtable size

谨记

  • 抵制因CPU高而添加更多引擎的诱惑
    如果CPU高是因为自旋锁竞争引起的,添加更多的CPU只会使事情更糟。
    添加更多的"spinner"只会简单的增加每个spid 获取自旋锁的时间,甚至更慢。
<think>好的,我现在需要回答用户关于互斥锁(mutex lock)自旋锁(spin lock)的使用场景及主要区别的问题。首先,我得回忆一下这两种锁的基本概念它们在操作系统中的作用。互斥锁自旋锁都是用来实现线程同步的机制,但它们的实现方式适用场景不同。 根据用户提供的引用资料,特别是引用[2][3],互斥锁在获取不到锁时会让线程进入睡眠状态,释放CPU资源,而自旋锁则会一直循环检查锁的状态,占着CPU不放。这让我想到,自旋锁适用于锁持有时间非常短的场景,比如内核中的某些操作,而互斥锁更适合锁持有时间较长的情况,避免CPU空转浪费资源。 接下来,我需要整理它们的区别。根据引用[4],自旋锁在Linux内核中的使用需要初始化正确的加锁解锁操作,而互斥锁可能涉及到更复杂的上下文切换。性能方面,引用[1]提到当等待时间在纳秒级别且线程数较少时,自旋锁性能更好,CPU使用率互斥锁相差不大。这时候用户可能需要权衡等待时间线程数量来选择锁的类型。 然后,使用场景方面,引用[3]提到自旋锁在不能睡眠的上下文中使用,比如中断处理程序,而互斥锁适合用户空间的长时间等待。这里需要明确用户的应用场景是在内核还是用户空间,以及锁的持有时间长短。 另外,需要注意死锁的问题。两种锁都可能引起死锁,但自旋锁如果在获取锁后发生中断,并且中断处理程序也尝试获取同一个锁,会导致死锁,因此需要配合禁用中断的操作,如引用[4]提到的内核中的使用方式。 最后,生成相关问题时要围绕用户可能的后续疑问,比如如何选择、性能分析、实现原理、死锁预防等,确保问题覆盖用户可能感兴趣的方向。</think>### 互斥锁(Mutex Lock)与自旋锁(Spin Lock)对比 #### 1. **核心区别** - **实现机制**: - **自旋锁**:当线程尝试获取锁失败时,会持续循环检测锁状态(忙等待),不释放CPU资源。适用于锁持有时间极短的场景,例如$T_{wait} < 1\mu s$[^1][^2]。 - **互斥锁**:若锁已被占用,线程会主动让出CPU并进入睡眠状态,直到锁被释放后被唤醒。适用于锁持有时间较长或存在资源竞争较激烈的场景[^3][^4]。 - **性能特点**: - 自旋锁避免了上下文切换的开销,但在竞争下可能导致CPU资源浪费。 - 互斥锁通过睡眠减少CPU占用,但频繁的上下文切换会增加额外开销(通常在$\mu s$级)。 #### 2. **使用场景** - **自旋锁适用场景**: - 锁持有时间极短(如内核中断处理、原子操作)。 - 线程数较少(例如引用[1]中提到的$TNUM=2$)。 - 无法睡眠的上下文(如中断服务例程)[^4]。 - **互斥锁适用场景**: - 锁持有时间较长(如文件I/O、数据库操作)。 - 用户空间多线程编程(避免忙等待浪费CPU)。 - 并发场景(减少CPU空转)。 #### 3. **性能对比示例** 假设线程数为2,锁等待时间为$ns$级: - 自旋锁的响应时间接近直接获取锁的时间,且CPU利用率与互斥锁相差不大。 - 当等待时间增加到$\mu s$级时,互斥锁因避免忙等待而性能更优。 #### 4. **代码示例(Linux内核)** ```c // 自旋锁使用示例(内核空间) #include <linux/spinlock.h> spinlock_t my_lock; spin_lock_init(&my_lock); spin_lock(&my_lock); /* 临界区操作 */ spin_unlock(&my_lock); ``` ```c // 互斥锁使用示例(用户空间) pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mutex); /* 临界区操作 */ pthread_mutex_unlock(&mutex); ``` #### 5. **风险与注意事项** - **自旋锁**:需避免在单核CPU竞争场景中使用,否则可能引发CPU资源浪费或死锁[^3]。 - **互斥锁**:需注意优先级反转问题(可通过优先级继承解决)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值