当前位置: 首页 > news >正文

UDP send 出现大量“Resource temporarily unavailable”

背景

        最近排查用户现场环境,查看日志出现大量的“send: Resource temporarily unavailable”错误,UDP设置NO_BLOCK模式,send又发生在进程上下文,并且还设置了SO_SNDBUF 为8M,在此情况下为什么还会出现发送队列满的情况,由此产生几个问题?

  • send 在什么情况下会报“Resource temporarily unavailable”错误?
  • send工作在进程上下文中,发送的SKB报文在什么时机进行释放?
  • /proc/net/softnet_stat 第三列数不停的再增加?
  • SO_SNDBUF的设置真的生效了么,netstat -napu 接收队列并没有达到阈值8M?
内核源码分析

  • send 在什么情况下会报“Resource temporarily unavailable”错误?

 我们跟踪kernel 源码,用户态调用系统调用send,内核跟踪路径

/* trace-cmd record -p function_graph -g __sys_sendto  */
__sys_sendto() {__sock_sendmsg() {inet_sendmsg() {udp_sendmsg() {/* 查找路由,经历了策略路由 */ip_route_output_flow() {ip_route_output_key_hash() {ip_route_output_key_hash_rcu() {__fib_lookup() {fib4_rule_match();fib4_rule_action() {fib_get_table();fib_table_lookup();}fib4_rule_suppress();}}}}}/* 生成skb 结构 */ip_make_skb() {__ip_append_data.isra.0() {sock_alloc_send_skb() {/* 这个函数特别分析 */sock_alloc_send_pskb() {alloc_skb_with_frags() {__alloc_skb() {skb_set_owner_w();}}}}}}udp_send_skb.isra.0() {ip_send_skb() {ip_local_out() {__ip_local_out() {/* 进入netfilter 框架 */nf_hook_slow() {ipv4_conntrack_local() {nf_conntrack_in() {}}}ip_output() {nf_hook_slow() {iptable_mangle_hook() {ipt_do_table() {}}nf_nat_ipv4_out() {nf_nat_ipv4_fn() {}}ipv4_confirm() {nf_confirm() {}}}/* IP 层处理完毕 */ip_finish_output() {__ip_finish_output() {ip_finish_output2() {dev_queue_xmit() {__dev_queue_xmit() {netdev_core_pick_tx() {netdev_pick_tx() {}}}_raw_spin_lock();sch_direct_xmit() {}/* 发送到网卡,这里使用的vmxnet3 虚拟网卡 */_raw_spin_lock();dev_hard_start_xmit() {vmxnet3_xmit_frame() {vmxnet3_tq_xmit.isra.0() {_raw_spin_lock_irqsave();vmxnet3_map_pkt.isra.0();_raw_spin_unlock_irqrestore();}}}}__qdisc_run() {}}}}}}}}}}}
}

 根据调用栈信息看到整个sendto,处于一个进程上下文中,经历了socket层,ip层,netfilter, qdisc, driver 层,我们特别注意到sock_alloc_send_pskb() 函数

struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,unsigned long data_len, int noblock,int *errcode, int max_page_order)
{struct sk_buff *skb;long timeo;int err;/* 这里我们设置的noblock, timeo=0 */timeo = sock_sndtimeo(sk, noblock);for (;;) {err = sock_error(sk);if (err != 0)goto failure;err = -EPIPE;if (sk->sk_shutdown & SEND_SHUTDOWN)goto failure;/*static inline int sk_wmem_alloc_get(const struct sock *sk){return refcount_read(&sk->sk_wmem_alloc) - 1;}sk->sk_wmem_alloc 和 sk->sk_sndbuf 进行对比,当大于时进行等待或者返回-EAGAIN, */if (sk_wmem_alloc_get(sk) < READ_ONCE(sk->sk_sndbuf))break;/* alloc wmem(write memory) 大于sk->sk_sndbuf,并且timeo 为0,返回-EAGIN*/ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);err = -EAGAIN;if (!timeo)goto failure;if (signal_pending(current))goto interrupted;timeo = sock_wait_for_wmem(sk, timeo);}skb = alloc_skb_with_frags(header_len, data_len, max_page_order,errcode, sk->sk_allocation);/*skb_set_owner_w() {skb->destructor = sock_wfree;/* 成功申请写内存后,增加sk_wmem_alloc 变量 */refcount_add(skb->truesize, &sk->sk_wmem_alloc);}*/if (skb)skb_set_owner_w(skb, sk);return skb;interrupted:err = sock_intr_errno(timeo);
failure:*errcode = err;return NULL;
}
void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
{/* 设置skb 为孤儿状态 */skb_orphan(skb);skb->sk = sk;
#ifdef CONFIG_INETif (unlikely(!sk_fullsock(sk))) {skb->destructor = sock_edemux;sock_hold(sk);return;}
#endif/* 注意这个回调函数,sock_wfree() 什么时机调用?*/skb->destructor = sock_wfree;skb_set_hash_from_sk(skb, sk);/** We used to take a refcount on sk, but following operation* is enough to guarantee sk_free() wont free this sock until* all in-flight packets are completed*//* 注释已经解释很清楚了,我们释放内存,直到报文处理完成 */refcount_add(skb->truesize, &sk->sk_wmem_alloc);
}
void sock_wfree(struct sk_buff *skb)
{struct sock *sk = skb->sk;unsigned int len = skb->truesize;if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) {/** Keep a reference on sk_wmem_alloc, this will be released* after sk_write_space() call*/WARN_ON(refcount_sub_and_test(len - 1, &sk->sk_wmem_alloc));sk->sk_write_space(sk);len = 1;}/** if sk_wmem_alloc reaches 0, we must finish what sk_free()* could not do because of in-flight packets*/if (refcount_sub_and_test(len, &sk->sk_wmem_alloc))__sk_free(sk);
}

 到这里我们可以看到,当我们申请sk_wmem_alloc大于我们设置的sk_sndbuf时,系统调用直接返回给我们-EAGAIN错误码,sk_wmem_alloc 什么时机增加和减少?整个发送的进程上下文暂未找到减少的流程,从代码可以看出,在什么时机调用sock_wfree(),就是更新sk_wmem_alloc。

  • send工作在进程上下文中,发送的SKB报文在什么时机进行释放?
# bpftrace -e 'kprobe:sock_wfree {printf ("%s\n", kstack());}'sock_wfree+1skb_release_all+19kfree_skb+50__dev_kfree_skb_any+59vmxnet3_tq_tx_complete+254vmxnet3_poll_rx_only+121net_rx_action+322__softirqentry_text_start+209irq_exit+174do_IRQ+90ret_from_intr+0native_safe_halt+14arch_cpu_idle+21default_idle_call+35do_idle+507cpu_startup_entry+32start_secondary+376secondary_startup_64+164

这里可以看到,在中断上下文中do_IRQ() 触发了软中net_rx_action(),调用了vmxnet3_poll_rx_only() 和 vmxnet3_tq_tx_complete() 中kfree_skb() 函数回调 sock_wfree(),其发送过skb后,并没有立刻释放skb,借用飞哥《理解了实现再谈性能》的一张图第6,7步骤。这部分内容书中有详细的介绍,可以详细看下此书。

 至此我们也可以理解为什么send() 时会报-EAGAIN,因为发送申请内存和释放内存是异步操作的,当CPU比较繁忙,send发送比回收快时,很快将sk_sndbuf 占满,会发生EAGAIN情况,这里需要注意 /proc/net/softnet_stat 文件的第三列 的数据变化。

  • /proc/net/softnet_stat 第三列数不停的再增加?
static __latent_entropy void net_rx_action(struct softirq_action *h)
{struct softnet_data *sd = this_cpu_ptr(&softnet_data);unsigned long time_limit = jiffies +usecs_to_jiffies(netdev_budget_usecs);int budget = netdev_budget;LIST_HEAD(list);LIST_HEAD(repoll);local_irq_disable();list_splice_init(&sd->poll_list, &list);local_irq_enable();for (;;) {struct napi_struct *n;if (list_empty(&list)) {if (!sd_has_rps_ipi_waiting(sd) && list_empty(&repoll))goto out;break;}n = list_first_entry(&list, struct napi_struct, poll_list);budget -= napi_poll(n, &repoll);/* If softirq window is exhausted then punt.* Allow this to run for 2 jiffies since which will allow* an average latency of 1.5/HZ.*//*这里影响单词softirq 处理报文个数有两个参数决定:netdev_budget 和 netdev_budget_usecs*/if (unlikely(budget <= 0 ||time_after_eq(jiffies, time_limit))) {/* percpu squeeze 对应 /proc/net/softnet_stat 第三列 */sd->time_squeeze++;break;}}local_irq_disable();list_splice_tail_init(&sd->poll_list, &list);list_splice_tail(&repoll, &list);list_splice(&list, &sd->poll_list);if (!list_empty(&sd->poll_list))__raise_softirq_irqoff(NET_RX_SOFTIRQ);net_rps_action_and_irq_enable(sd);
out:__kfree_skb_flush();
}

 第三列的变化是取值于time_squeeze变量,也就表明单次软中处理已经无法处理完,需要唤醒ksoftirqd 内核线程协助处理,此时未处理的软中断事务,比如释放skb将由内核线程ksoftirqd处理,这将延后到内核线程ksoftirqd 何时得到调度,在我们客户现场环境是关闭内核抢占的。

我们在看下处理软中断函数

asmlinkage __visible void do_softirq(void)
{__u32 pending;unsigned long flags;if (in_interrupt())return;local_irq_save(flags);pending = local_softirq_pending();/* 当 ksofirqd 已经启动的时候,我们不会再继续调用do_softirq,注释也能 明确说明*/if (pending && !ksoftirqd_running(pending))do_softirq_own_stack();local_irq_restore(flags);
}/** If ksoftirqd is scheduled, we do not want to process pending softirqs* right now. Let ksoftirqd handle this at its own rate, to get fairness,* unless we're doing some of the synchronous softirqs.*/
#define SOFTIRQ_NOW_MASK ((1 << HI_SOFTIRQ) | (1 << TASKLET_SOFTIRQ))
static bool ksoftirqd_running(unsigned long pending)
{struct task_struct *tsk = __this_cpu_read(ksoftirqd);if (pending & SOFTIRQ_NOW_MASK)return false;return tsk && (tsk->state == TASK_RUNNING) &&!__kthread_should_park(tsk);
}

看代码逻辑,当有新的软中断事件发生时,会检测ksoftirqd的运行情况,已经是运行状态时,不会调用do_softirq(),对应网卡软中断事件来说就是不处理发送后的SKB回收,由ksoftirqd 来处理,这样就加剧了SKB回收的工作,增加send 出现EAGAIN的可能性。

  • SO_SNDBUF的设置真的生效了么,netstat -napu 接收队列并没有达到阈值8M?

明明我们程序设置了8M的snd_buf,但是netstat -napu 确始终未发现超过8M的大小,这个需要从源码分析

int sock_setsockopt(struct socket *sock, int level, int optname,char __user *optval, unsigned int optlen)
{switch (optname) {case SO_SNDBUF:/* Don't error on this BSD doesn't and if you think* about it this is right. Otherwise apps have to* play 'guess the biggest size' games. RCVBUF/SNDBUF* are treated in BSD as hints*/val = min_t(u32, val, sysctl_wmem_max);
set_sndbuf:/* Ensure val * 2 fits into an int, to prevent max_t()* from treating it as a negative value.*/val = min_t(int, val, INT_MAX / 2);sk->sk_userlocks |= SOCK_SNDBUF_LOCK;WRITE_ONCE(sk->sk_sndbuf,max_t(int, val * 2, SOCK_MIN_SNDBUF));/* Wake up sending tasks if we upped the value. */sk->sk_write_space(sk);break;case SO_SNDBUFFORCE:if (!capable(CAP_NET_ADMIN)) {ret = -EPERM;break;}/* No negative values (to prevent underflow, as val will be* multiplied by 2).*/if (val < 0)val = 0;goto set_sndbuf;case SO_RCVBUF:/* Don't error on this BSD doesn't and if you think* about it this is right. Otherwise apps have to* play 'guess the biggest size' games. RCVBUF/SNDBUF* are treated in BSD as hints*/val = min_t(u32, val, sysctl_rmem_max);
set_rcvbuf:/* Ensure val * 2 fits into an int, to prevent max_t()* from treating it as a negative value.*/val = min_t(int, val, INT_MAX / 2);sk->sk_userlocks |= SOCK_RCVBUF_LOCK;/** We double it on the way in to account for* "struct sk_buff" etc. overhead.   Applications* assume that the SO_RCVBUF setting they make will* allow that much actual data to be received on that* socket.** Applications are unaware that "struct sk_buff" and* other overheads allocate from the receive buffer* during socket buffer allocation.** And after considering the possible alternatives,* returning the value we actually used in getsockopt* is the most desirable behavior.*/WRITE_ONCE(sk->sk_rcvbuf,max_t(int, val * 2, SOCK_MIN_RCVBUF));break;case SO_RCVBUFFORCE:if (!capable(CAP_NET_ADMIN)) {ret = -EPERM;break;}/* No negative values (to prevent underflow, as val will be* multiplied by 2).*/if (val < 0)val = 0;goto set_rcvbuf;
}

 从代码可以看出当我们使用SO_SNDBUF时候,会强制 min_t(u32, val, sysctl_wmem_max)取小,也就是上限为sysctl_wmem_max的大小,查看系统cat /proc/sys/net/core/wmem_max,最大为229376,也就是说我们应用层所有设置SO_SNDBUF都有这个问题,此时查看了man 手册有这段话

       SO_SNDBUF
              Sets  or  gets the maximum socket send buffer in bytes.  The kernel doubles this value
              (to allow space for bookkeeping overhead) when it is set using setsockopt(2), and this
              doubled  value  is  returned  by  getsockopt(2).   The  default  value  is  set by the
              /proc/sys/net/core/wmem_default file and the maximum  allowed  value  is  set  by  the
              /proc/sys/net/core/wmem_max  file.   The  minimum  (doubled)  value for this option is
              2048.

       SO_SNDBUFFORCE (since Linux 2.6.14)
              Using this socket option, a privileged (CAP_NET_ADMIN) process can  perform  the  same
              task as SO_SNDBUF, but the wmem_max limit can be overridden.

 这里已经给出了答案,当我们使用SO_SNDBUF时,会有wmem_max 的上限,如果我们想改变限制,就使用SO_SNDBUFFORCE强制更新写缓存区大小。

解决方案

之前的领导有句话,“发现问题,并解决问题”,根据上面分析为缓解send 出现EAGIN的情况,有以下优化方案

  1. 通过设置setsockopt 使用SO_SNDBUFFORCE类型,强制修改系统限制
  2. 适当增加 netdev_budget 和 netdev_budget_usecs 数值,增加单次软中断处理能力
  3. 优化应用软件,出现这种情况应用软件100%占用CPU,导致ksoftirqd 处理变慢
总结

至此,我们已经分析开头所说困惑,一个小小的“Resource temporarily unavailable”错误,背后蕴藏着太多技术细节,如果得过且过将来必成后患。

工作中遇到的每个小问题,背后都蕴藏着大量知识,只有平时多积累总结,才能游刃有余解决所面对的问题。

相关文章:

UDP send 出现大量“Resource temporarily unavailable”

背景 最近排查用户现场环境&#xff0c;查看日志出现大量的“send: Resource temporarily unavailable”错误&#xff0c;UDP设置NO_BLOCK模式&#xff0c;send又发生在进程上下文&#xff0c;并且还设置了SO_SNDBUF 为8M&#xff0c;在此情况下为什么还会出现发送队列满的情况…...

怎么拆解台式电脑风扇CPU风扇的拆卸步骤-怎么挑

今天我就跟大家分享一下如何选购电脑风扇的知识。 我也会解释一下机箱散热风扇一般用多少转。 如果它恰好解决了您现在面临的问题&#xff0c;请不要忘记关注本站并立即开始&#xff01; 文章目录列表&#xff1a;大家一般机箱散热风扇都用多少转&#xff1f; 机箱散热风扇选择…...

Windows安装Odoo结合内网穿透实现公网访问本地企业管理系统

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…...

Portainer的替代Dockge?又一个Docker Compose管理器?

Dockge&#xff1a;让Docker Compose管理触手可及&#xff0c;一图胜千言&#xff0c;轻松构建与管控您的容器服务栈&#xff01;- 精选真开源&#xff0c;释放新价值。 概览 Docker&#xff0c;这一开放源代码的创新平台&#xff0c;旨在实现应用程序部署、扩展与运维的自动化…...

Midjourney AI绘图工具介绍及使用

介绍 Midjourney是一款目前被誉为最强的AI绘图工具。只要输入想到的文字&#xff0c;就能通过人工智能产出相对应的图片。 官网只是宣传和登录入口&#xff0c;提供个人主页、订阅管理等功能&#xff0c;Midjourney实际的绘画功能&#xff0c;是在另外一个叫discord的产品中实…...

clang-query 的编译安装与使用示例

1&#xff0c;clang query 概述 作用&#xff1a; 检查一个程序源码的抽象语法树&#xff0c;测试 AST 匹配器&#xff1b; 帮助检查哪些 AST 节点与指定的 AST 匹配器相匹配&#xff1b; 2&#xff0c;clang-query 安装 准备&#xff1a; git clone --recursive https://git…...

echarts数据下钻如何配置

官方范例&#xff1a;https://echarts.apache.org/examples/zh/editor.html?cbar-multi-drilldown 看了一眼范例直接晕了&#xff0c;你这&#xff0c;一堆数据直接写死&#xff0c;这怎么用啊&#xff01; 一般来说&#xff0c;实现步骤是&#xff1a; 1&#xff09;后台&a…...

git 提交空目录

git 提交空目录 1. git 无法感应空目录2. git 提交空目录References 1. git 无法感应空目录 Git FAQ https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html Currently the design of the Git index (staging area) only permits files to be liste…...

【优化方案】Java 将字符串中的星号替换为0-9中的数字,并返回所有可能的替换结果

需求 将输入的字符串中的星号替换为0-9中的数字&#xff0c;并返回所有可能的替换结果&#xff0c;允许存在多个*号。 分析&#xff1a; 在每个星号位置&#xff0c;我们需要进行 0-9 的循环遍历&#xff0c;因此每个星号位置都有 10 种可能性。如果字符数组中有k个星号&#x…...

C语言复习-链表

链表: 特点: 通过 next 指针 把内存上不连续 的几段数据 联系起来 set nu -- 打印行号 概念: 一种数据结构 -- 数据存放的思想 比如 -- 数组 -- 内存连续的一段空间&#xff0c;存放相同类型的一堆数据 缺点 -- 增删元素很 难 -- 不灵活 --> 引入链表 next指针的初步认识…...

Redis面试题-缓存雪崩、缓存穿透、缓存击穿问题

1 穿透: 两边都不存在&#xff08;皇帝的新装&#xff09; &#xff08;黑名单&#xff09; &#xff08;布隆过滤器&#xff09; 2 击穿&#xff1a;一个热点的key失效了&#xff0c;这时大量的并发请求直接到达数据库. &#xff08;提前预热&#xff09; 3 雪崩&#xff1a…...

【Node.js】npx

概述 npx 可以使用户在不安装全局包的情况下&#xff0c;运行已安装在本地项目中的包或者远程仓库中的包。 高版本npm会自带npx命令。 它可以直接运行 node_modules/.bin 下的 exe 可执行文件。而不像之前&#xff0c;我们需要在 scripts 里面配置&#xff0c;然后 npm run …...

hive授予指定用户特定权限及beeline使用

背景&#xff1a;因业务需要&#xff0c;需要使用beeline对hive数据进行查询&#xff0c;但是又不希望该用户可以查询所有的数据&#xff0c;希望有一个新用户bb给他指定的库表权限。 解决方案&#xff1a; 1.赋权语句&#xff0c;使用hive管理员用户在终端输入hive进入命令控…...

Vmware虚拟机无法用root直连说明

Vmware虚拟机无法用root直连说明 背景目的SSH服务介绍无法连接检查配置 背景 今天在VM上新装了一套Centos-stream-9系统&#xff0c;网络适配器的连接方式采用的是桥接&#xff0c;安装好虚拟机后&#xff0c;在本地用ssh工具进行远程连接&#xff0c;ip、用户、密码均是成功的…...

Visio中存在问题的解决方法

公式缩放 mathtype公式在visio缩放之后&#xff0c;出现了变形。 解决方法&#xff1a;每次输入公式都通过 插入->对象->mathType Equation 新建一个公式。可以避免 注&#xff1a;网上有的说在word中使用mathtype编写公式&#xff0c;之后复制到visio中。 插入波形 选择…...

taro之Swiper的使用

图样&#xff1a; 往往我们需要轮播图去显示我们想要的图片之类的 这是工作的代码 <View classNametop-title><SwiperclassNamebanner-swiperinterval{3000}circularautoplay>{homeBannerList.map((item) > {return (<SwiperItem key{item.id}><View…...

正大国际:金融行业发展趋势

2024金融科技趋势研究报告 大模型生态揭秘!金融行业迎来变革&#xff0c;中控成生态核心&#xff0c;大模型在金融行业的应用 随着大模型的不断发展&#xff0c;越来越多的金融机构开始尝试在一些业务场景中引入大模型和生成式A能力&#xff0c;预计2024年&#xff0c;领先的金…...

vue中实现超出一行 展开和收起的功能

html中: <divclass="txttype"ref="txttype"style="margin-bottom: 6px":class="hidetext == true ? hidetext : "><div style="width: 96%"><el-tagtype="info"style="margin-right: 10px&…...

记录一次使用cert-manager-颁发CA证书

一、官网 SelfSigned - cert-manager Documentation 二、例子 apiVersion: v1 kind: Namespace metadata:name: sandbox --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata:name: selfsigned-issuer spec:selfSigned: {} --- apiVersion: cert-manager.io/v…...

生成式AI的风险与挑战

生成式AI&#xff0c;即通过训练数据生成新的文本、图像或音频等内容的人工智能技术&#xff0c;具有很多潜在的风险与挑战。 1. 信息可信度&#xff1a;生成式AI往往是基于大量训练数据&#xff0c;但这些数据可能存在偏见、错误或虚假信息。生成的内容可能会引入不准确或误导…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...