首頁  >  文章  >  資料庫  >  Mysql update sql造成的生產故障如何解決

Mysql update sql造成的生產故障如何解決

WBOY
WBOY轉載
2023-05-31 13:31:141063瀏覽

故障表現

  • 一方面 :在阿里雲控制台雲端資料庫PolarDB對應的叢集管理頁面上,在診斷與最佳化模組裡面的一鍵在診斷會話管理中,發現某條update sql 執行時間非常久且非常頻繁;

  • 另一方面:在業務監控系統中開始不斷有業務執行時間發出警告訊息提示,且警告的業務資料不斷上升,部分操作影響客戶使用。

業務背景

由於業務操作涉及到的業務流程比較複雜,對純技術的分享來看,不是重點討論的話,為了更有利於理解問題發生的原因,使用類比的方式,把複雜的業務類比成如下描述: 有資料庫3張表,第一張表t_grandfather (爺爺表),第二張表為t_father(父表),第三張表t_grandson(子孫表),DDL如下:

CREATE TABLE `t_grandfather ` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `count` int(11) NOT NULL DEFAULT 0 COMMENT '子孙后代数量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='老爷表';

CREATE TABLE `t_father ` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `grandfather_id` int(11) NOT NULL COMMENT '老爷表id',
  PRIMARY KEY (`id`),
  KEY `idx_grandfather_id` (`grandfather_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='老爸表';

CREATE TABLE `t_grandson` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `grandfather_id` int(11) NOT NULL COMMENT '老爷表id',
  PRIMARY KEY (`id`),
  KEY `idx_grandfather_id` (`grandfather_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='孙子表';

三張表之間的業務邏輯關係為,先生成老爺表,然後這個老爺取很多老婆(業務),會不斷的生娃,生一個娃就會生成一張老爸表,同時會更新老爺表的count=count 1,表示新增一個後代了,老爺的老婆(業務)在不斷的生娃的時候,之前的生的娃也會有老婆,他們的老婆也會生娃,對老爺來說,就是它有了孫子(產生新的業務數據),那有了孫子之後也需要更新老爺表的count=count 1,表示新增一個後代了,以此類推,子子孫孫無窮無盡也(業務資料不斷生成) 如下圖所示:

Mysql update sql造成的生產故障如何解決

祖傳程式碼的邏輯為,只要是t_father表和t_grandson有新增,就去更新t_grandfather。這個邏輯設計上問題不大,不過考慮到孫子表資料量很猛的時候,這裡就會出現一個非常嚴重的效能問題。以下是業務摘取的部分偽代碼

 /**
 * 处理 father 的业务
 */
 public void doFatherBusiness  (){
     //do fatherBusiness baba .... 此处省
     // 插入 t_father 表
    if (fatherMapper.inster(father)){
         //update t_grandfather set count=count+1 where id= #{grandfatherId}
         grandfatherMapper.updateCount(father.getGrandfatherId  ())  ;
     }
}


 /**
 * 处理 grandson 的业务
 */
 public void doGrandsonBusiness  (){
     //do grandson baba .... 此处省略
     // 插入 t_grandson 表
     if(grandsonMapper.inster(grandson)){
          //update t_grandfather set count=count+1 where id= #{grandfatherId}
          grandfatherMapper.updateCount(grandson.getGrandfatherId());
     }
}

當多個業務(線程)分別調用上面的方法時,都會對t_grandfather表的更新操作造成巨大的壓力,特別是更新同一個id的情況下,mysql server內部對鎖的競爭非常激烈。最後表現出來就如前文背景所描述的一致。

解決方案

1. 臨時處理方案:

一方面,在阿里雲控制台,對sql進行限流,在正常阻塞的會話,強制kill掉,讓資料的執行緒不阻塞著,釋放資源,另外一方面,在把接收請求的服務減少節點數,目的是減少業務資料量進入;

2 .長久方案

一方面更改掉上面的業務邏輯,插入t_grandson表和t_father表時,不在去更新t_grandfather表的count字段;另一方面,需要用到count統計需求時,全部切換成別的方式;

以上是Mysql update sql造成的生產故障如何解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除