秒杀抢购思路以及高并发下数据安全

2023-11-18



转载地址:https://my.oschina.net/wangjie404/blog/815455

我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万次的高并发场景,这个指标非常关键。举个例子,我们假设处理一个业务请求平均响应时间为100ms,同时,系统内有20台Apache的Web服务器,配置MaxClients为500个(表示Apache的最大连接数目)。

那么,我们的Web系统的理论峰值QPS为(理想化的计算方式):

20*500/0.1 = 100000 (10万QPS)

咦?我们的系统似乎很强大,1秒钟可以处理完10万的请求,5w/s的秒杀似乎是“纸老虎”哈。实际情况,当然没有这么理想。在高并发的实际场景下,机器都处于高负载的状态,在这个时候平均响应时间会被大大增加。

就Web服务器而言,Apache打开了越多的连接进程,CPU需要处理的上下文切换也越多,额外增加了CPU的消耗,然后就直接导致平均响应时间增加。因此上述的MaxClient数目,要根据CPU、内存等硬件因素综合考虑,绝对不是越多越好。可以通过Apache自带的abench来测试一下,取一个合适的值。然后,我们选择内存操作级别的存储的Redis,在高并发的状态下,存储的响应时间至关重要。网络带宽虽然也是一个因素,不过,这种请求数据包一般比较小,一般很少成为请求的瓶颈。负载均衡成为系统瓶颈的情况比较少,在这里不做讨论哈。

那么问题来了,假设我们的系统,在5w/s的高并发状态下,平均响应时间从100ms变为250ms(实际情况,甚至更多):

20*500/0.25 = 40000 (4万QPS)

于是,我们的系统剩下了4w的QPS,面对5w每秒的请求,中间相差了1w。

举个例子,高速路口,1秒钟来5部车,每秒通过5部车,高速路口运作正常。突然,这个路口1秒钟只能通过4部车,车流量仍然依旧,结果必定出现大塞车。(5条车道忽然变成4条车道的感觉)

同理,某一个秒内,20*500个可用连接进程都在满负荷工作中,却仍然有1万个新来请求,没有连接进程可用,系统陷入到异常状态也是预期之内。

 

其实在正常的非高并发的业务场景中,也有类似的情况出现,某个业务请求接口出现问题,响应时间极慢,将整个Web请求响应时间拉得很长,逐渐将Web服务器的可用连接数占满,其他正常的业务请求,无连接进程可用。

更可怕的问题是,是用户的行为特点,系统越是不可用,用户的点击越频繁,恶性循环最终导致“雪崩”(其中一台Web机器挂了,导致流量分散到其他正常工作的机器上,再导致正常的机器也挂,然后恶性循环),将整个Web系统拖垮。

3. 重启与过载保护

如果系统发生“雪崩”,贸然重启服务,是无法解决问题的。最常见的现象是,启动起来后,立刻挂掉。这个时候,最好在入口层将流量拒绝,然后再将重启。如果是redis/memcache这种服务也挂了,重启的时候需要注意“预热”,并且很可能需要比较长的时间。

秒杀和抢购的场景,流量往往是超乎我们系统的准备和想象的。这个时候,过载保护是必要的。如果检测到系统满负载状态,拒绝请求也是一种保护措施。在前端设置过滤是最简单的方式,但是,这种做法是被用户“千夫所指”的行为。更合适一点的是,将过载保护设置在CGI入口层,快速将客户的直接请求返回

高并发下的数据安全

我们知道在多线程写入同一个文件的时候,会存现“线程安全”的问题(多个线程同时运行同一段代码,如果每次运行结果和单线程运行的结果是一样的,结果和预期相同,就是线程安全的)。如果是MySQL数据库,可以使用它自带的锁机制很好的解决问题,但是,在大规模并发的场景中,是不推荐使用MySQL的。秒杀和抢购的场景中,还有另外一个问题,就是“超发”,如果在这方面控制不慎,会产生发送过多的情况。我们也曾经听说过,某些电商搞抢购活动,买家成功拍下后,商家却不承认订单有效,拒绝发货。这里的问题,也许并不一定是商家奸诈,而是系统技术层面存在超发风险导致的。

1. 超发的原因

假设某个抢购场景中,我们一共只有100个商品,在最后一刻,我们已经消耗了99个商品,仅剩最后一个。这个时候,系统发来多个并发请求,这批请求读取到的商品余量都是99个,然后都通过了这一个余量判断,最终导致超发。(同文章前面说的场景)

 

在上面的这个图中,就导致了并发用户B也“抢购成功”,多让一个人获得了商品。这种场景,在高并发的情况下非常容易出现。

优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false

<?php
//优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false
include('./mysql.php');
$username = 'wang'.rand(0,1000);
//生成唯一订单
function build_order_no(){
  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0,$username){
    global $conn;
    $sql="insert into ih_log(event,type,usernma)
    values('$event','$type','$username')";
    return mysqli_query($conn,$sql);
}
function insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number)
{
      global $conn;
      $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price,username,number)
      values('$order_sn','$user_id','$goods_id','$sku_id','$price','$username','$number')";
     return  mysqli_query($conn,$sql);
}
//模拟下单操作
//库存是否大于0
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' ";
$rs=mysqli_query($conn,$sql);
$row = $rs->fetch_assoc();
  if($row['number']>0){//高并发下会导致超卖
      if($row['number']<$number){
        return insertLog('库存不够',3,$username);
      }
      $order_sn=build_order_no();
      //库存减少
      $sql="update ih_store set number=number-{$number} where sku_id='$sku_id' and number>0";
      $store_rs=mysqli_query($conn,$sql);
      if($store_rs){
          //生成订单
          insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number);
          insertLog('库存减少成功',1,$username);
      }else{
          insertLog('库存减少失败',2,$username);
      }
  }else{
      insertLog('库存不够',3,$username);
  }


?>

2. 悲观锁思路

解决线程安全的思路很多,可以从“悲观锁”的方向开始讨论。

悲观锁,也就是在修改数据的时候,采用锁定状态,排斥外部请求的修改。遇到加锁的状态,就必须等待。

 

虽然上述的方案的确解决了线程安全的问题,但是,别忘记,我们的场景是“高并发”。也就是说,会很多这样的修改请求,每个请求都需要等待“锁”,某些线程可能永远都没有机会抢到这个“锁”,这种请求就会死在那里。同时,这种请求会很多,瞬间增大系统的平均响应时间,结果是可用连接数被耗尽,系统陷入异常。

优化方案2:使用MySQL的事务,锁住操作的行

<?php
//优化方案2:使用MySQL的事务,锁住操作的行
include('./mysql.php');
//生成唯一订单号
function build_order_no(){
  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0){
    global $conn;
    $sql="insert into ih_log(event,type)
    values('$event','$type')";
    mysqli_query($conn,$sql);
}

//模拟下单操作
//库存是否大于0
mysqli_query($conn,"BEGIN");  //开始事务
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE";//此时这条记录被锁住,其它事务必须等待此次事务提交后才能执行
$rs=mysqli_query($conn,$sql);
$row=$rs->fetch_assoc();
if($row['number']>0){
    //生成订单
    $order_sn=build_order_no();
    $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
    values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
    $order_rs=mysqli_query($conn,$sql);
    //库存减少
    $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
    $store_rs=mysqli_query($conn,$sql);
    if($store_rs){
      echo '库存减少成功';
        insertLog('库存减少成功');
        mysqli_query($conn,"COMMIT");//事务提交即解锁
    }else{
      echo '库存减少失败';
        insertLog('库存减少失败');
    }
}else{
  echo '库存不够';
    insertLog('库存不够');
    mysqli_query($conn,"ROLLBACK");
}
?>

3. FIFO队列思路

那好,那么我们稍微修改一下上面的场景,我们直接将请求放入队列中的,采用FIFO(First Input First Output,先进先出),这样的话,我们就不会导致某些请求永远获取不到锁。看到这里,是不是有点强行将多线程变成单线程的感觉哈。

 

然后,我们现在解决了锁的问题,全部请求采用“先进先出”的队列方式来处理。那么新的问题来了,高并发的场景下,因为请求很多,很可能一瞬间将队列内存“撑爆”,然后系统又陷入到了异常状态。或者设计一个极大的内存队列,也是一种方案,但是,系统处理完一个队列内请求的速度根本无法和疯狂涌入队列中的数目相比。也就是说,队列内的请求会越积累越多,最终Web系统平均响应时候还是会大幅下降,系统还是陷入异常。

4. 文件锁的思路

对于日IP不高或者说并发数不是很大的应用,一般不用考虑这些!用一般的文件操作方法完全没有问题。但如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进一文件进行操作,如果这时不对文件的访问进行相应的独占,就容易造成数据丢失

优化方案4:使用非阻塞的文件排他锁

<?php
//优化方案4:使用非阻塞的文件排他锁
include ('./mysql.php');
//生成唯一订单号
function build_order_no(){
  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0){
    global $conn;
    $sql="insert into ih_log(event,type)
    values('$event','$type')";
    mysqli_query($conn,$sql);
}


$fp = fopen("lock.txt", "w+");
if(!flock($fp,LOCK_EX | LOCK_NB)){
    echo "系统繁忙,请稍后再试";
    return;
}
//下单
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";
$rs =  mysqli_query($conn,$sql);
$row = $rs->fetch_assoc();
if($row['number']>0){//库存是否大于0
    //模拟下单操作
    $order_sn=build_order_no();
    $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
    values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
    $order_rs =  mysqli_query($conn,$sql);
    //库存减少
    $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
    $store_rs =  mysqli_query($conn,$sql);
    if($store_rs){
      echo '库存减少成功';
        insertLog('库存减少成功');
        flock($fp,LOCK_UN);//释放锁
    }else{
      echo '库存减少失败';
        insertLog('库存减少失败');
    }
}else{
  echo '库存不够';
    insertLog('库存不够');
}
fclose($fp);


 ?>

 

5. 乐观锁思路

这个时候,我们就可以讨论一下“乐观锁”的思路了。乐观锁,是相对于“悲观锁”采用更为宽松的加锁机制,大都是采用带版本号(Version)更新。实现就是,这个数据所有请求都有资格去修改,但会获得一个该数据的版本号,只有版本号符合的才能更新成功,其他的返回抢购失败。这样的话,我们就不需要考虑队列的问题,不过,它会增大CPU的计算开销。但是,综合来说,这是一个比较好的解决方案。

 

有很多软件和服务都“乐观锁”功能的支持,例如Redis中的watch就是其中之一。通过这个实现,我们保证了数据的安全。

优化方案5:Redis中的watch

<?php

$redis = new redis();
 $result = $redis->connect('127.0.0.1', 6379);
 echo $mywatchkey = $redis->get("mywatchkey");

/*
  //插入抢购数据
 if($mywatchkey>0)
 {
     $redis->watch("mywatchkey");
  //启动一个新的事务。
    $redis->multi();
   $redis->set("mywatchkey",$mywatchkey-1);
   $result = $redis->exec();
   if($result) {
      $redis->hSet("watchkeylist","user_".mt_rand(1,99999),time());
      $watchkeylist = $redis->hGetAll("watchkeylist");
        echo "抢购成功!<br/>"; 
        $re = $mywatchkey - 1;   
        echo "剩余数量:".$re."<br/>";
        echo "用户列表:<pre>";
        print_r($watchkeylist);
   }else{
      echo "手气不好,再抢购!";exit;
   }  
 }else{
     // $redis->hSet("watchkeylist","user_".mt_rand(1,99999),"12");
     //  $watchkeylist = $redis->hGetAll("watchkeylist");
        echo "fail!<br/>";    
        echo ".no result<br/>";
        echo "用户列表:<pre>";
      //  var_dump($watchkeylist);  
 }*/


$rob_total = 100;   //抢购数量
if($mywatchkey<=$rob_total){
    $redis->watch("mywatchkey");
    $redis->multi(); //在当前连接上启动一个新的事务。
    //插入抢购数据
    $redis->set("mywatchkey",$mywatchkey+1);
    $rob_result = $redis->exec();
    if($rob_result){
         $redis->hSet("watchkeylist","user_".mt_rand(1, 9999),$mywatchkey);
        $mywatchlist = $redis->hGetAll("watchkeylist");
        echo "抢购成功!<br/>";
     
        echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>";
        echo "用户列表:<pre>";
        var_dump($mywatchlist);
    }else{
          $redis->hSet("watchkeylist","user_".mt_rand(1, 9999),'meiqiangdao');
        echo "手气不好,再抢购!";exit;
    }
}
?>

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

秒杀抢购思路以及高并发下数据安全 的相关文章

  • 深度神经网络在NLP的应用!

    关注后 星标 Datawhale 每日干货 每月组队学习 不错过 Datawhale干货 作者 张泽 华东师范大学 Datawhale优秀学习者 深度学习正在给自然语言处理带来巨大的变革 例如机器翻译 情感分析 问答系统等落地实践 深度学习
  • RT-Thread之线程的诞生与消亡史

    1 引言 本文基于Cotex M内核处理器分析讨论RT Thread中线程从创建到消亡的整个详细过程 线程的载体 控制块 RT Thread中是用线程控制块来描述线程实体的 在 RT Thread 中 线程控制块由结构体 struct rt
  • 数字化信道

    数字化信道 数字化信道主要包括多相滤波和DFT两个模块 多相滤波 多相滤波 就是将滤波器系数按照相数进行重排 在D倍抽取后 整个频带的频谱将混叠在0频附近 F s
  • 二分查找的总结

    一 二分查找 1 思路分析 这道题目的前提是数组为有序数组 同时题目还强调数组中无重复元素 因为一旦有重复元素 使用二分查找法返回的元素下标可能不是唯一的 这些都是使用二分法的前提条件 当大家看到题目描述满足如上条件的时候 可要想一想是不是
  • 2022第十三届蓝桥杯国赛真题javaB组

    文章目录 试题A 重合次数 试题B 数数 试题C 左移右移 试题D 窗口 试题E 迷宫 试题F 小球称重 试题G 背包与魔法 试题H 修路 试题I 围栏 试题J 好数之和 试题A 重合次数 本题总分 5 分 问题描述 在同一天中 从上午6
  • eclipse debug进入.class_Eclipse的安装与使用

    相信大家在用记事本编译运行java程序的同时肯定心里有不少怨言吧 要是用这种工具编译一个复杂点的程序简直就有想死的心了 更不用说什么大的网站项目了 接下来阿Q就带领大家了解一个全新的编译工具Eclipse Eclipse的安装 首先进入ec
  • JS字符串转数字

    目录 parseInt parseFloat Number JavaScript中有三种方法可以将字符串转换为数字 parseInt parseInt 函数可以将字符串转换成整数 它会忽略字符串的开头空格 并读取尽可能多的数字字符 直到遇到
  • 2.4.5 Profile CPU参数

    最后更新2021 07 19 CPU的状态 参数表现出来的是分区的状态和参数 Power 6 7小型机 分区有3种模式 Shared Dedicated Shared dedicated partition Dedicated分区同时选择了
  • 求职笔记-操作系统-动态链接库、静态链接库区别

    dll什么意思 动态链接库 存放的是各类程序的函数实现过程 当程序需要调用函数时 需要先载入DLL 然后取得函数的地址 最后进行调用 使用DLL文件的好处是程序不需要在运行之初加载所有代码 只有在程序需要某个函数的时候才从DLL中取出 还可
  • linux防火墙 ( cent7.*)常用操作:

    cent7 防火墙操作 注意开通或关闭端口后 一定要重启防火墙服务 重装防火墙 不然无法生效 1 查看 系统防火墙是否开启 firewall cmd state 2 开启 关闭 重启访火墙 永久关闭防火墙 必须先临时关闭防火墙 再执行该命令
  • Mac终端如何查找具体文件的详细路径

    find 命令 find iname test Boston CSV csv
  • 毕业设计-基于计算机图像识别的垃圾智能分类系统

    目录 前言 课题背景和意义 实现技术思路 一 YOLOv3 算法 二 基于 Tensorflow2 的 YOLOv3 算法垃圾识别 三 总结 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业
  • win10远程桌面连接提示身份验证错误,要求的函数不受支持的解决方案

    报错信息 出现问题的原因是微软最近发布的更新补丁 要求服务器端和用户端都更新后才可以连接 最简单粗暴地方式就是卸载自己电脑的更新 而下面的这种方法需要修改注册列表 解决方案 1 WIN R 然后运行 regedit 命令 2 找到路径 HK
  • MySQL——无法打开MySQL8.0软件安装包或者安装过程中失败,如何解决?

    在运行MySQL8 0软件安装包之前 用户需要确保系统中已经安装了 Net Framework相关软件 如果缺少此软件 将不能正常地安装MySQL8 0软件 解决方案 到这个地址 https www microsoft com en us
  • 51 单片机占用 RAM 分析

    51 单片机占用 RAM 分析 简介 很久不用 51 单片机了 再拿起 51 的东西 发现之前学的时候遗漏很多细节 比如 RAM 的占用情况 都哪些会占用 RAM 空间 当时学习的时候从来没有注意过 包括用上 32 位的 MCU 之后也不怎
  • 学习SVG(八)文本

    简介 在SVG中除了绘图外 还可以添加文本 需要使用
  • 直播预告

    点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入 6月9日晚7 30 9 00 AI TIME特别邀请了三位优秀的讲者跟大家共同开启ICLR专场六 哔哩哔哩直播通道 扫码关注AITIME哔哩哔哩官方账号 观看直播 链接 http
  • 前沿探索|关于 AIGC 的「幻觉/梦游」问题

    AI语言模型的梦游是指模型产生内容与真实世界不符或者是毫无意义的情况 这种情况主要是由于语言模型缺乏真实世界的知识和语言的含义 导致模型难以理解和表达现实世界的概念和信息 这种情况在现代自然语言处理中普遍存在 尤其是在开放式生成领域的问题中
  • 分享一个可以下载全球geojson经纬度信息的网址

    https gadm org download country html
  • MySQL数据库语言一、DDL

    作者简介 正在努力的99年打工人 宣言 人生就是B birth 和D death 之间的C choise 做好每一个选择 创作不易 动动小手给个点赞加关注吧 有什么意见评论区告诉我 一起学习 目录 前言 什么是数据库 DDL语句 创建库 创

随机推荐

  • Python获取微信好友地址以及性别并生成可视化图表

    简介 使用python批量获取微信好友地址 需要使用itchat库 这个库是用的网页版微信的接口进行数据获取的 所以你想测试这个功能必须要你的微信能够登录网页版微信 之前的itchat uos模块使用了统信版的接口绕过了腾讯的检测 所有的微
  • Python opencv学习-8寻找轮廓、绘制轮廓

    import numpy as np import cv2 im cv2 imread image canny png 寻找轮廓前要对其进行灰度化 二值化处理 也可使用canny进行边缘检测 imgray cv2 cvtColor im c
  • 大厂真实Java面试题合集附答案(腾讯、阿里、字节跳动、百度、美团)

    这些面试题都是互联网大厂真实流出的面试内容 每个问题都附带完整详细的答案 不像网上的那些资料三教九流有的甚至还没答案 这些面试题我也是经过日积月累才整理出来的精品资料 这些面试题主要是针对1 5年左右的Java开发程序员提升的 不管是传统行
  • 实时音频编解码之五 噪声整形

    本文谢绝任何形式转载 谢谢 1 4 5 噪声整形 因压缩比特率而带来的量化误差会导致规律的噪声产生 即使量化带来的噪声能量上远小于语音信号 但是由于人的听觉系统对规律性的噪声非常敏感 因而非常影响听觉体验 噪声整形的目的是增加量化后解码信号
  • Python报错 AttributeError: ‘NoneType‘ object has no attribute ‘split

    Python报错 AttributeError NoneType object has no attribute split 源程序 raw line None dstID if line n pid ls append ID title
  • typora的images怎么设置相对路径

    我的软件安装在D Typora 分别有D Typora FilesSave和D Typora images 分别用来保存 md文件和用到的图片 首先preferences image启用copy image to custom folder
  • C++设计模式之抽象工厂模式

    之前讲到了C 设计模式 工厂方法模式 我们可能会想到 后期产品会越来越多了 建立的工厂也会越来越多 工厂进行了增长 工厂变的凌乱而难于管理 而且由于工厂方法模式创建的对象都是继承于Product的 所以工厂方法模式中 每个工厂只能创建同一产
  • 太好用了!Linux 服务器上必备的 4 个开源工具

    关注后回复 进群 拉你进程序员交流群 来自 开源最前线 今天和大家分享 4 个可以在 Linux 上运行的开源服务器 1 Samba Samba 是种自由软件 用来让 UNIX 系列的操作系统与微软 Windows 操作系统的 SMB CI
  • 响应式布局之REM

    REM是实现响应式布局的方案之一 除了REM之外 还有VM REM VM 今天主要来记录一下REM的实操 一 安装插件 npm install lib flexible npm install postcss plugin px2rem D
  • 第36章_瑞萨MCU零基础入门系列教程之步进电机控制实验

    本教程基于韦东山百问网出的 DShanMCU RA6M5开发板 进行编写 需要的同学可以在这里获取 https item taobao com item htm id 728461040949 配套资料获取 https renesas do
  • 史上最详细的快速排序算法

    史上最详细的快速排序算法 最近学了快速排序算法 在csdn上找了很多篇博客 虽然代码可以执行正确 但是解释却有点 官方 有很多细节 很多需要注意的地方并没有写到 故此 我写了这篇博客 看了我这篇博客 你绝对会恍然大悟 先给大家看看清楚明了的
  • 谁说不同品牌内存无法兼容-关键调整频率和内存时序

    高手绕道 菜鸟文 当时2018年买了两根光威DDR4 8G 3000的灯条 2019年手欠又买了两根威刚DDR4 8G 3000的黄金马甲条 两组内存条都是京东上买的 当时买完两组之后插上就看看电影 跑跑虚拟机看看网页没发现啥问题 结果过了
  • 力扣题---二叉树前、中、后序遍历

    二叉树前序遍历 我们先来了解题目 输入 root 1 null 2 3 输出 1 2 3 示例 2 输入 root 输出 示例 3 输入 root 1 输出 1 从示例不难看出 题目给定树的根结点 用前序遍历的方式 把二叉树的值放入数组中
  • 言情小说通用情节[转]

    第一部分 典型开篇 一 好美好神秘的人哦 一件惊艳加钟情 眼珠掉地上滚三圈 于是非君莫娶 嫁 死缠烂打 看欧的牛皮糖超级粘人功 二 你由于某些原因 比如漂亮可爱的外表 突如其来的爆炸 或者地上一块可怜的香蕉皮 而陷入危机的时候 那勇敢的 阿
  • Java操作Excel文件

    创建一个Excel文件 public static void creatExcelFile String filepath Workbook wb new XSSFWorkbook try FileOutputStream fileOut
  • Telink BLE MESH开发

    一 前言 官网资料介绍建议采用DMA传输 串口数据的接收是放到了fifo中 但是串口发送也是采用的DMA 问题在于串口发送并没有建立缓冲器 而是判断当前DMA是否忙 如果忙数据直接丢弃 这样做显然不合理 如果发送时DMA忙应该将数据放到缓冲
  • vscode连接远程Linux服务器失败

    vscode连接远程Linux服务器失败 文章目录 vscode连接远程Linux服务器失败 解决连接失败 设置密钥免密登录 解决连接失败 问题 vscode会不断的提示你去输入密码 然后一直retry 还是失败 但是使用其它远程连接工具比
  • IMX6ULL_Pro开发板基本操作(韦东山学习笔记)

    NAT网卡 桥接网卡 配置桥接网卡 驱动 为什么编译驱动程序之前要先编译内核 1 配置编译 内核 设备树 其他驱动程序 2 放到板子上 3 编译 测试第1个驱动 IMX6ULL Pro烧写系统
  • 公司重用我独立负责一个核心系统,我该怎么设计系统的高可用架构?

    V xin ruyuanhadeng获得600 页原创精品文章汇总PDF 目录 业务场景引入 业务系统消息同步丢失 计费业务系统的计费问题 计费业务数据补偿系统设计 背景 今天给大家分享一个话题 就是对于线上跟钱有关的计费类的系统 在线上可
  • 秒杀抢购思路以及高并发下数据安全

    转载地址 https my oschina net wangjie404 blog 815455 我们通常衡量一个Web系统的吞吐率的指标是QPS Query Per Second 每秒处理请求数 解决每秒数万次的高并发场景 这个指标非常关