超卖问题解决方案
目录
需求概述
系统需求
提升高并发吞吐量
解决超卖问题
解决方案分析
悲观锁与乐观锁
悲观锁
乐观锁
数据库行级锁
实现悲观锁(排他锁)
实现乐观锁
悲观锁&乐观锁
Redis分布式锁
Redis原子操作方案
方案分析
技术实现
通过MULTI事务命令实现
Redis+Lua实现
使用Lua注意点
需求概述
系统需求
在本项目的抢卷模块中需要实现下边两个需求
提升高并发吞吐量
抢卷类似抢购、秒杀等业务场景,具有时效性的特点,提前规定好用户在什么时间可以抢购,用户访问集中,这样就会给系统造成高并发,抢卷模块在设计时需要以提升系统在高并发下的吞吐量为目标(吞吐量表示单位时间内系统处理的总请求数量,吞吐量高意味着系统处理能力强
衡量系统吞吐量的常用指标:QPS,TPS
QPS(Queries Per Second):
每秒查询数(Queries Per Second),它表示系统在每秒内 能够处理的查询或请求的数量,是衡量一个系统处理请求的性能和吞吐量的指标。
计算公式:总请求数/时间窗口大小
示例:
在10秒内处理1万个请求,QPS为1000。每个请求处理的时间越短,QPS越大。
假设:一个网站有10万用户,有2万日活跃用户,并发量是4000,每个用户每秒平均发起2个请求,那么总请求数就是 2*4000,那么QPS就是 8000,如果单机支持2000的qps理论上需要4台服务器。
qps指标是需要根据服务器硬件性能、及具体的业务场景去测试,比如:门户查询数据如果直接走Nginx静态服务器则QPS可以达到上万,如果请求查询Tomcat,并且通过数据库去查询数据库返回,此时QPS会远低于查询Nginx静态服务器的QPS值,如果不走数据库,而是从Redis查询数其QPS也会大大提升。
TPS(Transactions Per Second):
表示系统每秒完成的事务数,与QPS不同,TPS更关注系统的事务处理能力,而不仅仅是单纯的查询或请求,一次事务通常会包括多个请求。在高度事务性的系统中,如在线交易系统、支付系统等,TPS是一个关键指标,用于衡量系统的处理能力。
TPS指标通常会涉及业务处理及数据库存储,在测试时也需要根据服务器硬件性能、及具体的业务场景去测试,拿下单举例:单机支持几十到几百的TPS指标属于正常。
解决超卖问题
超卖是最终下单购买数量大于库存数量,比如:库存有100个,用户最终购买了101个,多出这一个就是超卖了,结合抢券业务即用户最终抢到的优惠券总数大于优惠券库存数。
造成超卖的原因:造成超卖问题的原因是在高并发场景下对库存这个共享资源进行操作存在线程不安全所导致
举例:
下图是两个线程更新数据库的库存字段。
线程1:先查询库存为1,判断是否大于0,如果大于则库存减1,最后更新数据库库存字段
线程2:先查询库存为1,判断是否大于0,如果大于则库存减1,最后更新数据库库存字段
线程1和线程2查询到的库存都是1,两个线程分别减1得到剩余库存数为0,由于线程2并不是基于线程1扣减库存后的值进行扣减,线程2更新库存覆盖了线程1更新的库存值,最后的库存都为0,但是却执行了两次卖出操作,因此出现了超卖问题。
解决方案分析
悲观锁与乐观锁
悲观锁
悲观锁是一种悲观思想,总是认为会有其他线程修改数据库,为了保证线程安全,因此在操作前总是先加锁,操作完成后释放锁,其他线程只有当锁释放后才可以获取锁继续操作数据。synchronized和ReentrantLock都可以实现悲观锁
使用悲观锁后,原来的多线程并发执行改为了顺序(同步)执行,当线程2去执行时查询到库存发现为0,不满足条件更新库存失败
乐观锁
乐观锁是一种乐观思想,认为不会有太多线程去并发修改数据,所以谁都可以去执行代码
Java提供的CAS机制可以实现乐观锁,CAS(Compare And Swap,比较并交换),在修改数据前比较版本号,如果数据的版本号骄傲没有变化说明书菊没有修改,此时再去修改数据
示例:
库存数据对应一个版本,库存每次变化则版本号跟着变化,如下:
库存 | 版本号 |
100 | 1 |
99 | 2 |
... | ... |
1 | 100 |
0 | 101 |
线程1修改库存前拿到库存及对应的版本号:1和100。
线程1判断库存如果大于0则将库存减1,准备更新库存。
更新库存时要校验当前库存的版本是否和自己之前拿到的一致,如果版本号为1说明自己在执行的这过程没有其它线程去修改过库存,此时将库存更新为99并将库存加1为2。
线程2执行和线程1一样的逻辑,线程2去更新库存时发现库存的版本号为2与自己之前拿到的不一致,更新库存失败。
数据库行级锁
实现悲观锁(排他锁)
执行select ... for update实现加锁,select ... for update会锁住符合条件的行的数据,如下语句会锁住一行的数据:
select * from 库存表 where id=? for update
通常此语句放在事务中,开启事务时执行此语句获取锁,事务提交或回滚自动释放锁,保证在事务处理过程中没有其他线程去修改数据。
高并发场景不推荐使用select … for update方法,同时也可能存在死锁的潜在风险。
实现乐观锁
数据库行级锁也可以实现乐观锁,通常做法是在表中添加一个version字段,在更新时对比版本号,更新成功将版本号加1,SQL为:
update 表名 set 字段=值,version=version+1 where id =? and version =?
针对扣减库存业务:
update 库存表 set 库存=库存-1 where 库存>0 and id =?
多线程执行上面的SQL,假如线程1先执行会添加排他锁,当事务没有结束前其他线程去更新同一条记录会被阻塞,等到线程1更新结束其他线程才可以更新库存
当执行update后返回影响的记录行数为1,表示更新成功即扣减库存成功,返回0表示没有更新记录行,即扣减库存失败
悲观锁&乐观锁
悲观锁和乐观锁都是一种解决共享资源的线程安全问题的方法,悲观锁是在读数据时就加锁,如果读比较多则加锁频繁影响性能,相比而言乐观锁性能比悲观锁要好。
对于并发不高的场景可以使用数据乐观锁去控制扣减库存,由于抢购业务并发较高且对性能要求也高,如果使用数据库行级锁去控制,并发高就会对数据造成压力,如果进行限流控制并发数又无法满足性能要求,所以对于抢购业务使用数据库行级锁进行控制是不合适的
Redis分布式锁
数据库乐观锁不适合用高并发场景,可以将库存数据放在Redis,并且通过JVM锁区控制扣减库存
上边介绍的synchronized、reentrantLock、CAS只控制了JVM本身的线程争抢同一个锁,无法控制多个JVM之间争抢同一个锁。
如下图,有两个JVM进程,每个JVM进程都有一个Lock01锁,这两个JVM进程中的线程1仍然会同时去修改库存:
线程1:先查询库存为1,判断是否大于0,如果大于则库存减1,最后更新Redis库存数据。
线程2:先查询库存为1,判断是否大于0,如果大于则库存减1,最后更新Redis库存数据。
此时就会出现修改库存数据的线程不安全问题。
所以,如果是单机环境下,使用JVM的锁在内存加锁可以解决资源并发访问的线程安全问题。
微服务架构的项目在部署时,每个微服务会部署多个实例(每个JVM就是一个实例),如果要控制多个JVM之间争抢资源需要用到分布式锁,分布式锁是由一个统一的服务提供分布式锁服务,例如Redis等数据库可以实现分布式锁。
如下图,每个JVM中的线程取证强同一个分布式锁,在扣减库存前先获取分布式锁,拿到锁再扣减库存,执行完释放锁之后其他的JVM的线程才可以获取锁继续扣减库存,如下图:
上述方案将库存放在Redis中避免了与数据库交互,很大程度上提高了执行效率,在分布式场景下使用分布式锁是一种常用的控制共享资源的方案
分布式锁需要搭建独立的分布式锁服务(例如Redis、Zookeeper等),每次操作需要远程与分布式锁服务交互获取锁、释放锁。
Redis原子操作方案
上边使用分布式锁的方案中,每次操作需要远程与分布式锁服务交互获取锁、释放锁,在这个过程中申请锁和释放锁的交互操作在一定程度上会损耗服务器的性能,因此我们尝试将锁的交互进行优化
分布式锁方案中是在Java程序扣减库存最后更新redis库存的值,可以使用redis的decr命令去扣减库存
(Redis Decr命令将key中储存的数字值减1,并且具有原子性,Redis中所有命令都具有原子性
原子性表示该命令在执行过程中是不被中断的,也就实现了多线程去执行decr命令扣减库存是顺序执行的,加入库存原来是100,扣减到0结束,多线程并发执行decr命令不会出现扣减次数超过100次,如下图:
基于Redis命令的原子性,我们将JVM锁的交互转移到Redis数据库中进行处理:
方案分析
在Redis原子操作方案中扣减库存使用decr命令实现,decr命令具有原子性,如果在扣减库存操作中有多个操作,那么操作不再是原子性:
扣减库存逻辑如下:
1、首先查询库存
2、判断库存大小,如果大于0则扣减库存,否则 直接返回
3、记录抢券成功的记录,用于判断用户不能重复抢券的依据。
4、记录抢券同步的记录,用于后续的异步处理,将抢券结果保存到数据库。
如果上述四步整体不具有原子性仍然没有办法控制超卖问题,所以必须保证1、2、3步逻辑放在一起整体具有原子性。
因此需要我们保证多个Redis命令具有原子性
技术实现
对于redis单个命令都是原子操作,现在要求扣减库存、写入抢卷成功队列及写入同步队列保证原子性,有两个解决方案:通过MULTI事务命令实现、Redis+Lua实现
通过MULTI事务命令实现
MULTI
HSET key1 field1 value2 field2 value2
INCR key2
EXEC
命令执行流程如下:
执行MULTI 标记首先标记一个事务块开始。
然后将要执行的命令加入队列。
将“HSET key1 field1 value2 field2 value2” 命令放入队列中,表示向key1中写入两个hashkey。
将“INCR key2”命令放入队列中,表示对key2自增1。
运行EXEC命令按顺序执行,整体保证原子性。
Pipeline与MULTI区别
pipline也可实现批量执行多个 redis命令,pipline与multi的区别是:
pipeline 是把多个redis指令一起发出去,redis并没有保证这些命令的执行是原子的;multi实现的是将多个命令作为事务块去执行,保证整个操作的原子性。
如果仅是执行多个命令不保证原子性那么使用pipeline 的性能要比multi要高,但是针对本项目要保证多个命令实现原子性的需求那么pipeline 不符合要求。
Redis+Lua实现
Lua 是一种强大、高效、轻量级、可嵌入的脚本语言,Lua体积小、启动速度快,从而适合嵌入在别的程序里,Lua可以用于web开发、游戏开发、嵌入式开发等领域。
参考:http://www.lua.org/docs.html
对上边的例子编写Lua脚本,如下:
local ret = redis.call('hset', KEYS[1], ARGV[1], ARGV[2], ARGV[3], ARGV[4]);
redis.call('incr', KEYS[2]);
return ret..'';
说明:
KEYS:表示在脚本中所用到的那些Redis键(key),这些键名参数可以在Lua中通过全局变量KEYS数组,KEYS[1]表示第一个key,KEYS[2]表示第二个key...
ARGV:表示在脚本中所用到的参数,在Lua主功能通过全局变量ARGV数组访问,访问形式和KEYS变量类似(ARGV[1]、ARGV[2],诸如此类),ARGV[1]、ARGV[2]分别表示第一个第二个参数。。
执行Lua脚本:
使用EVAL 命令执行Lua脚本。
EVAL是redis的命令本身具有原子性,整个脚本的执行具有原子性。
EVAL script numkeys key [key ...] arg [arg ...]
参数说明:
- script: 是一段 Lua 5.1 脚本程序。
- numkeys: 用于指定键名参数的个数。
- key [key ...]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
- arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
eval "local ret = redis.call('hset', KEYS[1], ARGV[1], ARGV[2], ARGV[3], ARGV[4]);redis.call('incr', KEYS[2]);return ret..'';" 2 test_key01 test_key02 field1 aa field2 bb
说明:
eval后边的script参数即脚本程序,将上边的Lua脚本使用双引号括起来。
numkeys:为2表示2个key
之后传入key的名称(多key中间用空格分隔):test_key01 test_key02
key后边再传入ARGV 参数(多ARGV 中间用空格分隔):field1 aa field2 bb
Java代码中调用Lua脚本:
指定Lua脚本的位置,通过DefaultRedisScript的setScriptSource方法完成:
在RedisLuaConfiguration中定义DefaultRedisScript bean:
@Bean("Lua_test01")
public DefaultRedisScript<Integer> getLuaTest01() {DefaultRedisScript<Integer> redisScript = new DefaultRedisScript<>();//resource目录下的scripts文件下的Lua_test01.Lua文件redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("scripts/Lua_test01.Lua")));redisScript.setResultType(Integer.class);return redisScript;
}
创建lua脚本 :~~
创建RedisTest测试类:
注入上边定义的DefaultRedisScript,注意注入时指定名称“Lua_test01”。
package com.jzo2o.market.service;import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;@SpringBootTest
@Slf4j
public class RedisLuaTest {@Resource(name = "redisTemplate")RedisTemplate redisTemplate;@Resource(name = "Lua_test01")DefaultRedisScript script;//测试Lua@Testpublic void test_Luafirst() {//参数1:key ,key1:test_key01 key2:test_key02List<String> keys = Arrays.asList("test_key01","test_key02");//参数2:传入Lua脚本的参数,"field1","aa","field2", "bb"Object result = redisTemplate.execute(script, keys, "field1","aa","field2", "bb");log.info("执行结果:{}",result);}}
MULTI 不适合写带有业务逻辑的脚本内容,并且MULTI 执行命令是执行完成最后一起拿到所有命令的执行结果,业务中有一些逻辑判断,可能需要提前返回结果,因此我们使用Redis+Lua实现抢卷功能
抢卷功能的Lua脚本如下:
-- 抢券Lua实现
-- key: 抢券同步队列,资源库存,抢券成功列表
-- argv:活动id,用户id--优惠券是否已经抢过
local couponNum = redis.call("HGET", KEYS[3], ARGV[2])
-- hget 获取不到数据返回false而不是nil
if couponNum ~= false and tonumber(couponNum) >= 1
thenreturn "-1";
end
-- --库存是否充足校验
local stockNum = redis.call("HGET",KEYS[2], ARGV[1])
if stockNum == false or tonumber(stockNum) < 1
thenreturn "-2";
end
--抢券列表
local listNum = redis.call("HSET",KEYS[3], ARGV[2], 1)
if listNum == false or tonumber(listNum) < 1
thenreturn "-3";
end--减库存
stockNum = redis.call("HINCRBY",KEYS[2], ARGV[1], -1)
if tonumber(stockNum) < 0
thenreturn "-4"
end
-- 抢单结果写入同步队列
local result = redis.call("HSETNX", KEYS[1], ARGV[2],ARGV[1])
if result > 0
thenreturn ARGV[1] ..""
end
return "-5"
使用Lua注意点
Lua脚本在redis集群上执行需要注意什么?
在redis集群下执行redis命令会根据key求哈希,确定具体的槽位(slot),然后将命令路由到负责该槽位的 Redis 节点上。
执行一次Lua脚本会涉及到多个key,在redis集群下执行lua脚本要求多个key必须最终落到同一个节点,否则调用Lua脚本会报错:ERR eval/evalsha command keys must be in same slot。
如何保证多个key落地到一个redis节点呢?
只要保证多个key的哈希值一致即可保证多个key落到一个redis节点上,这个如何实现呢?
解决方法:一次执行Lua脚本的所有key中使用大括号‘{}’且保证大括号中的内容相同,此时会根据大括号中的内容求哈希,因为内容相同所以求得的哈希数据相同所以就落在了同一个Redis节点。
测试如下:
在key名称后边添加{},大括号中写一个固定的值。
@Test
public void test_Luafirst2() {//参数1:key ,key1:test_key01List<String> keys = Arrays.asList("test_key01{111}","test_key02{111}");//参数2:传入Lua脚本的参数,"field1","aa","field2", "bb"Object result = redisTemplate.execute(script, keys, "field1","aa","field2", "bb");log.info("执行结果:{}",result);
}
相关文章:
超卖问题解决方案
目录 需求概述 系统需求 提升高并发吞吐量 解决超卖问题 解决方案分析 悲观锁与乐观锁 悲观锁 乐观锁 数据库行级锁 实现悲观锁(排他锁) 实现乐观锁 悲观锁&乐观锁 Redis分布式锁 Redis原子操作方案 方案分析 技术实现 通过MULTI事务…...
智享AI直播代理:零门槛掘金新风口
智享AI直播代理:零门槛掘金新风口 传统直播困局,AI破局而生 在电商与内容创业井喷的今天,传统直播模式却陷入“三高”泥潭——人力成本高、内容门槛高、运营风险高。一位主播单日直播超8小时即面临状态下滑,而多平台运营更需…...
在huggingface上制作小demo
在huggingface上制作小demo 今天好兄弟让我帮他搞一个模型,他有小样本的化学数据,想让我根据这些数据训练一个小模型,他想用这个模型预测一些值 最终我简单训练了一个小模型,起初想把这个模型和GUI界面打包成exe发给他࿰…...
Spring、Spring Boot和 Spring Cloud 的关系
Spring、Spring Boot和 Spring Cloud 的关系 Spring, Spring Boot 和 Spring Cloud 都是 Spring 生态系统中的重要组成部分,它们之间有紧密的关系,但各自有不同的定位和功能。下面是它们之间的关系和区别: 1、Spring Framework:…...
[蓝桥杯] 求和(C语言)
题目链接 P8772 [蓝桥杯 2022 省 A] 求和 - 洛谷 题目理解 这道题就是公式题,我们模拟出公式后,输出最终结果即可。 本题不难,相信很多同学第一次见到这道题都是直接暴力解题。 两个for循环,测试样例,直接拿下。 #in…...
从用户需求到产品迭代:Scrum 实践全流程详解
目录 前言1. 用户需求与产品待办列表的形成1.1 用户需求的来源与整理1.2 构建产品待办列表(Product Backlog) 2. 迭代计划与目标设定2.1 Sprint 的时间周期设定2.2 设定明确的 Sprint 目标 3. 开发执行与每日站会3.1 高效协作的开发过程3.2 每日站会&…...
windows10安装配置并使用Miniconda3
windows10安装配置并使用Miniconda3 Conda 与 Anaconda 的区别 Conda 是包管理和环境管理工具,Anaconda 在 Conda 的 基础上预装了大量科学计算包 Conda 与 pip 的区别 Conda 是跨语言的包和环境管理器(支持 Python/R 等),能安…...
16-产品经理-需求的评审
在创建需求的时候,有一个"不需要评审"的复选框,如果选中该复选框的话,需求的创建成功后状态是激活的。 但大部分情况下面,需求还是需要评审的。 即使产品完全由一个人负责,也可以将一些不成熟的想法存为草…...
【java图形化界面编程】
文章目录 一、GUI简介二、Swing1.容器组件2. 布局管理器:BorderLayout3.代码实现 实验总结: 一、GUI简介 GUI:图形用户界面。通过图形用户界面,程序的输入输出可以脱离控制台JAVA中实现GUI主要使用3种技术:AMT&#x…...
BGP路由协议之属性1
公认属性是所有 BGP 路由器都必须能够识别的属性 公认必遵 (Well-known Mandatory) : 必须包括在每个 Update 消息里公认任意 (Well-known Discretionary) : 可能包括在某些 Update 消息里。 可选属性不需要都被 BGP 路由器所识别 可选过渡(OptionalTransitive) : BGP 设备不…...
架构思维: 数据一致性的两种场景深度解读
文章目录 Pre案例数据一致性问题的两种场景第一种场景:实时数据不一致不要紧,保证数据最终一致性就行第二种场景:必须保证实时一致性 最终一致性方案实时一致性方案TCC 模式Seata 中 AT 模式的自动回滚一阶段二阶段-回滚二阶段-提交 Pre 架构…...
压测工具开发实战篇(四)——client子窗口功能
你好,我是安然无虞。 文章目录 树控件添加文件补充学习: 函数定义中循环体里的局部变量补充学习: 动态添加对象属性 刷新文件上下文菜单 (右键菜单)实现右键菜单功能 编辑节点文本 在学习本篇文章之前, 建议先看一下上篇介绍MDI子窗口的文章: 压测工具开发实战篇(三…...
如何开发 HTML 游戏
开发 HTML 游戏适合初学者学习编程和游戏开发的基础知识。HTML 游戏通常结合了 HTML、CSS 和 JavaScript 技术,利用浏览器的渲染能力来实现交互式的游戏体验。 1. 确定游戏类型 在开始开发之前,你需要明确你的游戏类型。例如: 简单游戏&…...
机器学习 从入门到精通 day_01
1. 机器学习介绍与定义 1.1 机器学习定义 机器学习(Machine Learning)本质上就是让计算机自己在数据中学习规律,并根据所得到的规律对未来数据进行预测。 机器学习包括如聚类、分类、决策树、贝叶斯、神经网络、深度学习(…...
React中的跨组件通信
在React中,跨组件通信有几种常见的方式。每种方式适用于不同的场景,下面是几种常见的跨组件通信方法: 1. 通过父子组件传递 Props 父组件可以通过 props 将数据传递给子组件,子组件只能接收和使用这些数据。 父组件(…...
Vue项目 bug 解决
Vue2项目部署失败 从gitee 上拉下一个前端项目,然后npm install,报错如下: 解决办法: 从 npm切换到cnpm:npm install -g cnpm执行命令export NODE_OPTIONS--openssl-legacy-provider下载依赖:cnpm instal…...
Python 3.13.2 安装教程(附安装包)轻松开启编程之旅
文章目录 前言软件介绍安装步骤1. 下载安装包2. 运行安装程序3. 选择安装选项4. 等待安装完成5. 验证安装结果 前言 在数字化时代,Python 作为一种简洁、高效且功能强大的编程语言,广泛应用于 Web 开发、数据科学、人工智能等诸多领域。无论是编程新手入…...
Meta 最新发布的 Llama 4:多模态开源大模型全面解析
TL;DR 2025 年 4 月 5 日,Meta AI 正式发布了第四代大型语言模型 Llama 4。引入了 Mixture-of-Experts (MoE,专家混合) 架构,同时原生支持多模态输入,最小的 Llama 4 Scout 模型支持 10m 的长文本输入。 Paper name The Llama 4…...
Web开发:常用 HTML 表单标签介绍
在 Web 开发中,HTML 表单是实现用户交互的关键元素,它为用户提供了输入数据的途径,广泛应用于注册登录、搜索查询、问卷调查等功能场景。本文将详细介绍常用的 HTML 表单标签及其使用方法。 表单容器标签 <form> <form>标签用…...
力扣HOT100之链表:2. 两数相加
这道题就是按照正常的数学思维去做的,设置一个标志位flag用来标记进位的情况,当发生进位时设置为1,否则设置为0,初始时设置为0。我们同时遍历两个链表,将两个节点的值相加,再加上上一位的进位flagÿ…...
Spring Boot 项目集成 License 授权与续期完整指南
一、背景说明 在 Spring Boot 项目中,通过引入第三方 spring-boot-starter-license 组件,可以快速实现系统权限到期控制、License 证书管理等功能。本文详细介绍如何集成 License 功能,并解决证书安装、权限配置、异常拦截及续期流程等关键问…...
2010年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析
2010年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析 全国大学生数学建模竞赛(China Undergraduate Mathematical Contest in Modeling)是国家教委高教司和中国工业与应用数学学会共同主办的面向全国大学生的群众性科技活动,目的在于激…...
典型的ETL使用场景与数据集成平台的应用
在当今数字化时代,数据已经成为企业决策和运营的核心资产。为了更好地管理和利用数据,企业需要借助高效的数据处理技术。ETL(Extract,Transform,Load)作为数据处理的核心技术之一,广泛应用于数据…...
深入解析嵌入式Linux系统架构:从Bootloader到用户空间 - 结合B站视频教学
B站视频链接,请多多关注本人B站: 📌 Yocto项目实战教程:第二章 视频讲解 目录 第2章 Linux系统架构 2.1 GNU/Linux2.2 Bootloader2.3 内核空间2.4 用户空间 总结 第2章 Linux系统架构 {#linux系统架构} 嵌入式Linux系统是Linux内核的精简版…...
从Oracle和TiDB的HTAP说起
除了数据库行业其他技术群体很多不知道HTAP的 时至今日还是有很多人迷信Hadoop,觉得大数据就是Hadoop。这是不正确的。也难怪这样,很多人OLTP和OLAP也分不清,何况HTAP。 Oracle是垂直方向实现 TiDB是水平方向实现 我个人认为这是两种流派…...
【Vue-路由案例】面经基础版
目录 <<回到导览1.面经基础版1.1.VueCli建项目1.1.1.VueCli 自定义项目1.1.2.ESlint代码规范 1.2.项目路由1.2.1.一级路由配置1.2.2.二级配置路由1.2.3.设置高亮1.2.4.发生请求、渲染1.2.5.跳转传参、再发请求1.2.6.体验优化1.2.7.keep-alive <<回到导览 1.面经基…...
C#调用C++动态库时出现`System.DllNotFoundException`错误的解决思路
文章目录 1. DLL文件路径问题2. 依赖的运行时库缺失3. 平台不匹配(x86/x64)4. 导出函数名称不匹配5. DLL文件损坏或权限问题6. 运行时库冲突(MT/MD不匹配)7. 使用DLLImport时的常见错误总结步骤 在C#中调用C动态库时出现System.Dl…...
数据清洗
map阶段:按行读入内容,对内容进行检查,如果字段的个数少于等于11,就删除这条日志(不保留)去除日志中字段个数小于等于11的日志内容。 <偏移量,第一行的内容> → <通过刷选之后的第一行…...
ubuntu 20.04 编译和运行A-LOAM
1.搭建文件目录和clone代码 mkdir -p A-LOAM/src cd A-LOAM/src git clone https://github.com/HKUST-Aerial-Robotics/A-LOAM cd .. 2.修改代码文件 2.1 由于PCL版本1.10,将CMakeLists.txt中的C标准改为14: set(CMAKE_CXX_FLAGS "-stdc14"…...
Oracle迁移翻车,数据校验没做好...
作为DBA,你是否经历过这样的噩梦?数据库迁移、主从同步、容灾切换后,数据不一致却迟迟无法定位,只能手动写脚本逐表比对,熬到凌晨还在查差异… Oracle GoldenGate Veridata(OGG Veridata) 就是…...
小刚说C语言刷题——第17讲 循环之for语句
在生活中,我们经常会碰到重复去做某一件事。例如,一个人绕着操场跑圈,一天24小时往复。这些周而往复的事,我们称为循环。 1.循环的作用 在编程时,我们用循环的目的有两个。一个是减少循环时代码量,一个是通…...
如何使用 Coze 的 HTTP 请求节点实现高效数据交互
如何使用Coze的HTTP请求节点实现高效数据交互 在自动化工作流开发中,与外部服务进行数据交互是核心需求之一。Coze平台的HTTP请求节点提供了强大的解决方案,支持通过HTTP协议实现数据的获取、提交、更新和删除等操作。本文将结合官方文档,详…...
【力扣hot100题】(071)每日温度
经典单调栈问题。 感觉自己对这类问题还是不太熟练,想了很久思路,还想了很久是单调递增栈还是单调递减栈…… 方法是维护一个单调递减栈。先将结果result初始化为0,如果温度一直递减,那么result就不用变化了。 遍历每日温度&am…...
ChatBI的落地挑战——技术先进≠产品可用
近年来,大语言模型(LLM)的爆发让“对话式BI”(ChatBI)成为行业热点。然而,许多企业发现,尽管技术Demo令人惊艳,实际落地却困难重重——用户提问率低、回答准确度不稳定、使用场景模糊…...
1.2 测试设计阶段:打造高质量的测试用例
测试设计阶段:打造高质量的测试用例 摘要 本文详细介绍了软件测试流程中的测试设计阶段,包括测试用例设计、测试数据准备、测试环境搭建和测试方案设计等内容。通过本文,读者可以系统性地了解测试设计的方法和技巧,掌握如何高效…...
x64dbg调试python解释器
可以先写个input()这会让dbg中断在ntdll模块中,查看调用堆栈在系统调用结束后的打断点 然后直接断到PyObject_Vectorcall函数...
浙江大学DeepSeek系列专题线上公开课第二季第四期即将上线!端云协同:让AI更懂你的小心思! - 张圣宇 研究员
今晚8点10分左右,端云协同:让AI更懂你的小心思!浙大学者张圣宇研究员将揭秘人机交互新玩法。浙江大学DeepSeek系列专题线上公开课第二季第四期即将上线! 讲座 主题: 大小模型端云协同赋能人机交互 主讲人:…...
【项目管理】第3章 信息系统治理 --知识点整理
相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 (一)知识总览 对应:第1章-第5章 (二)知识笔记 三、信息系统治理 本文涉及信息系统治理与审计的核心知识。 1)…...
算法与数据结构线性表之栈和队列
Hello大家好! 很高兴与大家见面! 给生活添点快乐,开始今天的编程之路。 我的博客:<但愿. 我的专栏:C语言、题目精讲、算法与数据结构、C 欢迎点赞,关注 一 栈 1概念:栈是⼀种特殊的线性表,其只允许…...
【Introduction to Reinforcement Learning】翻译解读2
2.2 马尔可夫决策过程(MDPs) 马尔可夫决策过程(MDP)为顺序决策提供了框架,其中动作不仅影响即时奖励,还会影响未来结果。与多臂老虎机问题不同,MDP中的即时奖励与延迟奖励相平衡。在多臂老虎机…...
2016年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析
2016年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析 全国大学生数学建模竞赛(China Undergraduate Mathematical Contest in Modeling)是国家教委高教司和中国工业与应用数学学会共同主办的面向全国大学生的群众性科技活动,目的在于激励学生学习数学的积极性,提高学…...
UI测试(2)
1、HTML 是用来描述网页的一种语言。 指的是超文本标记语言 (Hyper Text Markup Language) ,HTML 不是一种编程语言,而是一种标记语言 (markup language) 负责定义页面呈现的内容:标签语言:<标签名>标签值<标签名>&am…...
Pr视频剪辑 Premiere Pro 2024 for Mac
Pr视频剪辑 Premiere Pro 2024 for Mac 文章目录 Pr视频剪辑 Premiere Pro 2024 for Mac一、介绍二、效果三、下载 一、介绍 Premiere Pro 2024 for Mac是一款专业的视频编辑软件,广泛应用于电影、电视、广告等领域。它为Mac用户提供了强大的剪辑、调色、音频处理等…...
电源测试系统自动化转型:Chroma 8000 与 NSAT-8000 核心功能对比解析
在全球制造业加速智能化升级的背景下,电源模块测试正从传统手动模式向自动化、智能化深度转型。作为企业降本增效与提升竞争力的关键,如何选择适配的测试系统成为行业焦点。本文聚焦市场主流的 Chroma 8000 与 NSAT-8000 两款系统,从功能设计…...
智能指针和STL库学习思维导图和练习
思维导图: #include <iostream> #include <vector> #include <string> using namespace std;// 用户结构体 struct User {string username;string password; };vector<User> users; // 存储所有注册用户// 使用迭代器查找用户名是否存在 ve…...
【JS】二分查找
题目 步骤 初始化指针:定义 left 和 right 两个指针,分别指向数组的起始位置和末尾位置,确定查找范围。进入循环:只要 left 小于等于 right,就继续执行循环,因为此时查找范围不为空。计算中间索引ÿ…...
Mamba模型
为什么要提出mamba模型? transformer特点:训练快,推理慢,计算成本O(n*n) Rnn的特点:训练慢,推理快,容易遗忘 其实很容易理解,因为RNN的输入只包含前一个隐…...
人工智能通识速览(Part4. 评估指标)
四、评估指标 1.回归模型 均方误差(MSE) 优点:数学性质良好,计算简单,对误差的惩罚力度较大,能很好地反映模型预测值与真实值之间的平均差异程度,便于比较不同模型的性能。缺点:由…...
IT运维服务方案
一、服务目标 IT 运维服务致力于构建稳固、高效且智能的信息系统生态,为客户的业务运营筑牢数字化根基。凭借前沿的主动式维护策略,运用大数据分析、智能监控等技术手段,提前洞察系统隐患,在萌芽阶段化解潜在故障。同时࿰…...
【简历全景认知2】电子化时代对简历形式的降维打击:从A4纸到ATS的生存游戏
一、当简历遇上数字洪流:传统形式的式微 在1990年代,一份排版精美的纸质简历还能让HR眼前一亮;但今天,超过75%的 Fortune 500 企业使用ATS(Applicant Tracking System)进行初筛,未优化的简历可能在5秒内就会沦为数字废土。这种变迁本质上符合「技术接纳生命周期」理论—…...