Skip to main content
数据库 Index-Merge 导致的死锁

问题

监控系统,告警发现 serviceA-task 定时同步供应商订单任务执行出现失败,后来发现 serviceB-api 的日志报文中也一直有死锁存在,Log 日志具体如下:

### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction, dubbo version: 2.13.2.RELEASE, current host: 10.36.131.12 org.springframework.dao.DeadlockLoserDataAccessException:
### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

问题原因

问题背景

(1)RPC 接口:InboundAppointmentRpcService.createInboundAppointment

(2)Task 任务:shire-task#supplierSaleOrderAggregateTask

上述都会对表 wms_supplier_order_info 执行下面语句更新数据库记录

@Override
    public int updateSupplierOrderInfo(WmsSupplierOrderInfo reocrd) {
        if (Objects.isNull(reocrd)) {
            return 0;
        }
        WmsSupplierOrderInfoExample example = new WmsSupplierOrderInfoExample();
        example.createCriteria()
                .andWarehouseIdEqualTo(reocrd.getWarehouseId())
                .andSupplierIdEqualTo(reocrd.getSupplierId())
                .andGoodsIdEqualTo(reocrd.getGoodsId())
                .andExpectTimeEqualTo(reocrd.getExpectTime())
                .andIsDeletedEqualTo(Boolean.FALSE);
        return mapper.updateByExampleSelective(reocrd, example);
    }

问题原因分析

分析进度 1:

按照上述的更新语句,模拟写了一条查询语句(和上面更新语句的条件是一样的),查看执行计划,出现一条语句走了两条索引,索引类型为 index merge

explain SELECT * FROM wms_supplier_order_info where warehouse_id = 2 and supplier_id = 434135643 and goods_id = 175091807986 and expect_time = '2020-10-12 00:00:00' and is_deleted = 0

image-20240509172744833.png

查了文档,发现出现 index merge 操作会大大增加数据库死锁的概率-附上官方文档:https://bugs.mysql.com/bug.php?id=77209

分析进度 2

找 DBA 同事拿到了当时的死锁日志如下,并还原当时的 DDL 更新语句:

还原当时场景下对应的 SQL 语句,如下:

第一个事务对应的语句

SET warehouse_id = 6880,
        supplier_id = 334985823,
        expect_time = '2021-01-26 00:00:00',
        cargo_id = 218057,
        goods_id = 207967301292,
        goods_name = '【无辣不欢】香辣小米椒100g',
        quantity = 66,
        fetch_time = '2021-01-25 01:31:42.944000',
        sku_spec = '100g/份',
        supplier_name = '河源市喜悦生态农业科技有限公司'
     WHERE (  warehouse_id = 6880
                  and supplier_id = 334985823
                  and goods_id = 207967301292 and expect_time = '2021-01-26 00:00:00' and is_deleted = "false"

第二个事务对应的语句

SET id = 1566583,
        warehouse_id = 3997,
        supplier_id = 735844057,

        expect_time = '2021-01-26 00:00:00',
        cargo_id = 26557,
        goods_id = 184949669110,
        goods_name = '苏菲超熟睡柔棉感420mm4片+弹力贴身纤巧230mm10片日夜组合装',
        quantity = 11,
        fetch_time = '2021-01-25 00:47:37',
        created_at = '2021-01-25 00:03:08',
        updated_at = '2021-01-25 00:47:37',
        is_deleted = 0,
        sku_spec = '14片/条',
        supplier_name = '恒安金盛居家日用专营店',
        `status` = 1,
        expect_first_arrival_time = '2021-01-25 10:00:00' , expect_quantity = 400 where ( warehouse_id = 3997
                  and supplier_id = 735844057
                  and goods_id = 184949669110 and expect_time = '2021-01-26 00:00:00' and is_deleted = "false")

对上面的死锁日志进行分析

(1)事务 1 TRANSACTION(1):持有 4 把行锁(4 row lock(s)), 其中一把处于等待状态((1) WAITING FOR THIS LOCK TO BE GRANTED),位于页面编号为 61 的地方,锁针对的是主键索引(index PRIMARY of table)的记录锁(Record lock),只锁记录不锁区间

(2)事务 2 TRANSACTION(2)持有 23 把锁,其中持有((2) HOLDS THE LOCK(S))页面编号为 61 的一个主键记录锁(正是事务 1 在等待的),有 15 把是处于所等待的状态,就是等待索引 index idx_expect_time_is_deleted 的锁

(3)进一步分析,事务 1 需要的那把锁正好在事务 2 的手里,而对于事务 2 需要获取的索引 index idx_expect_time_is_deleted 的锁,发现已经被事务 1 占用,只能阻塞等待,出现了互相等待问题,进入死锁

模拟分析当时的两个事务加锁的场景可能如下:

image-20240509173205913.png

解决方式

1、尽量避免使用多 where 条件更新记录,可以先查询出来,然后根据主键更新。

2、优化索引,创建联合索引 goods_id,expect_time,is_deleted

3、避免使用大事务,在事务内的加上的行锁,只能在 commit 后,锁才会释放,控制所有锁的时间

4、关闭 MySQL 优化器的 index merge 功能

附录

问题:

1、为什么使用 Merge Index 技术呢?

答:Merge Index 索引合并技术是 MySQL 的一个优化,对多个索引分别进行条件扫描,然后将它们各自的结果进行合并(intersect/union)

参考:

Merger-Index 导致死锁:https://blog.csdn.net/daidaineteasy/article/details/109266083

Merge-Index 技术剖析:https://www.orczhou.com/index.php/2013/01/mysql-source-code-query-optimization-index-merge/

Merge-Index 技术官方介绍:https://dev.mysql.com/doc/refman/5.6/en/index-merge-optimization.html

👏评论2025-05-31 01:53:40
Cloudflare Workers AI:免费体验14B参数大模型

Cloudflare Workers AI:免费体验14B参数大模型

一般来说大模型,我们普通人部署不起来。小模型自己部署质量又太差,可以试试cloudflare 上面部署的14b 的不大不小模型,通过API 即可调用,速度很快,支持中文,支持大部分流行开源模型。

首先必要条件

  • 有 cloudflare 账号
  • 可以科学上网

获取 API 令牌

进入 https://dash.cloudflare.com/5a8357419fa33acb237f231b2c4ffe02/ai/workers-ai/models 这个页面,点击 使用 REST API进行创建API页面。

  1. 在页面上可以看到已经有你调用的账号ID了,但是还不够,我们还需要API token 令牌,才能完成接口调用。

账号ID:

5a8357419fa33acb237f231xxxxxx

  1. 接下来我们点击创建Works AI API 令牌 ,得到如下令牌。

cloudlfare workAI apitoken:

Z0Oe3xLr8Tb5Lp9j63bTk677hEgXXXXXXXXX

  1. 选择下面你想用的方式进行测试调用,有curl、javaScript、python。我们用curl 测试看下。

测试这个模型通过,可以看到中文支持比较好。

curl -X POST \
  https://api.cloudflare.com/client/v4/accounts/帐户ID/ai/run/@cf/qwen/qwen1.5-14b-chat-awq \
  -H "Authorization: Bearer Z0Oe3xLr8Tb5Lp9j63bTk677hEgXXXXXXXXX" \
  -d '{"messages":[{"role":"system","content":"你是一个ai助手"},{"role":"user","content":"讲一个笑话 "}]}'

参考

  1. https://dash.cloudflare.com/5a8357419fa33acb237f231b2c4ffe02/ai/workers-ai/models
👏评论2025-05-31 01:53:39
前端/CSS/flex

前言

1、felx (弹性布局)只能处理一维布局

2、grid (网格布局)可以处理二维布局

介绍

Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。 任何一个容器都可以指定为 Flex 布局。 行内元素也可以使用 Flex 布局。注意:设为 Flex 布局,则子元素的floatclear属性将失效。

.box {
  display: flex;
}
.box1 {
  display: inline-flex;
}

基本概念

采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。

在这里插入图片描述

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做 main start,结束位置叫做 main end;交叉轴的开始位置叫做 cross start,结束位置叫做 cross end。 项目默认沿主轴排列。单个项目占据的主轴空间叫做 main size,占据的交叉轴空间叫做 cross size。 ————————————————

原文链接:https://blog.csdn.net/Sandersonia/article/details/132159383

容器属性

以下 6 个属性设置在容器上。

  • flex-direction:主轴的方向(即项目的排列方向)。
  • flex-wrap:一行内容内容过多时排列方式
  • flex-flow:是 flex-direction 属性和 flex-wrap 属性的简写形式
  • justify-content:在主轴上的对齐方式
  • align-items:在交叉轴上如何对齐
  • align-content:多根轴线的对齐方式
👏评论2025-05-31 01:53:39
安装 Node.js 和 Git

安装 Node.js

选择版本和系统

  1. 访问 Node.js 官网https://nodejs.org/en/download/prebuilt-binaries/current 1e819d2f70369b7d50ca2d48d4c26751dfd6ece7_knock_capture_image
  2. 选择版本: 选择最新的 LTS 版本,例如:v20.17.0(LTS)。 LTS 版本代表长期支持版本,它更稳定,适合生产环境使用。
  3. 选择系统: 选择您的操作系统版本,例如:Linux
  4. 选择架构: 选择您的硬件架构,例如:x64 提示: 使用 uname -a 命令查看您的系统信息。
uname -a

输出示例

Linux racknerd-f03fadb 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64 GNU/Linux

解析

  • Linux:操作系统是 Linux。
  • x86_64:硬件架构是 x64。

下载和解压

  1. 复制下载链接: 右键点击下载按钮,选择复制链接地址。 8f599348ae2f8a364616724682a9369ad58295be_knock_capture_image
  2. 下载 Node.js: 使用 wget 命令下载 Node.js 安装包。
wget https://nodejs.org/dist/v20.17.0/node-v20.17.0-linux-x64.tar.xz

提示: 下载链接可能因版本更新而变化,请根据实际情况替换链接中的版本号。 3. 解压安装包: 使用 tar 命令解压安装包。

tar xf node-v20.17.0-linux-x64.tar.xz

创建软连接

Node.js 解压后的目录中包含 bin 子目录,其中包含 nodenpm 等可执行文件。为了方便使用,我们可以创建软连接,将它们链接到系统路径。

ln -s /root/node-v20.17.0-linux-x64/bin/npm /usr/local/bin/
ln -s /root/node-v20.17.0-linux-x64/bin/node /usr/local/bin/

提示: 您可以根据实际情况将 /root/ 替换为 Node.js 解压目录的实际路径。

安装 Git

下载 Git

  1. 访问 Git 官网https://git-scm.com/download/linux
  2. 选择适合您的系统版本进行下载提示: 请根据您的操作系统版本选择合适的版本进行下载。

生成 SSH 密钥

为了方便使用 SSH 协议进行 Git 操作,我们需要生成 SSH 密钥。

  1. 打开终端
  2. 执行以下命令生成 SSH 密钥
ssh-keygen -t rsa -b 4096 -C "[email protected]"

参数说明

  • -t rsa:指定密钥类型为 RSA。
  • -b 4096:指定密钥长度为 4096 位。
  • -C "[email protected]":指定您的邮箱地址。 提示: 按照提示操作,可以为密钥设置密码。
  1. 查看公钥
cat ~/.ssh/id_rsa.pub

提示: 将公钥内容复制并粘贴到 GitHub 账号的 SSH 密钥设置中。

克隆仓库

使用 git clone 命令克隆 GitHub 仓库。

git clone [email protected]:username/repo.git

参数说明

  • [email protected]:username/repo.git:GitHub 仓库地址。
  • username:GitHub 用户名。
  • repo:GitHub 仓库名称。

常见问题

  • 碰到提示报错: Host key verification failed: 执行 ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts 将 GitHub 域名添加到 known_hosts 文件。
  • 碰到提示报错: Warning: UNPROTECTED PRIVATE KEY FILE!: 执行 chmod 600 ~/.ssh/id_rsa 修改私钥文件权限,确保只有您有权访问该文件。

请注意: 本文是当前本人亲自操作过程,具体操作请根据实际情况进行调整。

希望以上内容能帮助您顺利安装 Node.js 和 Git 。

👏评论2024-09-02 20:00:00