关于本博

关于本博

find me on twitter: @plantegg

知识星球:https://t.zsxq.com/0cSFEUh2J

Github: 欢迎star

关注基础知识,一次把问题搞清楚,从案例出发深挖相关知识。

以前觉得自己一看就懂,实际是一问就打鼓,一用就糊涂。所以现在开始记录并总结再联系案例,一般是先把零散知识记录下来(看到过),慢慢地相关知识积累更多,直到碰到实践案例或是有点领悟到于是发现这块知识可以整理成一篇系统些的文章(基本快懂了)。

“技术变化太快,容易过时”,我的看法是网络知识、操作系统、计算机原理等核心概念知识的寿命会比你的职业生涯还长。这些都是40岁之后还会还会很有用

如何在工作中学习 所有方法我都记录在这篇文章中了,希望对你能有所帮助。

所有新文章从这里可以看到,即使再简单的一篇总结我可以持续总结三五年,有新的发现、感悟都是直接在原文上增减,不会发表新的文章。

image-20220421102225491

为什么写博客而不是公众号,我见过20年前的互联网,深度依赖搜索引擎,所以还是喜欢博客。另外技术类文章更适合电脑阅读(随时摘录、实验)

精华文章推荐

在2010年前后MySQL、PG、Oracle数据库在使用NUMA的时候碰到了性能问题,流传最广的这篇 MySQL – The MySQL “swap insanity” problem and the effects of the NUMA architecture http://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/ 文章描述了性能问题的原因(文章中把原因找错了)以及解决方案:关闭NUMA。 实际这个原因是kernel实现的一个低级bug,这个Bug在2014年修复了https://github.com/torvalds/linux/commit/4f9b16a64753d0bb607454347036dc997fd03b82,但是修复这么多年后仍然以讹传讹,这篇文章希望正本清源、扭转错误的认识。

image-20210517082233798

CPU的制造和概念 从最底层的沙子开始用8篇文章来回答关于CPU的各种疑问以及大量的实验对比案例和测试数据来展示了CPU的各种原理,比如多核、超线程、NUMA、睿频、功耗、GPU、大小核再到分支预测、cache_line失效、加锁代价、IPC等各种指标(都有对应的代码和测试数据)。

image-20210802161410524

《Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的》 从一个参数引起的rt抖动定位到OS锁等待再到CPU Pause指令,以及不同CPU型号对Pause使用cycles不同的影响,最终反馈到应用层面的rt全过程。在MySQL内核开发的时候考虑了Pause,但是没有考虑不同的CPU型号,所以换了CPU型号后性能差异比较大

image.png

10倍性能提升全过程 在双11的紧张流程下,将系统tps从500优化到5500,从网络到snat、再到Spring和StackTrace,一次全栈性能优化过程的详细记录和分析。

image.png

就是要你懂TCP–半连接队列和全连接队列:偶发性的连接reset异常、重启服务后短时间的连接异常,通过一篇文章阐明TCP连接的半连接队列和全连接队大小是怎么影响连接创建的,以及用什么工具来观察队列有没有溢出、连接为什么会RESET

image.png

就是要你懂TCP–性能和发送接收Buffer的关系:发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响。BDP、RT、带宽对传输速度又是怎么影响的

就是要你懂网络–一个网络包的旅程:教科书式地阐述书本中的路由、网关、子网、Mac地址、IP地址是如何一起协作让网络包最终传输到目标机器上。 同时可以跟讲这块的RFC1180比较一下,RFC1180 写的确实很好,清晰简洁,图文并茂,结构逻辑合理,但是对于90%的程序员没有什么卵用,看完几周后就忘得差不多,因为他不是从实践的角度来阐述问题,中间没有很多为什么,所以一般资质的程序员看完当时感觉很好,实际还是不会灵活运用

国产CPU和Intel、AMD性能PK 从Intel、AMD、海光、鲲鹏920、飞腾2500 等CPU在TPCC、sysbench下的性能对比来分析他们的性能差距,同时分析内存延迟对性能的影响

image-20220319115644219

从网络路由连通性的原理上来看负载均衡lvs的DR、NAT、FullNAT到底搞了些什么鬼,以及为什么要这么搞,和带来的优缺点:《就是要你懂负载均衡–lvs和转发模式》

LVS 20倍的负载不均衡,原来是内核的这个Bug,这个内核bug现在还在,可以稳定重现,有兴趣的话去重现一下,然后对照源代码以及抓包分析一下就清楚了。

就是要你懂TCP–握手和挥手,不是你想象中三次握手、四次挥手就理解了TCP,本文从握手的本质–握手都做了什么事情、连接的本质是什么等来阐述握手、挥手的原理

nslookup OK but ping fail–看看老司机是如何解决问题的,解决问题的方法肯定比知识点重要多了,同时透过一个问题怎么样通篇来理解一大块知识,让这块原理真正在你的只是提示中扎根下来

如何在工作中学习 一篇很土但是很务实可以复制的方法论文章。不要讲举一反三、触类旁通,谁都知道要举一反三、触类旁通,但是为什么我总是不能够举一反三、触类旁通?

举三反一–从理论知识到实际问题的推导 坚决不让思路跑偏,如何从一个理论知识点推断可能的问题

性能相关(2015-2018年)

就是要你懂TCP–半连接队列和全连接队列 偶发性的连接reset异常、重启服务后短时间的连接异常

就是要你懂TCP–性能和发送接收Buffer的关系:发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响。BDP、RT、带宽对传输速度又是怎么影响的 发送窗口大小(Buffer)、接收窗口大小(Buffer)对TCP传输速度的影响,以及怎么观察窗口对传输速度的影响

就是要你懂TCP–性能优化大全

就是要你懂TCP–TCP性能问题 Nagle算法和delay ack

10倍性能提升全过程 在双11的紧张流程下,将系统tps从500优化到5500,从网络到snat、再到Spring和StackTrace,看看一个性能全栈工程师如何在各种工具加持下发现各种问题的。

CPU系列文章(2021年完成)

CPU的制造和概念

十年后数据库还是不敢拥抱NUMA?

[Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的](/2019/12/16/Intel PAUSE指令变化是如何影响自旋锁以及MySQL的性能的/)

[Perf IPC以及CPU性能](/2021/05/16/Perf IPC以及CPU利用率/)

CPU性能和CACHE

[CPU 性能和Cache Line](/2021/05/16/CPU Cache Line 和性能/)

AMD Zen CPU 架构 以及 AMD、海光、Intel、鲲鹏的性能对比

Intel、海光、鲲鹏920、飞腾2500 CPU性能对比

网络相关基础知识(2017年完成)

就是要你懂网络–一个网络包的旅程

通过案例来理解MSS、MTU等相关TCP概念

就是要你懂TCP–握手和挥手

wireshark-dup-ack-issue and keepalive

一个没有遵守tcp规则导致的问题

[kubernetes service 和 kube-proxy详解](/2020/09/22/kubernetes service 和 kube-proxy详解/)

DNS相关

就是要你懂DNS–一文搞懂域名解析相关问题

nslookup OK but ping fail

Docker中的DNS解析过程

windows7的wifi总是报DNS域名异常无法上网

LVS 负载均衡

就是要你懂负载均衡–lvs和转发模式

就是要你懂负载均衡–负载均衡调度算法和为什么不均衡

网络工具

就是要你懂Unix Socket 进行抓包解析

就是要你懂网络监控–ss用法大全

就是要你懂抓包–WireShark之命令行版tshark

netstat timer keepalive explain

Git HTTP Proxy and SSH Proxy

跨 Die 热迁移迁移导致的性能问题

跨 Die 热迁移迁移导致的性能问题

场景

在 ARM 上,本来业务跑在 Die0 上,如果通过taskset 将 CPU 绑到 Die1,经过一段时间运行,内存也会慢慢随着释放/新分配慢慢都迁移到 Die1, 但是这之后仍然发现性能比在 Die0 上要差很多。而在 Intel X86 上没碰到过这个问题

分析

下图是内存带宽使用率监控数据,可以看到跨 Die 绑定后原来的 Die0 带宽急剧增加(7.5% -> 13%)这是因为内存都需要跨 Die 访问了,随着跨 Die 访问并慢慢将内存迁移到 Die1 后内存带宽使用率回落到 5%:

img

同时可以看到 CPU 使用率也从 35% 飙升到 76%,随着内存的迁移完毕,CPU 使用率回落到 48%,但仍然比最开始的 35% 高不少:

img

Intel X86 下跨 Die 迁移

Intel 基本都是一路就是一个 Die,所以你可以理解这里的跨 Die 就是跨路/Socket 迁移:

img

img

结论

ARM 比 X86 差这么多的原因是内存页表跨 Die 访问导致的,业务同学测试了开启 THP 负载的影响,从结果看,THP on 可有效降低cpu水位,但是依然存在跨die迁移cpu水位上升的问题。

alios 对应的 patch:https://gitee.com/anolis/cloud-kernel/pulls/2254/commits 不区分 x86 和 arm

页表是进程创建时在内核空间分配好的,所以迁移内存时并不会迁移页表。通过测试页表跨die迁移的poc,验证了跨die页表访问是导致本文所述问题的根本原因

课后作业:

去了解下内存页表/THP(透明大页)

学习 CPU 访问内存延时是怎么回事,然后学习 CPU 和内存速度的差异,最后再去看看大学的计算机组成原理

学习下 taskset/perf 等命令

CPU 使用率高就一定有效率吗?

CPU 使用率高就一定有效率吗?

背景

最近碰到一个客户业务跑在8C ECS 上,随着业务压力增加 CPU使用率也即将跑满,于是考虑将 8C 升级到16C,事实是升级后业务 RT 反而略有增加,这个事情也超出了所有程序员们的预料,所以我们接下来分析下这个场景

分析

通过采集升配前后、以前和正常时段的火焰图对比发现CPU 增加主要是消耗在 自旋锁上了:

image-20240202085410669

用一个案例来解释下自旋锁和锁,如果我们要用多线程对一个整数进行计数,要保证线程安全的话,可以加锁(synchronized), 这个加锁操作也有人叫悲观锁,抢不到锁就让出这个线程的CPU 调度(代价上下文切换一次,几千个时钟周期)

另外一种是用自旋锁(CAS、spin_lock) 来实现,抢不到锁就耍赖占住CPU 死磕不停滴抢(CPU 使用率一直100%),自旋锁的设计主要是针对抢锁概率小、并发低的场景。这两种方案针对场景不一样各有优缺点

假如你的机器是8C,你有100个线程来对这个整数进行计数的话,你用synchronized 方式来实现会发现CPU 使用率永远达不到50%

image-20240202090428778

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#taskset -a -c 56-63 java LockAccumulator 100 1000000000
累加结果: 1000000000 and time:84267

Performance counter stats for 'taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 100 100000000':

17785.271791 task-clock (msec) # 2.662 CPUs utilized
110,351 context-switches # 0.006 M/sec
10,094 cpu-migrations # 0.568 K/sec
11,724 page-faults # 0.659 K/sec
44,187,609,686 cycles # 2.485 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
22,588,807,670 instructions # 0.51 insns per cycle
6,919,355,610 branches # 389.050 M/sec
28,707,025 branch-misses # 0.41% of all branches

如果我们改成自旋锁版本的实现,8个核CPU 都是100%

image-20240202090714845

以下代码累加次数只有加锁版本的10%,时间还长了很多,也就是效率产出实在是低

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 100000000
累加结果: 100000000
操作耗时: 106593 毫秒

Performance counter stats for 'taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 100000000':

85363.429249 task-clock (msec) # 7.909 CPUs utilized
23,010 context-switches # 0.270 K/sec
1,262 cpu-migrations # 0.015 K/sec
13,403 page-faults # 0.157 K/sec
213,191,037,155 cycles # 2.497 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
43,523,454,723 instructions # 0.20 insns per cycle
10,306,663,291 branches # 120.739 M/sec
14,704,466 branch-misses # 0.14% of all branches

代码

放在了github 上,有个带调X86 平台 pause 指令的汇编,Java 中要用JNI 来调用,ChatGPT4帮我写的,并给了编译、运行方案:

1
2
3
4
5
6
7
8
9
10
javac SpinLockAccumulator.java
javah -jni SpinLockAccumulator

# Assuming GCC is installed and the above C code is in SpinLockAccumulator.c
gcc -shared -o libpause.so -fPIC SpinLockAccumulator.c

java -Djava.library.path=. SpinLockAccumulator

实际gcc编译要带上jdk的头文件:
gcc -I/opt/openjdk/include/ -I/opt/openjdk/include/linux/ -shared -o libpause.so -fPIC SpinLockAccumulator.c

在MySQL INNODB 里怎么优化这个自旋锁

MySQL 在自旋锁抢锁的时候每次会调 ut_delay(底层会掉CPU指令,让CPU暂停一下但是不让出——避免上下文切换),发现性能好了几倍。这是MySQL 的官方文档:https://dev.mysql.com/doc/refman/5.7/en/innodb-performance-spin_lock_polling.html

所以我们继续在以上代码的基础上在自旋的时候故意让CPU pause(50个), 这个优化详细案例:https://plantegg.github.io/2019/12/16/Intel%20PAUSE%E6%8C%87%E4%BB%A4%E5%8F%98%E5%8C%96%E6%98%AF%E5%A6%82%E4%BD%95%E5%BD%B1%E5%93%8D%E8%87%AA%E6%97%8B%E9%94%81%E4%BB%A5%E5%8F%8AMySQL%E7%9A%84%E6%80%A7%E8%83%BD%E7%9A%84/

该你动手了

随便找一台x86 机器,笔记本也可以,macOS 也行,核数多一些效果更明显。只要有Java环境,就用我编译好的class、libpause.so 理论上也行,不兼容的话按代码那一节再重新编译一下

可以做的实验:

  • 重复我前面两个运行,看CPU 使用率以及最终耗时
  • 尝试优化待pause版本的自旋锁实现,是不是要比没有pause性能反而要好
  • 尝试让线程sleep 一下,效果是不是要好?
  • 尝试减少线程数量,慢慢是不是发现自旋锁版本的性能越来越好了

改变线程数量运行对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//自旋锁版本线程数对总时间影响很明显,且线程少的话性能要比加锁版本好,这符合自旋锁的设定:大概率不需要抢就用自旋锁
#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 1 100000000
累加结果: 100000000
操作耗时: 2542 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 2 100000000
累加结果: 100000000
操作耗时: 2773 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 4 100000000
累加结果: 100000000
操作耗时: 4109 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 8 100000000
累加结果: 100000000
操作耗时: 11931 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 16 100000000
累加结果: 100000000
操作耗时: 13476 毫秒


//加锁版本线程数变化对总时间影响不那么大
#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 16 100000000
累加结果: 100000000 and time:9074

#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 8 100000000
累加结果: 100000000 and time:8832

#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 4 100000000
累加结果: 100000000 and time:7330

#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 2 100000000
累加结果: 100000000 and time:6298

#taskset -a -c 56-63 java -Djava.library.path=. LockAccumulator 1 100000000
累加结果: 100000000 and time:3143

设定100并发下,改变机器核数对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//16核机器跑3次 耗时稳定在12秒以上,CPU使用率 1600%
#taskset -a -c 48-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 12860 毫秒

#taskset -a -c 48-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 12949 毫秒

#taskset -a -c 48-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 13692 毫秒

//8核机器跑3次,耗时稳定5秒左右,CPU使用率 800%
#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 6773 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 5557 毫秒

#taskset -a -c 56-63 java -Djava.library.path=. SpinLockAccumulator 100 10000000
累加结果: 10000000
操作耗时: 2724 毫秒

总结

以后应该不会再对升配后CPU 使用率也上去了,但是最终效率反而没变展现得很惊诧了

从CPU 使用率、上下文切换上理解自旋锁(乐观锁)和锁(悲观锁)

MySQL 里对自旋锁的优化,增加配置 innodb_spin_wait_delay 来增加不同场景下DBA 的干预手段

这篇文章主要功劳要给 ChatGPT4 ,里面所有演示代码都是它完成的

相关阅读

流量一样但为什么CPU使用率差别很大 同样也是跟CPU 要效率,不过这个案例不是因为自旋锁导致CPU 率高,而是内存延时导致的

今日短平快,ECS从16核升配到48核后性能没有任何提升(Netflix) 也是CPU 使用率高没有产出,cacheline伪共享导致的

听风扇声音来定位性能瓶颈

你要是把这个案例以及上面三个案例综合看明白了,相当于把计算机组成原理就学明白了。这里最核心的就是“内存墙”,也就是内存速度没有跟上CPU的发展速度,导致整个计算机内绝大多场景下读写内存缓慢成为主要的瓶颈

如果你觉得看完对你很有帮助可以通过如下方式找到我

find me on twitter: @plantegg

知识星球:https://t.zsxq.com/0cSFEUh2J

开了一个星球,在里面讲解一些案例、知识、学习方法,肯定没法让大家称为顶尖程序员(我自己都不是),只是希望用我的方法、知识、经验、案例作为你的垫脚石,帮助你快速、早日成为一个基本合格的程序员。

争取在星球内:

  • 养成基本动手能力
  • 拥有起码的分析推理能力–按我接触的程序员,大多都是没有逻辑的
  • 知识上教会你几个关键的知识点
image-20240324161113874

tcp会偶尔3秒timeout的分析以及如何用php规避这个问题

tcp会偶尔3秒timeout的分析以及如何用php规避这个问题

这是一篇好文章,随着蘑菇街的完蛋,蘑菇街技术博客也没了,所以特意备份一下这篇

  • 作者:蚩尤

  • 时间:May 27, 2014

2年前做一个cache中间件调用的时候,发现很多通过php的curl调用一个的服务会出现偶尔的connect_time超时, 表现为get_curlinfo的connect_time在3秒左右, 本来没怎么注意, 因为客户端的curl_timeout设置的就是3秒, 某天, 我把这个timeout改到了5秒后, 发现了一个奇怪的现象, 很多慢请求依旧表现为connect_time在3秒左右..看来这个3秒并不是因为客户端设置的timeout引起的.于是开始查找这个原因.


首先, 凭借经验调整了linux内核关于tcp的几个参数

1
2
net.core.netdev_max_backlog = 862144
net.core.somaxconn = 262144

经过观察发现依旧会有3秒超时, 而且数量并没有减少.

第二步, 排除是大并发导致的问题, 在一台空闲机器上也部署同样的服务, 仅让线上一台机器跑空闲机器的服务, 结果发现依旧会有报错.排除并发导致的问题.

最后, 通过查了大量的资料才发现并不是我们才遇到过这个问题, 而且这个问题并不是curl的问题, 它影响到所有tcp的调用, 网上各种说法, 但结论都指向linux内核对于tcp的实现.(某些版本会出现这些问题), 有兴趣的可以看下下面这两个资料.
资料1
资料2

一看深入到linux内核..不管怎样修改的成本一定很大..于是乎, 发挥我们手中的php来规避这个问题的时间到了.

原本的代码, 简单实现,常规curl调用:

1
2
3
4
5
6
7
8
9
10
function curl_call($p1, $p2 ...) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_URL, 'http://demon.at');
$res = curl_exec($ch);
if (false === $res) {
//失败..抛异常..
}
return $res;
}

可以看出, 如果用上面的代码, 无法避免3秒connect_time的问题..这种实现对curl版本会有要求(CURLOPT_CONNECTTIMEOUT_MS),主要的思路是,通过对链接时间进行毫秒级的控制(因为超时往往发生在connect的时候),加上失败重试机制,来最大限度保证调用的正确性。所以,下面的代码就诞生了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function curl_call($p1, $p2, $times = 1) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_URL, 'http://demon.at');
$curl_version = curl_version();
if ($curl_version['version_number'] >= 462850) {
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 20);
curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
} else {
throw new Exception('this curl version is too low, version_num : '
. $curl_version['version']);
}
$res = curl_exec($ch);
curl_close($ch);
if (false === $res) {
if (curl_errno($ch) == CURLE_OPERATION_TIMEOUTED
and $times != 最大重试阀值 ) {
$times += 1;
return curl_call($p1, $p2, $times);
}
}

return $res;
}

上面这段代码只是一个规避的简单实例, 一些小细节并没有可以完善..比如抛出异常常以后curl资源的手动释放等等..这里不做讨论..当然还漏了一点要说的是,对重试次数最好加上限制 :)

说明一下上面几个数字值的含义:

1
2
462850 //因为php的CURLOPT_CONNECTTIMEOUT_MS需要 curl_version 7.16.2,这个值就是这个版本的数字版本号,还需要注意的是, php版本要大于5.2.3
20 //连接超时的时间, 单位:ms

这样这个问题就这样通过php的代码来规避开了.
如果有对这个问题有更好的解决方法,欢迎指教.


总结

tcp connect 的流程是这样的
1、tcp发出SYN建链报文后,报文到ip层需要进行路由查询
2、路由查询完成后,报文到arp层查询下一跳mac地址
3、如果本地没有对应网关的arp缓存,就需要缓存住这个报文,发起arp请求
4、arp层收到arp回应报文之后,从缓存中取出SYN报文,完成mac头填写并发送给驱动。

问题在于,arp层缓存队列长度默认为3。如果你运气不好,刚好赶上缓存已满,这个报文就会被丢弃。

TCP层发现SYN报文发出去3s(默认值)还没有回应,就会重发一个SYN。这就是为什么少数连接会3s后才能建链。

幸运的是,arp层缓存队列长度是可配置的,用 sysctl -a | grep unres_qlen 就能看到,默认值为3。

一次抓包分析过程——Wireshark 新手上车

一次抓包分析过程——Wireshark 新手上车

问题

网友尝试做星球第一个必做实验的时候,什么内核参数都没改,发现请求经常会停滞 100ms,这种要怎么判断是局域网的网络问题还是应用问题呢? 服务是 python3 -m http.server 启动的,看上去没有出现什么重传、窗口也没看到什么问题

因为不能提供环境给我,我尝试对这个抓包进行了分析,因为只有客户端抓包,所以分析结果是没有结论的,但分析过程比较适合入门 Wireshark,适合刚加入星球的、没分析过网络包的同学可以参考,熟手请忽略

分析

整个抓包 28MB,跨度 600 毫秒,看得出带宽很大、RTT 极小(到Wireshark 里看看前几个包的交互 RT 就知道了)

image-20240715093847359

详细分析

看第一次卡 100ms 之前的抓包,在100ms 以前客户端ack 了所有Server 发出来的的tcp包(红框),也就是说每一个发给客户端的包客户端都ack 完毕,证明客户端处理足够快,但是 8089端口不继续发包而是等了100ms再继续发,如下图:

image-20240715094218182

到这里的结论:

不是因为发送buffer、接收buffer太小导致的卡;也不是因为拥塞窗口导致的,就是Server 端没有发包。大概率是Server 进程卡了,或者Server 进程读取物理文件往OS buffer 写这些环节卡了(可以在服务端通过 strace -tt 看看进程在这 100 毫秒有没有往内核怼数据)

所以要继续在 Server 端来分析这个问题

怎么快速定位到红框、红线这里的包?

到 Time Sequence 图上点平台两边的点都可以自动跳转到这里,每个点代表一个网络包,横坐标代表时间

其它分析

将如下 Time Sequence 图使劲放大,从第一个包开始看,可以观察到教科书所说的慢启动

image-20240715095134352

整体看的话,慢启动几乎可以忽略,毕竟这个抓包是下载一个巨大的文件,如果是一个小文件这个慢启动还是影响很大的,如下图,红框部分看起来微不足道

image-20240715095506381

把时间范围放大,继续看,在卡之前红色箭头很长的,代表带宽、buffer有能力一次发送很多网络包,但是后面每次只发一点点网络包(绿色箭头长度)就卡了

image-20240715095647702

重现

我用 python3 当服务端未能重现这个卡100ms 的现象,拉取都很丝滑

image-20240715101505977

非常细节地去分析的话,也是能看到一些小问题的,比如1.9ms的卡顿、比如zero_window

image-20240715103928266

重现的时候,有1.9ms 这样的卡顿,但是不算有规律,因为这么小在整个传输过程中影响不大

image-20240715103708750

我重现的时候正好抓到了 seq 回绕,seq 是个 32位的无符号整数,到了最大值就从0又开始:

image-20240715115500312

此时的 Time Sequence:

image-20240715115655516

建议

可以用实验1里面的一些手段debug 一下Server 为什么卡了,除了 strace -tt 还可以用 ebpf 试试看看 Server 的调度上哪里顿了 100ms

新手如何通过Wireshark 来看抓包?

首先不要纯粹为了学习去看,而是要问你的问题是什么?如果网络传输速度慢,我们就看 Time Sequence(斜率越陡速度越快),去看为什么发送端不发包了

  • 如正文里的卡顿平台,在250ms内差不多要卡240ms 不发包,速度自然不行
  • 我重现抓包中的zero Windows
  • 达到网络BDP 瓶颈了,去看拥塞窗口在最大值的时候会丢包,触发降速

里面可以看、要看的东西太多,所以我也说不上要看什么,而是要问你的问题是什么

历时5年的net_write_timeout 报错分析

历时5年的net_write_timeout 报错分析

全网关于 JDBC 报错:net_write_timeout 的最好/最全总结

前言

上一次为了讲如何分析几百万个抓包,所以把这个问题中的一部分简化写了这篇抓包篇:https://articles.zsxq.com/id_lznw3w4zieuc.html 建议你先去看看把场景简化下,然后本篇中的分析涉及抓包部分就不再啰嗦讲解,请看抓包篇

问题描述

用户为了做数据分析需要把160个DB中的数据迁移到另外一个只读库中,有专门的迁移工具,但是这个迁移工具跑一阵后总是报错,报错堆栈显示是Tomcat 到DB之间的连接出了异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Application was streaming results when the connection failed. Consider raising value of 'net_write_timeout' on the server.
at sun.reflect.GeneratedConstructorAccessor150.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:989)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3749)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3649)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4090)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:972)
at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:2123)
at com.mysql.jdbc.RowDataDynamic.nextRecord(RowDataDynamic.java:374)
at com.mysql.jdbc.RowDataDynamic.next(RowDataDynamic.java:354)
at com.mysql.jdbc.RowDataDynamic.close(RowDataDynamic.java:155)
at com.mysql.jdbc.ResultSetImpl.realClose(ResultSetImpl.java:6726)
at com.mysql.jdbc.ResultSetImpl.close(ResultSetImpl.java:865)
at com.alibaba.druid.pool.DruidPooledResultSet.close(DruidPooledResultSet.java:86)

这个异常堆栈告诉我们Tomcat 到Database之间的连接异常了,似乎是 net_write_timeout 超时导致的

对应业务结构:

image-20230706210452742

net_write_timeout 原理简介

先看下 net_write_timeout的解释:

The number of seconds to wait for a block to be written to a connection before aborting the write. 只针对执行查询中的等待超时,网络不好,tcp buffer满了(应用迟迟不读走数据)等容易导致mysql server端报net_write_timeout错误,指的是mysql server hang在那里长时间无法发送查询结果。

报这个错就是DB 等了net_write_timeout这么久没写数据,可能是Tomcat 端卡死没有读走数据。

但是根据我多年来和这个报错打交道的经验告诉我:这个报错不只是因为net_write_timeout 超时导致的,任何Tomcat 到 DB间的连接断开了,都报这个错误,原因是JDBC 驱动搞不清楚断开的具体原因,统统当 net_write_timeout 了

一定要记住这个原理。如果这里不理解可以进一步阅读:https://wx.zsxq.com/dweb2/index/topic_detail/412251415855228

分析

首先把Tomcat 集群从负载均衡上摘一个下来,这样没有业务流量干扰更利于测试和分析日志

然后让迁移数据工具直接连这个没有流量的节点,问题仍然稳定重现。

进一步提取迁移工具的SQL,然后走API手工提交给Tomcat 执行,问题仍然稳定重现,现在重现越来越简单了,效率高多了。

Tomcat 上抓包

因为没有业务流量干扰,抓包很干净,但是因为DB 节点太多,所以量还是很大的,分析如抓包篇:https://articles.zsxq.com/id_lznw3w4zieuc.html

如下图红框所示的地方可以看到MySQL Server 传着传着居然带了个 fin 包在里面,表示MySQL Server要断开连接了,无奈Client只能也发送quit 断开连接。红框告诉我们一个无比有力的证据MySQL Server 在不应该断开的地方断开了连接,问题在 MySQL Server 端

image-20230620141017987

看起来是Database 主动端开了连接,因为这个过程Tomcat 不需要发任何东西给 Database。这个现象5年前在其它用户场景下就抓到过了,最后问题也不了了之,这次希望搞清楚

Database 分析

打开 DB 日志,捞取全量日志可以看到 DB 断开的原因是收到了kill Query!

有这个结果记住上面抓包图,以后类似这样莫名起来 DB 主动断开大概率就是 kill Query 导致的(经验攒得不容易!)

Database 抓包

确实能抓到kill,而且从用户账号来看就是从 Tomcat 发过去的!

继续分析Tomcat 抓包

从 DB 分析来看还是有人主动 kill 导致的,所以继续分析Tomcat的抓包看是不是因为代码bug导致Tomcat 发了kill 给DB

大海捞针,搜 kill,找Tomcat 发给DB的tcp length 长度是16-20的(刚好容纳kill id) 总的来说就是找不到,很神奇

由于 DB上记录的 Tomcat IP、port 都被中间链路转换过几次了,根本没办法一一对应搞清楚是哪个Tomcat 节点发出来的

继续尝试重现

分析完Tomcat 业务代码后感觉业务不会去kill,于是灵机一动在没有流量的Tomcat上跑了一个Sleep 600秒,不用任何数据,神奇的问题也稳定重现了,这下大概知道什么原因了,肯定是客户自己加了慢查询监控逻辑,一旦发现慢查询就 kill

于是问客户是不是有这种监控,果然有,停掉后反复重试不再有问题!

测试环境手工触发kill,然后能抓到下发的kill Query 给Database

image-20230707150658392

未解谜题

为什么没在Tomcat 抓到发给Database的 kill ?

我反复去重现了,如果是我手工触发Tomcat kill是可以清晰地抓到Tomcat 会发160个kill 给Database,但是我任其自然等待用户监控来杀就一定抓不到kill 下发给DB

我猜和 Tomcat 集群有关,首先用户监控是走的LVS,通过其中一个Tomcat 可以查询到所有 Tomcat 上的请求,然后发起 kill

但因为节点太多无法证实!当然业务监控也可以监控DB 然后直接发kill,但是和抓包看到的发起kill的用户不对,发起 kill 的用户是Tomcat独一无二的。

JDBC驱动报错 net_write_timeout 结论

Application was streaming results when the connection failed. Consider raising value of ‘net_write_timeout’ on the server. - com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Application was streaming results when the connection failed. Consider raising value of ‘net_write_timeout’ on the server.

这个报错不一定是 net_write_timeout 设置过小导致的,JDBC 在 streaming 流模式下只要连接异常就会报如上错误,比如:

  • 连接被 TCP reset
  • RDS 前端自带的Proxy 主动断开连接
  • 连接因为某种原因(比如 QueryTimeOut) 触发 kill Query导致连接中断
  • RDS 端因为kill 主动断开连接 //比如用户监控RDS、DRDS脚本杀掉慢查询

net_write_timeout:表示这么长时间RDS/DN 无法写数据到网络层发给DRDS/CN,原因是DRDS/CN 长时间没将数据读走

总结

首先一个错误现象对应多个完全不一样的错误原因是非常头疼的,这个问题反反复复在多个场景下出现,当然原因各异,但是这个传数据途中 DB 主动 fin连接还是第一次碰到并搞清楚,同样主动 fin 不一定是kill,但是我们要依照证据推进问题,既然是DB fin就有必要先从DB 来看原因。

从这个问题你可以先从什么是JDBC 流模式出发(mysql –quick 就是流模式,你可以快速查一个大数据试试;然后去掉–quick 对比一下),结合网络buffer 来了解流模式:https://plantegg.github.io/2020/07/03/MySQL%20JDBC%20StreamResult%20%E5%92%8C%20net_write_timeout/

然后从流模式来学习MySQL 的 net_write_timeout,假如你的代码报了 net_write_timeout 你会分析吗?

最后从连接断开去总结,比如网络不好、比如内核bug、比如DB crash、比如 kill、比如……都会导致连接断开,但这一切对业务来说只有 net_write_timeout 一个现象

这个问题分享出来是因为非常综合,我惊抱怨 socketTimeout、Communication failure等异常,这些异常也挺常见导致的原因多种,但是和 net_write_timeout 比起来还是不如 net_write_timeout 更综合,所以分享给大家,建议这几篇一起阅读效果最好!

实验模拟 Consider raising value of ‘net_write_timeout’

使用 Java MySQL JDBC Driver 的同学经常碰到如下错误堆栈,到底这个错误是 net_write_timeout 设置太小还是别的原因也会导致这个问题?需要我们用实验验证一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Application was streaming results when the connection failed. Consider raising value of 'net_write_timeout' on the server.
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:990)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3559)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3459)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3900)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:873)
at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:1996)
at com.mysql.jdbc.RowDataDynamic.nextRecord(RowDataDynamic.java:374)
at com.mysql.jdbc.RowDataDynamic.next(RowDataDynamic.java:354)
at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:6312)
at Test.main(Test.java:38)
Caused by: java.io.EOFException: Can not read response from server. Expected to read 8 bytes, read 3 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3011)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3519)
... 8 more

JDBC 驱动对这个错误有如下提示(坑人):

Application was streaming results when the connection failed. Consider raising value of ‘net_write_timeout’ on the server. - com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Application was streaming results when the connection failed. Consider raising value of ‘net_write_timeout’ on the server.

实验中的一些说明:

  1. netTimeoutForStreamingResults=1 表示设置 net_write_timeout 为 1 秒,客户端会发送 set net_write_timeout=1 给数据库
  2. conn.setAutoCommit(false); //流式读取必须要 关闭自动提交
  3. stmt.setFetchSize(Integer.MIN_VALUE);

以上 2/3是触发流式读取的必要条件,第一条不设置默认是 600 秒,比较难等 :)

如果确实是 net_write_timeout 太小超时了, RDS 直接发 fin(但是 fin 前面还有一堆 response 包也在排队),然后 RDS 日志先报错:

1
2024-11-28T14:33:03.447397Z 12 [Note] Aborted connection 12 to db: 'test' user: 'root' host: '172.26.137.130' (Got timeout writing communication packets)

此时客户端还慢悠悠地读,RDS 没有回任何错误信息给客户端,客户端读完所有 Response 然后直接读到连接断开就报 Consider raising value of ‘net_write_timeout’ on the server 了,如果客户端读的慢,比如要 10 分钟实际连接在 RDS 上 10 分钟前就进入 fin 了,但是 10 分钟后客户端才报错

1
2
3
4
5
6
7
8
9
10
#netstat -anto | grep "3307"
tcp6 0 0 :::3307 :::* LISTEN off (0.00/0/0)
tcp6 0 140192 172.26.137.120:3307 172.26.137.130:51216 ESTABLISHED probe (0.04/0/0)
2024年 11月 28日 星期四 15:01:43 CST

//1秒中后此时 数据库感知到超时于是调用 close 断开连接,触发发送 fin给客户端,但是 fin 也需要排队,所以 140192增加了 1 变成140193
tcp6 0 0 :::3307 :::* LISTEN off (0.00/0/0)
tcp6 0 140193 172.26.137.120:3307 172.26.137.130:51216 FIN_WAIT1 probe (0.58/0/1)
2024年 11月 28日 星期四 15:01:44 CST

重现代码,数据库上构造一个大表,比如 10万行就行,能堆满默认的 tcp buffer size:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;

/*
* 编译:
* javac -cp /root/java/*:. Test.java
* 运行:
* java -cp .:./mysql-connector-java-5.1.45.jar Test "jdbc:mysql://gf1:3307/test?useSSL=false&useServerPrepStmts=true&cachePrepStmts=true&connectTimeout=500&socketTimeout=1700&netTimeoutForStreamingResults=1" root 123 "select *, id from streaming " 3000
* netTimeoutForStreamingResults=1 表示RDS 等超过 1 秒都因为 tcp buffer 满无法继续发送数据就断开连接
* */
public class Test {
private static String url;
private Str name;

public static void main(String args[]) throws NumberFormatException, InterruptedException, ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
url = args[0];
String user = args[1];
String pass = args[2];
String sql = args[3];
String interval = args[4];
try {
Connection conn = DriverManager.getConnection(url, user, pass);
while (true) {

conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.setFetchSize(Integer.MIN_VALUE);

long start = System.currentTimeMillis();
ResultSet rs = stmt.executeQuery(sql);
int count=0;
while (rs.next()) {
System.out.println("id:"+rs.getInt("id")+" count:"+count);
count++;
if(count<3) //1 秒后数据库端连接就已经关闭了,但是因为客户端读得慢,需要不 sleep 后才能读到 fin 然后报错,所以报错可以比实际晚很久
Thread.sleep(1500);
}
rs.close();
stmt.close();
Thread.sleep(Long.valueOf(interval));
break;
}
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

Consider raising value of ‘net_write_timeout’ 这个报错数据库端不会返回任何错误码给客户端,只是发 fin 断开连接,对客户端来说这条连接是 net_write_timeout 超时了 还是 被kill(或者其他原因) 是没法区分的,所以不管什么原因,只要连接异常 MySQL JDBC Driver 就抛 net_write_timeout 错误

如图,3 秒钟后 fin 包混在数据库 response 就被发到了客户端,实际2 秒前数据库已经报错了,也就是客户端和数据库端报错时间会差 2 秒(具体差几秒取决于重现代码里 sleep 多久然后-1)

image-20241128151324385

实验总结

这个报错不一定是 net_write_timeout 设置过小导致的,JDBC 在 streaming 流模式下只要连接异常就会报如上错误,比如:

  • 连接被 TCP reset
  • RDS 前端自带的Proxy 主动断开连接
  • 连接因为某种原因(比如 QueryTimeOut) 触发 kill Query导致连接中断
  • RDS 端因为kill 主动断开连接 //比如用户监控RDS 脚本杀掉慢查询
  • 开启流式读取后,只要客户端在读取查询结果没有结束就读到了 fin 包就会报这个错误

可以将 netTimeoutForStreamingResults 设为 0 或者 100,然后在中途 kill 掉 MySQL 上的 SQL,你也会在客户端看到同样的错误, kill SQL 是在 MySQL 的报错日志中都是同样的:

1
2024-11-28T07:33:12.967012Z 23 [Note] Aborted connection 23 to db: 'test' user: 'root' host: '172.26.137.130' (Got an error writing communication packets)

所以你看一旦客户端出现这个异常堆栈,除了抓包似乎没什么好办法,其实抓包也只能抓到数据库主动发了 fin 什么原因还是不知道,我恨这个没有错误码一统江湖的报错

net_write_timeout 后 RDS 直接发 fin(有时 fin 前面还有一堆 response 包也在排队),然后 rds 日志先报错:2024-11-28T06:33:03.447397Z 12 [Note] Aborted connection 12 to db: ‘test’ user: ‘root’ host: ‘172.26.137.130’ (Got timeout writing communication packets)

客户端慢悠悠地读,RDS 没有传任何错误信息给客户端,客户端读完所有 response 然后直接读到连接断开就报 Consider raising value of ‘net_write_timeout’ on the server 了,如果客户端读的慢,比如要 10 分钟实际连接在 RDS 上 10 分钟前就进入 fin 了,但是 10 分钟后客户端才报错

进阶阅读:https://plantegg.github.io/2024/09/25/%E4%B8%80%E4%B8%AA%E5%8E%86%E6%97%B65%E5%B9%B4%E7%9A%84%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/https://x.com/plantegg/status/1867535551337050153

长连接黑洞重现和分析

长连接黑洞重现和分析

这是一个存在多年,遍及各个不同的业务又反反复复地在集团内部出现的一个问题,本文先通过重现展示这个问题,然后从业务、数据库、OS等不同的角度来分析如何解决它,这个问题值得每一位研发同学重视起来,避免再次踩到

背景

为了高效率应对故障,本文尝试回答如下一些问题:

  • 为什么数据库crash 重启恢复后,业务还长时间不能恢复?
  • 我依赖的业务做了高可用切换,但是我的业务长时间报错
  • 我依赖的服务下掉了一个节点,为什么我的业务长时间报错
  • 客户做变配,升级云服务节点规格,为什么会导致客户业务长时间报错

目的:希望通过这篇文章尽可能地减少故障时长、让业务快速从故障中恢复

重现

空说无凭,先也通过一次真实的重现来展示这个问题

LVS+MySQL 高可用切换

OS 默认配置参数

1
2
3
4
5
6
#sysctl -a |grep -E "tcp_retries|keepalive"
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_time = 10
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15 //主要是这个参数,默认以及alios 几乎都是15

LVS 对外服务端口是3001, 后面挂的是 3307,假设3307是当前的Master,Slave是 3306,当检测到3307异常后会从LVS 上摘掉 3307挂上 3306做高可用切换

undefined

切换前的 LVS 状态

1
2
3
4
5
6
7
8
#ipvsadm -L --timeout
Timeout (tcp tcpfin udp): 900 120 300
#ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 127.0.0.1:3001 rr
-> 127.0.0.1:3307 Masq 1 0 0

Sysbench启动压力模拟用户访问,在 31秒的时候模拟管控检测到 3307的Master无法访问,所以管控执行切主把 3306的Slave 提升为新的 Master,同时到 LVS 摘掉 3307,挂上3306,此时管控端着冰可乐、翘着二郎腿,得意地说,你就看吧我们管控牛逼不、我们的高可用牛逼不,这一套行云流水3秒钟不到全搞定

切换命令如下:

1
2
#cat del3307.sh
ipvsadm -d -t 127.0.0.1:3001 -r 127.0.0.1:3307 ; ipvsadm -a -t 127.0.0.1:3001 -r 127.0.0.1:3306 -m

此时Sysbench运行状态,在第 32秒如期跌0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#/usr/local/bin/sysbench --debug=on --mysql-user='root' --mysql-password='123' --mysql-db='test' --mysql-host='127.0.0.1' --mysql-port='3001' --tables='16'  --table-size='10000' --range-size='5' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --time='11080' --report-interval='1' --histogram='on' --threads=1 oltp_read_write run
sysbench 1.1.0 (using bundled LuaJIT 2.1.0-beta3)

Running the test with following options:
Number of threads: 1
Report intermediate results every 1 second(s)
Debug mode enabled.

Initializing random number generator from current time


Initializing worker threads...

DEBUG: Worker thread (#0) started
DEBUG: Reporting thread started
DEBUG: Worker thread (#0) initialized
Threads started!

[ 1s ] thds: 1 tps: 51.89 qps: 947.00 (r/w/o: 739.44/207.56/0.00) lat (ms,95%): 35.59 err/s 0.00 reconn/s: 0.00
[ 2s ] thds: 1 tps: 60.03 qps: 1084.54 (r/w/o: 841.42/243.12/0.00) lat (ms,95%): 22.28 err/s 0.00 reconn/s: 0.00
…………
[ 29s ] thds: 1 tps: 68.00 qps: 1223.01 (r/w/o: 952.00/271.00/0.00) lat (ms,95%): 16.12 err/s 0.00 reconn/s: 0.00
[ 30s ] thds: 1 tps: 66.00 qps: 1188.00 (r/w/o: 924.00/264.00/0.00) lat (ms,95%): 16.71 err/s 0.00 reconn/s: 0.00
[ 31s ] thds: 1 tps: 67.00 qps: 1203.96 (r/w/o: 937.97/265.99/0.00) lat (ms,95%): 17.95 err/s 0.00 reconn/s: 0.00
[ 32s ] thds: 1 tps: 22.99 qps: 416.85 (r/w/o: 321.88/94.96/0.00) lat (ms,95%): 15.55 err/s 0.00 reconn/s: 0.00
[ 33s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 34s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 35s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00

5分钟后故障报告大批量涌进来,客户:怎么回事,我们的业务挂掉10分钟了,报错都是访问MySQL 超时,赶紧给我看看,从监控确实看到10分钟后客户业务还没恢复:

1
2
3
4
[ 601s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 602s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 603s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 604s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00

这时 oncall 都被从被窝里拎了起来,不知谁说了一句赶紧恢复吧,先试试把应用重启,5秒钟后应用重启完毕,业务恢复,大家开心地笑了,又成功防御住一次故障升级,还是重启大法好!

在业务/Sysbench QPS跌0 期间可以看到 3307被摘掉,3306 成功挂上去了,但是没有新连接建向 3306,业务/Sysbench 使劲薅着 3307

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ipvsadm -L -n --stats -t 127.0.0.1:3001
Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
-> RemoteAddress:Port
TCP 127.0.0.1:3001 2 660294 661999 78202968 184940K
-> 127.0.0.1:3306 0 0 0 0 0

#ipvsadm -Lcn | head -10
IPVS connection entries
pro expire state source virtual destination
TCP 13:11 ESTABLISHED 127.0.0.1:33864 127.0.0.1:3001 127.0.0.1:3307

#netstat -anto |grep -E "Recv|33864|3001|33077"
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 248 127.0.0.1:33864 127.0.0.1:3001 ESTABLISHED probe (33.48/0/8)
tcp6 0 11 127.0.0.1:3307 127.0.0.1:33864 ESTABLISHED on (49.03/13/0)

直到 900多秒后 OS 重试了15次发现都失败,于是向业务/Sysbench 返回连接异常,触发业务/Sysbench 释放异常连接重建新连接,新连接指向了新的 Master 3306,业务恢复正常

1
2
3
4
5
6
7
[ 957s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
DEBUG: Ignoring error 2013 Lost connection to MySQL server during query,
DEBUG: Reconnecting
DEBUG: Reconnected
[ 958s ] thds: 1 tps: 53.00 qps: 950.97 (r/w/o: 741.98/208.99/0.00) lat (ms,95%): 30.26 err/s 0.00 reconn/s: 1.00
[ 959s ] thds: 1 tps: 64.00 qps: 1154.03 (r/w/o: 896.02/258.01/0.00) lat (ms,95%): 22.69 err/s 0.00 reconn/s: 0.00
[ 960s ] thds: 1 tps: 66.00 qps: 1184.93 (r/w/o: 923.94/260.98/0.00) lat (ms,95%): 25.28 err/s 0.00 reconn/s: 0.00

到这里重现了故障中经常碰到的业务需要900多秒才能慢慢恢复,这个问题也就是 TCP 长连接流量黑洞

如果我们把 net.ipv4.tcp_retries2 改成5 再来做这个实验,就会发现业务/Sysbench 只需要20秒就能恢复了,也就是这个流量黑洞从900多秒变成了20秒,这回 oncall 不用再被从被窝里拎出来了吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[ 62s ] thds: 1 tps: 66.00 qps: 1191.00 (r/w/o: 924.00/267.00/0.00) lat (ms,95%): 17.63 err/s 0.00 reconn/s: 0.00
[ 63s ] thds: 1 tps: 63.00 qps: 1123.01 (r/w/o: 874.00/249.00/0.00) lat (ms,95%): 17.63 err/s 0.00 reconn/s: 0.00
[ 64s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 65s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 66s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 67s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 68s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 69s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 70s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 71s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 72s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 73s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 74s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 75s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 76s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 77s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 78s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 79s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 80s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 81s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
[ 82s ] thds: 1 tps: 0.00 qps: 0.00 (r/w/o: 0.00/0.00/0.00) lat (ms,95%): 0.00 err/s 0.00 reconn/s: 0.00
DEBUG: Ignoring error 2013 Lost connection to MySQL server during query,
DEBUG: Reconnecting
DEBUG: Reconnected
[ 83s ] thds: 1 tps: 26.00 qps: 457.01 (r/w/o: 357.01/100.00/0.00) lat (ms,95%): 16.41 err/s 0.00 reconn/s: 1.00
[ 84s ] thds: 1 tps: 60.00 qps: 1086.94 (r/w/o: 846.96/239.99/0.00) lat (ms,95%): 26.68 err/s 0.00 reconn/s: 0.00
[ 85s ] thds: 1 tps: 63.00 qps: 1134.02 (r/w/o: 882.01/252.00/0.00) lat (ms,95%): 23.10 err/s 0.00 reconn/s: 0.00

LVS + Nginx 上重现

NGINX上重现这个问题:https://asciinema.org/a/649890 3分钟的录屏,这个视频构造了一个LVS 的HA切换过程,LVS后有两个Nginx,模拟一个Nginx(Master) 断网后,将第二个Nginx(Slave) 加入到LVS 并将第一个Nginx(Master) 从LVS 摘除,期望业务能立即恢复,但实际上可以看到之前的所有长连接都没有办法恢复,进入一个流量黑洞

TCP 长连接流量黑洞原理总结

TCP 长连接在发送包的时候,如果没收到ack 默认会进行15次重传(net.ipv4.tcp_retries2=15, 这个不要较真,会根据RTO 时间大致是15次),累加起来大概是924秒,所以我们经常看到业务需要15分钟左右才恢复。这个问题存在所有TCP长连接中(几乎没有业务还在用短连接吧?),问题的本质和 LVS/k8s Service 都没关系

我这里重现带上 LVS 只是为了场景演示方便

这个问题的本质就是如果Server突然消失(宕机、断网,来不及发 RST )客户端如果正在发东西给Server就会遵循TCP 重传逻辑不断地TCP retran , 如果一直收不到Server 的ack,大约重传15次,900秒左右。所以不是因为有 LVS 导致了这个问题,而是在某些场景下 LVS 有能力处理得更优雅,比如删除 RealServer的时候 LVS 完全可以感知这个动作并 reset 掉其上所有长连接

为什么在K8S 上这个问题更明显呢,K8S 讲究的就是服务不可靠,随时干掉POD(切断网络),如果干POD 之前能kill -9(触发reset)、或者close 业务触发断开连接那还好,但是大多时候啥都没干,有强摘POD、有直接隔离等等,这些操作都会导致对端只能TCP retran

怎么解决

业务方

业务方要对自己的请求超时时间有控制和兜底,不能任由一个请求长时间 Hang 在那里

比如JDBC URL 支持设置 SocketTimeout、ConnectTimeout,我相信其他产品也有类似的参数,业务方要设置这些值,不设置就是如上重现里演示的900多秒后才恢复

SocketTimeout

只要是连接有机会设置 SocketTimeout 就一定要设置,具体值可以根据你们能接受的慢查询来设置;分析、AP类的请求可以设置大一点

最重要的:任何业务只要你用到了TCP 长连接一定要配置一个恰当的SocketTimeout,比如 Jedis 是连接池模式,底层超时之后,会销毁当前连接,下一次重新建连,就会连接到新的切换节点上去并恢复

RFC 5482 TCP_USER_TIMEOUT

RFC 5482 中增加了TCP_USER_TIMEOUT这个配置,通常用于定制当 TCP 网络连接中出现数据传输问题时,可以等待多长时间前释放网络资源,对应Linux 这个 commit

TCP_USER_TIMEOUT 是一个整数值,它指定了当 TCP 连接的数据包在发送后多长时间内未被确认(即没有收到 ACK),TCP 连接会考虑释放这个连接。

打个比方,设置 TCP_USER_TIMEOUT 后,应用程序就可以指定说:“如果在 30 秒内我发送的数据没有得到确认,那我就认定网络连接出了问题,不再尝试继续发送,而是直接断开连接。”这对于确保连接质量和维护用户体验是非常有帮助的。

在 Linux 中,可以使用 setsockopt 函数来设置某个特定 socket 的 TCP_USER_TIMEOUT 值:

1
2
int timeout = 30000; // 30 seconds
setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, (char *)&timeout, sizeof(timeout));

在这行代码中,sock 是已经 established 的 TCP socket,我们将该 socket 的 TCP_USER_TIMEOUT 设置为 30000 毫秒,也就是 30 秒。如果设置成功,这个 TCP 连接在发送数据包后 30 秒内如果没有收到 ACK 确认,将开始进行 TCP 连接的释放流程。

TCP_USER_TIMEOUT 相较 SocketTimeout 可以做到更精确(不影响慢查询),SocketTimeout 超时是不区分ACK 还是请求响应时间的,但是 TCP_USER_TIMEOUT 要求下层的API、OS 都支持。比如 JDK 不支持 TCP_USER_TIMEOUT,但是 Netty 框架自己搞了Native 来实现对 TCP_USER_TIMEOUT 以及其它OS 参数的设置,在这些基础上Redis 的Java 客户端 lettuce 依赖了 Netty ,所以也可以设置 TCP_USER_TIMEOUT

原本我是想在Druid 上提个feature 来支持 TCP_USER_TIMEOUT,这样集团绝大部分业务都可以无感知解决掉这个问题,但查下来发现 JDK 不支持设置这个值,想要在Druid 里面实现设置 TCP_USER_TIMEOUT 的话,得像 Netty 一样走Native 绕过JDK 来设置,这对 Druid 而言有点重了

ConnectTimeout

这个值是针对新连接创建超时时间设置,一般设置3-5秒就够长了

连接池

建议参考这篇 《数据库连接池配置推荐》 这篇里的很多建议也适合业务、应用等,你把数据库看成一个普通服务就好理解了

补充下如果用的是Druid 数据库连接池不要用它来设置你的 SocketTimeout 参数,因为他有bug 导致你觉得设置了但实际没设置上,2024-03-16号的1.2.22这个Release 才fix,所以强烈建议你讲 SocketTimeout 写死在JDBC URL 中简单明了

OS 兜底

假如业务是一个AP查询/一次慢请求,一次查询/请求就是需要半个小时,将 SocketTimeout 设置太小影响正常的查询,那么可以将如下 OS参数改小,从 OS 层面进行兜底

1
2
net.ipv4.tcp_retries2 = 8
net.ipv4.tcp_syn_retries = 4

keepalive

keepalive 默认 7200秒太长了,建议改成20秒,可以在OS 镜像层面固化,然后各个业务可以 patch 自己的值;

如果一条连接限制超过 900 秒 LVS就会Reset 这条连接,但是我们将keepalive 设置小于900秒的话,即使业务上一直闲置,因为有 keepalive 触发心跳包,让 LVS 不至于 Reset,这也就避免了当业务取连接使用的时候才发现连接已经不可用被断开了,往往这个时候业务抛错误的时间很和真正 Reset 时间还差了很多,不好排查

在触发 TCP retransmission 后会停止 keepalive 探测

LVS

如果你们试用了aliyun的SLB,当摘除节点的时候支持你设置一个时间,过了这个时间 aliyun的SLB 就会向这些连接的客户端发 Reset 干掉这些流量,让客户端触发新建连接,从故障中快速恢复,这是一个实例维度的参数,建议云上所有产品都支持起来,管控可以在购买 aliyun的SLB 的时候设置一个默认值:

connection_drain_timeout

其它

神奇的900秒

上面阐述的长连接流量黑洞一般是900+秒就恢复了,有时候我们经常在日志中看到 CommunicationsException: Communications link failure 900秒之类的错误,恰好 LVS 也是设置的 900秒闲置 Reset

1
2
#ipvsadm -L --timeout
Timeout (tcp tcpfin udp): 900 120 300

为什么这个问题这几年才明显暴露

  • 工程师们混沌了几十年
  • 之前因为出现频率低重启业务就糊弄过去了
  • 对新连接不存在这个问题
  • 有些连接池配置了Check 机制(Check机制一般几秒钟超时 fail)
  • 微服务多了
  • 云上 LVS 普及了
  • k8s service 大行其道

我用的 7层是不是就没有这个问题了?

幼稚,你4层都挂了7层还能蹦跶,再说一遍只要是 TCP 长连接就有这个问题

极端情况

A 长连接 访问B 服务,B服务到A网络不通,假如B发生HA,一般会先Reset/断开B上所有连接(比如 MySQL 会去kill 所有processlist;比如重启MySQL——假如这里的B是MySQL),但是因为网络不通这里的reset、fin网络包都无法到达A,所以B是无法兜底这个异常场景, A无法感知B不可用了,会使用旧连接大约15分钟

最可怕的是 B 服务不响应,B所在的OS 还在响应,那么在A的视角 网络是正常的,这时只能A自己来通过超时兜底

总结

这种问题在 LVS 场景下暴露更明显了,但是又和LVS 没啥关系,任何业务长连接都会导致这个 900秒左右的流量黑洞,首先要在业务层面重视这个问题,要不以后数据库一挂掉还得重启业务才能从故障中将恢复,所以业务层面处理好了可以避免900秒黑洞和重启业务,达到快速从故障中恢复

再强调下这个问题如果去掉LVS/k8s Service/软负载等让两个服务直连,然后拔网线也会同样出现

最佳实践总结:

  • 如果你的业务支持设置 SocketTimeout 那么请一定要设置,但不一定适合分析类就是需要长时间返回的请求
  • 最好的方式是设置 OS 层面的 TCP_USER_TIMEOUT 参数,只要长时间没有 ack 就报错返回,但 JDK 不支持直接设置
  • 如果用了 ALB/SLB 就一定要配置 connection_drain_timeout 这个参数
  • OS 镜像层面也可以将 tcp_retries2 设置为5-10次做一个兜底
  • 对你的超时时间做到可控、可预期

假如你的业务不是 Java,而是 Python 的话,请参考Java/Python超时参数对照表:

功能 JDBC (Java) mysql-connector-python PyMySQL
连接建立超时 connectTimeout connect_timeout connect_timeout
读写操作超时 socketTimeout connection_timeout read_timeout/write_timeout
连接池等待超时 poolTimeout pool_timeout 需手动实现

相关故障和资料

ALB 黑洞问题详述:https://mp.weixin.qq.com/s/BJWD2V_RM2rnU1y7LPB9aw

数据库故障引发的“血案” :https://www.cnblogs.com/nullllun/p/15073022.html 这篇描述较细致,推荐看看

tcp_retries2 的解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
tcp_retries1 - INTEGER
This value influences the time, after which TCP decides, that
something is wrong due to unacknowledged RTO retransmissions,
and reports this suspicion to the network layer.
See tcp_retries2 for more details.

RFC 1122 recommends at least 3 retransmissions, which is the
default.

tcp_retries2 - INTEGER
This value influences the timeout of an alive TCP connection,
when RTO retransmissions remain unacknowledged.
Given a value of N, a hypothetical TCP connection following
exponential backoff with an initial RTO of TCP_RTO_MIN would
retransmit N times before killing the connection at the (N+1)th RTO.

The default value of 15 yields a hypothetical timeout of 924.6
seconds and is a lower bound for the effective timeout.
TCP will effectively time out at the first RTO which exceeds the
hypothetical timeout.

RFC 1122 recommends at least 100 seconds for the timeout,
which corresponds to a value of at least 8.

tcp_retries2 默认值为15,根据RTO的值来决定,相当于13-30分钟(RFC1122规定,必须大于100秒),但是这是很多年前的拍下来古董参数值,现在网络条件好多了,尤其是内网,个人认为改成 5-10 是比较恰当 azure 建议:https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-best-practices-connection ,Oracle RAC的建议值是3:https://access.redhat.com/solutions/726753

十年后数据库还是不敢拥抱NUMA-续篇

十年后数据库还是不敢拥抱NUMA-续篇

背景

十年后数据库还是不敢拥抱NUMA, 这篇经典的纠正大家对NUMA 认知的文章一晃发布快3年了,这篇文章的核心结论是:

  • 之所以有不同的NUMA Node 是不同的CPU Core 到不同的内存距离远近不一样所决定的,这是个物理距离
  • 程序跑在不同的核上要去读写内存可以让性能差异巨大,所以我们要尽量让一个程序稳定跑在一个Node 内
  • 默认打开NUMA Node 其实挺好的

写这个续篇是我收到很多解释,因为跨Node 导致性能抖动,所以集团在物理机OS 的启动参数里设置了 numa=off ,也就是不管BIOS 中如何设置,我们只要在OS 层面设置一下 numa=off 就能让程序稳定下来不再抖了!

我这几年也认为这是对的,只是让我有点不理解,既然不区分远近了,那物理上存在的远近距离(既抖动)如何能被消除掉的呢?

所以这个续篇打算通过测试来验证下这个问题

设置

BIOS 中有 numa node 设置的开关(注意这里是内存交错/交织),不同的主板这个BIOS设置可能不一样,但是大同小异,基本都有这个参数

img

Linux 启动引导参数里也可以设置numa=on(默认值)/off ,linux 引导参数设置案例:

1
2
#cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.10.0-327.x86_64 ro crashkernel=auto vconsole.font=latarcyrheb-sun16 vconsole.keymap=us BIOSdevname=0 console=tty0 console=ttyS0,115200 scsi_mod.scan=sync intel_idle.max_cstate=0 pci=pcie_bus_perf ipv6.disable=1 rd.driver.pre=ahci numa=on nosmt=force

注意如上的 numa=on 也可以改为 numa=off

看完全置篇要记住一条铁律:CPU到内存的距离是物理远近决定的,你软件层面做些设置是没法优化这个距离,也就是没法优化这个时延 (这是个核心知识点,你要死死记住和理解,后面的一切实验数据都回过头来看这个核心知识点并揣摩)

实验

测试机器CPU,如下是BIOS numa=on、cmdline numa=off所看到的,一个node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 96
On-line CPU(s) list: 0-95
Thread(s) per core: 2
Core(s) per socket: 24
Socket(s): 2
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz
Stepping: 4
CPU MHz: 2500.000
CPU max MHz: 3100.0000
CPU min MHz: 1000.0000
BogoMIPS: 4998.89
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 33792K
NUMA node0 CPU(s): 0-95

测试工具是lmbench,测试命令:

1
for i in $(seq 0 6 95); do echo core:$i; numactl -C $i -m 0 ./bin/lat_mem_rd -W 5 -N 5 -t 64M; done >lat.log 2>&1

上述测试命令始终将内存绑定在 node0 上,然后用不同的物理core来读写这块内存,按照前一篇 这个时延肯定有快慢之分

BIOS和引导参数各有两种设置方式,组合起来就是四种,我们分别设置并跑一下内存时延,测试结果:

BIOS ON BIOS OFF
cmdline numa=on(默认值) NUMA 开启,内存在Node内做交织,就近有快慢之分 bios 关闭后numa后,OS层面完全不知道下层的结构,默认全局内存做交织,时延是个平均值
cmdline numa=off 交织关闭,效果同上 同上

测试原始数据如下(测试结果文件名 lat.log.BIOSON.cmdlineOff 表示BIOS ON,cmdline OFF ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//从下面两组测试来看,BIOS层面 on后,不管OS 层面是否on,都不会跨node 做交织,抖动存在
//BIOS on 即使在OS层面关闭numa也不跨node做内存交织,抖动存在
//默认从内存高地址开始分配空间,所以0核要慢
#grep -E "core|64.00000" lat.log.BIOSON.cmdlineOff
core:0 //第0号核
64.00000 100.717 //64.0000为64MB, 100.717 是平均时延100.717ns 即0号核访问node0 下的内存64MB的平均延时是100纳秒
core:24
64.00000 68.484
core:48
64.00000 101.070
core:72
64.00000 68.483
#grep -E "core|64.00000" lat.log.BIOSON.cmdlineON
core:0
64.00000 67.094
core:24
64.00000 100.237
core:48
64.00000 67.614
core:72
64.00000 101.096

//从下面两组测试来看只要BIOS off了内存就会跨 node 交织,大规模测试下内存 latency 是个平均值
#grep -E "core|64.00000" lat.log.BIOSOff.cmdlineOff //BIOS off 做内存交织,latency就是平均值
core:0
64.00000 85.657 //85 恰好是最大100,最小68的平均值
core:24
64.00000 85.741
core:48
64.00000 85.977
core:72
64.00000 86.671

//BIOS 关闭后numa后,OS层面完全不知道下层的结构,默认一定是做交织
#grep -E "core|64.00000" lat.log.BIOSOff.cmdlineON
core:0
64.00000 89.123
core:24
64.00000 87.137
core:48
64.00000 87.239
core:72
64.00000 87.323

从数据可以看到在BIOS 设置ON后,无论 OS cmdline 启动参数里是否设置了 ON 还是 OFF,内存延时都是抖动且一致的(这个有点诧异,说好的消除抖动的呢?)。如果BIOS 设置OFF后内存延时是个稳定的平均值(这个比较好理解)

疑问

  • 内存交错时为什么 lmbench 测试得到的时延是平均值,而不是短板效应的最慢值?

测试软件只能通过大规模数据的读写来测试获取一个平均值,所以当一大块内存读取时,虽然通过交织大块内存被切分到了快慢物理内存上,但是因为规模大慢的被平均掉了。(欢迎内核大佬指正)

  • 什么是内存交织?

我的理解假如你有8块物理内存条,如果你有一个int 那么只能在其中一块上,如果你有1MB的数据那么会按cacheline 拆成多个块然后分别放到8块物理内存条上(有快有慢)这样带宽更大,最后测试得到一个平均值

如果你开启numa那么只会就近交织,比如0-3号内存条在0号core所在的node,OS 做内存交织的时候只会拆分到这0-3号内存条上,那么时延总是最小的那个,如上测试中的60多纳秒。

这个问题一直困扰了我几年,所以我最近再次测试验证了一下,主要是对 BIOS=on 且 cmdline=off 时有点困扰

Intel 的 mlc 验证

测试参数: BIOS=on 同时 cmdline off

Intel 的 mlc 验证下,这个结果有点意思,latency稳定在 145 而不是81 和 145两个值随机出现,应该是mlc默认选到了0核,对应lmbench的这组测试数据(为什么不是100.717, 因为测试方法不一样):

1
2
3
4
5
6
7
8
9
10
11
12
//如下是
//从下面两种测试来看,BIOS层面 on后,不管OS 层面是否on,都不会跨node 做交织,抖动存在
//BIOS on 即使在OS层面关闭numa也不跨node做内存交织,抖动存在
#grep -E "core|64.00000" lat.log.BIOSON.cmdlineOff
core:0
64.00000 100.717
core:24
64.00000 68.484
core:48
64.00000 101.070
core:72
64.00000 68.483

此时对应的mlc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#./mlc
Intel(R) Memory Latency Checker - v3.9
Measuring idle latencies (in ns)...
Numa node
Numa node 0
0 145.8 //多次测试稳定都是145纳秒

Measuring Peak Injection Memory Bandwidths for the system
Bandwidths are in MB/sec (1 MB/sec = 1,000,000 Bytes/sec)
Using all the threads from each core if Hyper-threading is enabled
Using traffic with the following read-write ratios
ALL Reads : 110598.7
3:1 Reads-Writes : 93408.5
2:1 Reads-Writes : 89249.5
1:1 Reads-Writes : 64137.3
Stream-triad like: 77310.4

Measuring Memory Bandwidths between nodes within system
Bandwidths are in MB/sec (1 MB/sec = 1,000,000 Bytes/sec)
Using all the threads from each core if Hyper-threading is enabled
Using Read-only traffic type
Numa node
Numa node 0
0 110598.4

Measuring Loaded Latencies for the system
Using all the threads from each core if Hyper-threading is enabled
Using Read-only traffic type
Inject Latency Bandwidth
Delay (ns) MB/sec
==========================
00000 506.00 111483.5
00002 505.74 112576.9
00008 505.87 112644.3
00015 508.96 112643.6
00050 574.36 112701.5

当两个参数都为 on 时的mlc 测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#./mlc
Intel(R) Memory Latency Checker - v3.9
Measuring idle latencies (in ns)...
Numa node
Numa node 0 1
0 81.6 145.9
1 144.9 81.2

Measuring Peak Injection Memory Bandwidths for the system
Bandwidths are in MB/sec (1 MB/sec = 1,000,000 Bytes/sec)
Using all the threads from each core if Hyper-threading is enabled
Using traffic with the following read-write ratios
ALL Reads : 227204.2
3:1 Reads-Writes : 212432.5
2:1 Reads-Writes : 210423.3
1:1 Reads-Writes : 196677.2
Stream-triad like: 189691.4

说明:mlc和 lmbench 测试结果不一样,mlc 时81和145,lmbench测试是68和100,这是两种测试方法的差异而已,但是快慢差距基本是一致的

结论

在OS 启动引导参数里设置 numa=off 完全没有必要、也不能解决抖动的问题,反而设置了 numa=off 只能是掩耳盗铃,让用户看不到 NUMA 结构

流量一样但为什么CPU使用率差别很大

流量一样但为什么CPU使用率差别很大

这是我翻到2013年的一篇文章,当时惊动所有公司高人,最后分析得知原因后所有人都跪拜,你要知道那是2013年,正好10年过去了,如果是现在用我们星球的理论去套的话,简直不要太容易

问题描述

同样大小内存、同样的CPU、同样数量的请求、几乎可以忽略的io,两个机器的load却差异挺大。一个机器的load是12左右,另外一个机器却是30左右

你可以理解这是两台一摸一样的物理机挂在一个LVS 下,LVS 分发流量绝对均衡

所以要找出为什么?

分析

两台机器的资源使用率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//load低、CPU使用率低 的物理机,省略一部分核
Cpu0 : 67.1%us, 1.6%sy, 0.0%ni, 30.6%id, 0.0%wa, 0.0%hi, 0.7%si, 0.0%st
Cpu1 : 64.1%us, 1.6%sy, 0.0%ni, 34.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu2 : 63.0%us, 1.6%sy, 0.0%ni, 35.4%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu3 : 60.0%us, 1.3%sy, 0.0%ni, 38.4%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Cpu4 : 59.8%us, 1.3%sy, 0.0%ni, 37.9%id, 1.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu5 : 56.7%us, 1.0%sy, 0.0%ni, 42.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu6 : 63.4%us, 1.3%sy, 0.0%ni, 34.6%id, 0.0%wa, 0.0%hi, 0.7%si, 0.0%st
Cpu7 : 62.5%us, 2.0%sy, 0.0%ni, 35.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu8 : 58.5%us, 1.3%sy, 0.0%ni, 39.5%id, 0.0%wa, 0.0%hi, 0.7%si, 0.0%st
Cpu9 : 55.8%us, 1.6%sy, 0.0%ni, 42.2%id, 0.3%wa, 0.0%hi, 0.0%si, 0.0%st

//load高、CPU使用率高 的物理机,省略一部分核
Cpu0 : 90.1%us, 1.9%sy, 0.0%ni, 7.1%id, 0.0%wa, 0.0%hi, 1.0%si, 0.0%st
Cpu1 : 88.5%us, 2.9%sy, 0.0%ni, 8.0%id, 0.0%wa, 0.0%hi, 0.6%si, 0.0%st
Cpu2 : 90.4%us, 1.9%sy, 0.0%ni, 7.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu3 : 86.9%us, 2.6%sy, 0.0%ni, 10.2%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Cpu4 : 87.5%us, 1.9%sy, 0.0%ni, 10.2%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Cpu5 : 87.3%us, 1.9%sy, 0.0%ni, 10.5%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Cpu6 : 90.4%us, 2.9%sy, 0.0%ni, 6.4%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Cpu7 : 90.1%us, 1.9%sy, 0.0%ni, 7.6%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Cpu8 : 89.5%us, 2.6%sy, 0.0%ni, 6.7%id, 0.0%wa, 0.0%hi, 1.3%si, 0.0%st
Cpu9 : 90.7%us, 1.9%sy, 0.0%ni, 7.4%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

可以分析产出为什么低,检查CPU是否降频、内存频率是否有差异——检查结果一致

10年前经过一阵 perf top 看热点后终于醒悟过来知道得去看 IPC,也就是相同CPU使用率下,其中慢的机器产出低了一半,那么继续通过perf看IPC:

img

可以看到两台机器的IPC是 0.3 VS 0.55,和CPU使用率差异基本一致,instructions几乎一样(意味着流量一样,LVS 不背锅),但是处理同样的instructions 用掉的cpu-clock 几乎差了一倍,这应该是典型的内存时延大了一倍导致的。IPC 大致等于 instrunctions/cpu-clock (IPC:instrunctions per cycles)

经检查这两台物理机都是两路,虽然CPU型号/内存频率一致,但是主板间跨Socket的 QPI带宽差了一倍(主板是两个不同的服务商提供)。可以通过绑核测试不同Socket/Node 下内存时延来确认这个问题

这是同一台机器下两个Socket 的内存带宽,所以如果跨Socket 内存访问多了就会导致时延更高、CPU使用率更高

img

总结

在今天我们看到这种问题就很容易了,但我还是要感叹一下在入门前简直太神奇,入门后也不过尔尔,希望你也早点入门。

第一:向CPU要产出,同样的使用率产出得一样,不一样的话肯定是偷懒了,偷懒的直接证据就是 IPC 低了,导致IPC 低最常见的是内存时延高(内存频率、跨Node/Socket 等,或者内存碎片);延伸阅读:性能的本质 IPC ,也是本星球唯二的必读实验

第二:测试工具很完善了,lmbench , 怎么用lmbench 可以看这篇 ; 怎么使用perf Perf IPC以及CPU性能

,学成后装逼可以看 听风扇声音来定位性能瓶颈

我以前说过每个领域都有一些核心知识点,IPC 就是CPU领域的核心知识点,和tcp的rmem/wmem 一样很容易引导你入门

计算机专业里非要挑几个必学的知识点肯定得有计算机组成原理,但计算机组成原理内容太多,都去看也不现实,况且很多过时的东西,那么我只希望你能记住计算机组成原理里有个最核心的麻烦:内存墙——CPU 访问内存太慢导致了内存墙是我们碰到众多性能问题的最主要、最核心的一个,结合今天这个案例掌握IPC后再来学内存墙,再到理解计算机组成原理就对了,从一个实用的小点入手。

计算机专业里除掉组成原理(有点高大上,没那么接地气),另外一个我觉得最有用的是网络——看着low但是接地气,问题多,很实用

2011年的文章:

详解服务器内存带宽计算和使用情况测量

更好的工具来发现类似问题:https://github.com/intel/numatop

img

如果你觉得看完对你很有帮助可以通过如下方式找到我

find me on twitter: @plantegg

知识星球:https://t.zsxq.com/0cSFEUh2J

开了一个星球,在里面讲解一些案例、知识、学习方法,肯定没法让大家称为顶尖程序员(我自己都不是),只是希望用我的方法、知识、经验、案例作为你的垫脚石,帮助你快速、早日成为一个基本合格的程序员。

争取在星球内:

  • 养成基本动手能力
  • 拥有起码的分析推理能力–按我接触的程序员,大多都是没有逻辑的
  • 知识上教会你几个关键的知识点
image-20240324161113874

无招胜有招--一周年总结

无招胜有招–一周年总结

大家抱着美好和雄赳赳的目标来到这个知识星球,开始的时候兴奋地以为找到了银弹(其实银弹是有的,在文章最后),经过一段时间后大概率发现没什么变化,然后就回到了以前的老路子上,我觉得关键问题是你没获取到星球的精华,所以这篇我打算反复再唠叨一下

知识效率 工程效率

虽然我们现在通过这篇《知识效率 工程效率》知道了两者的差别, 但是还是需要记住通过积累可以将我们的学习能力从工程效率升级到知识效率(厚积薄发),大部分时候没有做到薄发,是因为你以为理解了、积累了实际没理解

核心知识点

尽力寻找每个领域的核心知识点,核心知识点的定义就是通过一两个这样的知识点能撬动对整个领域的理解,也就是常说的纲挈目张

比如网络领域里:一个网络包是怎么流转的+抓包。假如你理解网络包的流转后再去看LVS 负载均衡的原理你就发现只需要看一次你就能很好掌握LVS各个负载均衡的本质,而在这之前你反复看反复忘。掌握了这个知识点基本就可以通关整个领域,剩下的只是无招胜有招碰到一个挨个积累的问题了。

比如CPU领域理解超线程+IPC+会用perf和内存延时,理解超线程的本质是为什么一个核能干两个核的工作(这和操作系统的分时多任务背后原理是想通的),那是因为我们的程序没法吃满流水线(也就是没法用完一个核的计算能力,用IPC去衡量),没吃满闲置的时候就可以虚拟给另外一个进程用,比如CPU 跑起来最高IPC都能到4,但是无论你找一个Java还是MySQL 去看他们的IPC基本都在1以内,纯计算场景的IPC会高一点,IPC 可以到4但只跑到1的话也就是只用满了25%的能力,那当然可以再虚出来一个超线程提高效率。IPC 之所以低就是因为内存延时大,这么多年CPU的处理能力一直按摩尔定律在提升但是内存延时没有怎么提升,导致基本上我们常见的业务场景(Nginx/MySQL/Redis 等)都是CPU在等从内存取数据(所以搞了L1、L2、L3一堆cache)。

发散一下或者说留个作业你去看看NUMA 的原理或者说本质就是为了让CPU知道就近分配读取内存以提升效率

你看整本计算机组成原理+性能的本质都在这一个知识点的范围内进行延伸和突破

如果你发现一个核心知识点也欢迎写成博客文章分享出来

读日志、错误信息

我的经验只是大概20%左右的程序员会去耐心读别人的日志、报错信息,大部分摊摊手求助、放弃了

日志是最好的学习机会,我知道别人的日志写得很烂,但是你要能耐心多琢磨一点就会比别人更专业一点

对知识的可观测性

抓包、perf的使用这些平时要多积累,这点没有捷径,一个好的工程师肯定有一堆好的锤子、瑞士军刀、工具包的。在你掌握了知识点后要转化为工作效率,就得多积累这些工具,很多次我们碰到一个好的问题没分析出来是因为我们这种没有门槛的积累不够导致放弃了

比如需要抓包确认下,不会,一看tcpdump 一堆参数头疼放弃;比如想要知道长连接还是短连接,或者自己设置的长连接有没有生效,不会用netstat -o 这个参数去确认等;比如要下载个源码自己make/install 中间报了几个错误不仔细看放弃;

反过来回到我们所说的工程效率,就是靠这些工具帮你实现可视、可以触摸,网络之所以大多数同学在大学都学过但是最后基本学懂,就是因为这些网络的东东你只看理论很难立即,但是让你抓过一次包分析下就会恍然大悟——这就是关键门槛你能跨过去

好习惯

在星球里我更希望你带走一个好的习惯而不是一个具体知识点,虽然星球里的具体知识点、案例胜过很多教材,但他们总有过时、用不上的时候,唯有好的习惯可以跟随你,帮你实现无招胜有招

记笔记

放低身段,不要高估自己的能力(认为自己是知识效率),放低后你要怎么做呢:记笔记、记笔记、记笔记

只要是你在学习就要或者看书、看资料的时候觉得自己有点通透了,赶紧记录下来,因为大概率一个星期你就忘了,半年你就完全不记得自己以前看过一次了,我好多次看到一篇好文章就感叹自己学到了,兴奋地拉到文章最后想去评论下,结果发现居然有了自己的评论在下面 :)

动手

动手,看到后理解了,也记了笔记,其实最好还是要自己去重现,记下自己看到的现象和理解,动手又会有一堆门槛,搭环境、客观则、怎么验证等等,这个时候我前面说的可观测性里面积累的一大堆工具可以让你如有神助、重现起来效率就是比别人高

汇总输出

最后笔记记完还没完,笔记基本是零散的,你反复积累后到了一定的时机就是要把他们总结汇总成一篇完整度较高的博客文章,这里当然有自己的虚荣心在这里,但更多的是为了自己查询方便,有了新的理解或者使用姿势我经常更新补充10年前的博客文章,不会写一篇新的,这个补充知识让我的知识结构更完善,不是为了多发一篇博文,我现在解决问题、使用工具基本要靠翻自己的博客文章照着操作

慢就是快、少就是多

往往我们喜欢求快,以为自己一看就懂;求多以为自己越看的多越厉害

不要等着时间流投喂

看这篇置顶:https://t.zsxq.com/14Yel6KBg

纲举目张

对公司的业务、一个软件的运转流程都要尽量做到理解

比如学MySQL 要尽量知道从一条SQL 怎么进来,进行哪些处理后得到了查询结果;比如前面讲过的一个网络包是怎么到达对端的;比如你们公司的请求是怎么从客户端到达服务端(中间经过了LVS、Nginx吗),服务端又是那些服务得依赖和调用,有没有Redis、MQ、Database,最后数据又是怎么返回的,我知道这在一个公司很难(屎山很复杂),但目前没有更好的方法让你快速掌握并立足

为什么出现问题后总有一两个人很快能猜出来问题可能在哪个环节,这一部分是经验但更多的是对系统的了解,你都不知道有Redis存在一旦出错了你肯定猜不到Redis这里来

可以看看我之前说的实习生的故事,完全真实哈:

讲一个我碰到的实习生的事情

北邮毕业直接后直接到我司实习

特点:英语好、动手能力强、爱琢磨,除了程序、电脑没有其它爱好 :)

实习期间因为英语好把我司文档很快就翻烂了,对产品、业务逻辑的理解基本是顶尖的

实习期间很快成为所有老员工的红人,都离不开他,搭环境、了解业务流程

因为别人的习惯都是盯着自己眼前的这一趴,只有他对业务非常熟悉

实习后很快就转正了,又3年后transfer 去了美国总部

连女朋友都是老员工给牵线的,最后领证一起去了美国。为啥老员工这么热情,是大家真心喜欢他

再看看张一鸣自述的第一年的工作:

img

总结

我前面所说的我也没做太好,希望大家能做得更好,我第一次感受无招胜有招就是故事一里面,到故事二过去差不多10年,这10年里我一直在琢磨怎么才能无招胜有招,也有在积累,但是花了10年肯定效率不算高,所以在星球里我希望通过我的经验帮你们缩短一些时间

上面讲再多如果你只是看看那根本还是没用,买再多的课也没用,关键是看触动后能否有点改变。你可以从里面试着挑几个你认为容易操作,比如记笔记、比如不要等着时间流投喂,或者有感触的试试先改变或者遵循下看看能不能获得一些变化进而形成正向循环

或者从评论里开始说说你星球这一年真正有哪些改变、学到了啥、你的感悟,不方便的也可以微信我私聊一下

这篇就当成整个星球学习的一个总结吧

网球肘 过劳性(持续)肌腱病的治疗

网球肘 过劳性(持续)肌腱病的治疗

因为长期打球,导致手肘部分疼痛难耐,2024年1月开始进行了长时间的休息期,中间2024的2月是春节,所以总共修了快2个月,还不见好,于是去医院,其实医院给的治疗方案也不好,但是医师告诉了我一个关键词这个病叫:网球肘

知道关键字后就开始了自我寻求治疗方案的过程,记下来供参考,到2024年3月14号,最近两周多次打球验证我的网球肘基本好了,所以说一下治疗过程

个人总结

网球肘的核心是肌肉过劳发炎了,所以关键是如何消炎

一定要用:氟比洛芬凝胶贴膏 ,而且每天两贴尽量不要断,期间通过大拇指使劲按压疼痛部分来感受验证的减轻,一般连续贴3-5天会有明显的效果,如果无效请去医院

口服消炎药也可以试试,我估计针对性不强(瞎猜的,希望你试试后来告诉我)。至于体外冲击波可以尝试尝试,我个人的经验觉得还不足以证明其有效

后面的可以不用看了

治疗

网球肘已经有几个月了,开始我没在意以为就是肌肉劳累,休息休息就会好,直到过年的时候我真正歇了一个多月,过完年偶尔一用力居然又开是疼,让我计划去医院看看,之前自己在社区医院开过几盒:氟比洛芬凝胶贴膏

image-20240305141525956

(家中请常备这个药,膏药里的神奇)

【适应症】
下列疾病及症状的镇痛、消炎:
骨关节炎、肩周炎、肌腱及腱鞘炎、腱鞘周围炎、肱骨外上髁炎 ( 网球肘 )、肌肉痛、外伤所致肿胀、疼痛

过年期间自己也偶尔贴一下,但是效果不明显(应该是没有连续贴导致的效果不好)。

这次去医院正规想看看,但是大医院挂不上号,于是去了一个小医院(社区医院推荐的,说这家别的不行,刚好看运动医学还不错),到医院大夫一听就笑着问我知不知道有一种病叫:网球肘。这是我第一次听说这个病,大夫用大拇指按压我的伤口附近,确实非常疼,结合我经常打球基本确诊。

然后给我开了两次体外冲击波物理治疗,当场治疗了一次,过程中很痛,打完的当时再按压就不疼了,但是过几个小时还是照旧(这也在医师的预料中),给我开了两次这个治疗,我只去了一次

体外冲击波疗法(extracorporeal shock wave therapy, ESWT)是一种非侵入性、安全、有效治疗多种疾病的方法,在临床多个学科中得到了广泛应用,但临床应用不规范、治疗关键技术不一致、治疗方案不统一、培训体系不健全等问题严重制约了ESWT的临床推广应用。

https://rs.yiigle.com/CN101658202302/1459029.htm#:~:text=%E4%BD%93%E5%A4%96%E5%86%B2%E5%87%BB%E6%B3%A2%E7%96%97%E6%B3%95%EF%BC%88extracorporeal%20shock,ESWT%E7%9A%84%E4%B8%B4%E5%BA%8A%E6%8E%A8%E5%B9%BF%E5%BA%94%E7%94%A8%E3%80%82

回到家我就开始了对“网球肘”的学习,中间找到这篇最关键的经验贴【你一定要看】,我把这里面最有价值的引用一下:

比较对症的治疗方法是,内服 洛索洛芬钠片,外贴 氟比洛芬凝胶贴膏(商标是泽普思),尤其要注意用量和时机

  • 洛索洛芬钠片——我这次没吃这个

    • 一日三次,每次两片(60mg/片)
    • 饭后服用(切记!
  • 氟比洛芬凝胶贴膏——这点最重要,我不再像以前一样偶尔贴,而是连续一周每天两贴

    • 每次一帖,白天/晚上 各一帖
    • 除了洗澡之外,尽量连续贴

按照上面的做法,经过5天后我的网球肘真的神奇地好了,中间还阳了3天(所以第二次冲击波治疗我也没去)

经验

我的判断是网球肘消炎很重要,应该还是氟比洛芬凝胶贴膏起了关键作用,但是要注意:连续贴一周,每天两贴

至于冲击波是否有效果,我目前觉得可能有效果,但是证据还不够

知道这个病的名字很重要,这样就有了搜索关键字,看别人描述相对来说我这次不算严重

UpToDate 临床顾问

知道名字后,我在淘宝上购买了 UpToDate 临床顾问论文库的账号(收录了几乎所有的医学论文,但是只对收费会员开放),专业点说如果你好好研究 UpToDate,再结合自身状况可以得到比很多专业医师更专业的治疗

但是这次查到的治疗方案都是普通的消炎、镇痛(对乙氨基酚)等,但是不妨碍你下次可以继续到这里查,一般买个3天的账号才几块钱

image-20240305145408804

另外也推荐大家看默沙东手册(完全免费,有网页和app版本):

image-20240305145706453

自我检查

自己按压疼痛的地方确认在什么地方,结合平时的运动和习惯,是否恢复也可以通过按压和发力来确认

非甾体类抗炎药(NSAID)

非甾体抗炎药(non-steroidal anti-inflammatory drugs,NSAIDs)又称非类固醇抗炎药,简称非甾体类,是一类具有解热镇痛效果的药物,在施用较高剂量时也具有消炎作用

NSAID 包括布洛芬(Advil、Motrin IB 等)、萘普生纳(Aleve、Anaprox DS 等)、双氯芬酸钠和塞来昔布(Celebrex)

非甾体抗炎药中,属阿司匹林伊布洛芬甲芬那酸萘普生最为著名,在绝大多数国家都可作为非处方药销售[4]

对乙酰氨基酚因其抗炎作用微弱,而通常不被归为非甾体抗炎药,它主要通过抑制分布在中枢神经系统的环氧合酶-2,以减少前列腺素的生成,从而缓解疼痛,但由于环氧合酶-2在周边组织中数量较少,因此作用微弱

抗炎治疗

抗炎治疗 — 尽管抗炎治疗多年来都是肘部肌腱病的主要疗法,但支持性证据仅来自成功个案和极少数研究。在医学界对肌腱病有了科学认识之后,抗炎疗法对肘部肌腱病和其他慢性退行性肌腱病的作用也出现了争议。抗炎治疗包括冰敷、NSAID、离子透入疗法和注射糖皮质激素。对于LET,冰敷联合离心力量及柔韧性训练并未优于单纯离心力量训练[51]。(参见上文[‘病理生理学’](http://www.uptodate.zd.hggfdd.top/contents/zh-Hans/elbow-tendinopathy-tennis-and-golf-elbow?search=Tennis Elbow 冲击波&source=search_result&selectedTitle=3~150&usage_type=default&display_rank=3#H4))

体外冲击波疗法(extracorporeal shock wave therapy, ESWT)

体外震波治疗和其他电物理疗法 — 声波已用于治疗慢性LET。总体而言,支持体外震波治疗(extracorporeal shock wave therapy, ESWT)和其他“电物理”疗法的证据并不令人信服,所以我们不予以推荐[82]。该操作通常会令患者不适,但有些研究显示ESWT有一定益处[83],但也有许多研究未发现ESWT有益[84,85]。

体外冲击波疗法临床应用中国疼痛学专家共识 2023版

定义

“网球肘 ”(TenniS Elbow)又名肱骨外上髁炎 (1ateralepicondylitis),以网球运动 员发病率高 而得名

广义 的网球肘可分 为具有不同临床特点的四个类型 :

  1. 外侧网球肘 :亦称肱骨外上髁炎 ,即经典的网 球肘 ,主要累及附于肱骨外上髁的桡侧腕短伸肌腱起 点。
  2. 内侧网球肘:亦称肱骨内上髁炎或高尔夫球肘, 主要 累及附于 肱骨 内上髁 的屈肌 和旋前 圆肌腱 起 点。
  3. 后侧网球肘 :亦称三头肌腱炎 。
  4. 混合型网球 肘 :内外侧网球肘同时发生 ,并不少见

读懂医疗发票

自付二:对有自付的药品、检查费收取自费部分;比如药品:10%或50%;检查费:8%;材料费:30%;

自付一:根据下图,报销比例是90%,也就是你还要出总医药费的90%;但是要注意总医药费要减掉自付二的部分

举例:一张发票开了一盒泰诺(酚麻美敏片) 13.47块(乙类清单 10%自付),还有一盒没有无自付的头孢 5.17块,共18.64

最后发票显示自付二:1.35 就是13.4710% ——这个10%是因为该药有部分自费,自付一:1.73 是 (18.64-(13.4710%))*10% ——这个10%就是达到起付线1800后报销90%

如果你没有达到起付线,就是100%自付,那么不存在自付二,付款金额全部显示为自付一

职工基本医疗保险门(急)诊待遇标准

痛风

痛风是由于血中尿酸含量过高(高尿酸血症)而导致尿酸盐结晶沉积在关节内的疾病。沉积的结晶导致关节内和关节周围出现疼痛性炎症的发作。通常具有家族遗传性

痛风在男性中的发病率高于女性。男性痛风患者较女性常见,通常发生在中年男性和绝经期后的女性。很少发生于年轻人,但如果小于 30 岁的人发生痛风,其病情一般较重。

食物和痛风没关系。如果发作了就吃止痛药。不疼的时候吃非布司他(找医生开,这是处方药)。定期检查尿酸是否有降下来。 然后非常容易被忽视的一点是注意别喝含糖饮料,干脆戒掉。

风湿性多肌痛

风湿性多肌痛是关节滑膜的炎症,是一种能引起颈、肩、髋部肌肉疼痛和僵硬的疾病。

风湿性多肌痛发病年龄在 55 岁以上,原因尚不清楚。女性的患病率较男性高。风湿性多肌痛的病因尚不清楚。风湿性多肌痛可与 巨细胞(颞)动脉炎同时出现,也可在它之前或之后出现。有学者认为这两种疾病是同一种病变的不同表现。风湿性多肌痛似乎比巨细胞动脉炎更常见。

类风湿性关节炎 (RA)

类风湿性关节炎是一种炎症性关节炎,表现为关节的炎症,受累关节通常包括手脚关节,可导致关节肿胀、疼痛以及常常遭到破坏。

从一道面试题谈起

从一道面试题谈起

这是一道BAT 的面试题,针对的是应届生,其实我觉得这种题目也适合所有面试人,比刷算法题、八股文要有用、实际多了

题目

给你几天时间自己在家可以借助任何资源用测试工具Sysbench 完成一次MySQL数据的性能测试,并编写测试报告(自行搭建数据库)

sysbench压MySQL常用有只读、读写、只写、update等6个场景

结果

这个候选人把他的结果发给我看了,我看完一惊要坏事,这个结果估计要不及格了

他用 sysbench 跑了一下只读、读写、只写等场景然后截图就没有了!

image-20230908223348050

(如上图,大概就是6/7个这样的截图就没有了!)

我看到这个结果是很震惊的,你希望面试官挨个去看截图?最起码要有测试结果表格当做结论汇总吧

如果你不知道怎么做可以先去搜一下别人做的测试报告,你可以按照别人的测试流程完全走一遍,基本算是模仿,要有结论的话也能得60分。

60分的答案

每个场景增加1/8/16/32等并发,然后按照6个场景不同并发做成一个表格,并观察rt、cpu的指标最后汇总形成图表、给出结论分析,比如拐点在哪里、为什么

我觉得这个面试题好就好在这里的分析可以无穷展开,适合新手也适合多年的老手,任何结论理由你都可以写上去,只要有理有据有分析

80分的答案

给自己出一个拟题,比如对比5.7和8.0的性能差异,8.0相对5.7在哪些场景有优化、优劣势,比如这个测试报告

比如官方说的8.0在全局锁、pagesize等方面有些有优化,那么就针对性地设置场景来测试这些功能。

比如这是如上链接测试报告中间有数据图表:

image-20230908224210461

最后有结论和分析:

  • the main impact in the given IO-bound OLTP_RW workload is only DBLWR and nothing else !
  • and again, if your workload has more than 32 concurrent users sessions + using a very fast flash storage..
  • so far, impatient to see DBLWR fixed in MySQL 8.0 ;-))
  • using 4K page size is absolutely to consider for any IO-bound workloads !
  • NOTE : every Linux vendor today is claiming that 4K IO writes in Linux are atomic ! – and if this is really true for your platform, then you can safely disable DBLWR if you’re using 4K page and already reach x2 times higher TPS with MySQL 8.0 today in the given IO-bound OLTP_RW or any similar ! ;-)) – the same x2 times higher TPS was also observed on IO-bound TPCC even with an old SSD drive !
  • while if your workload is not IO-bound (having active dataset mostly cached in BP, none or very low IO reads) – then DBLWR is not your main impact ! – you may always tune your MySQL instance to make it mostly “invisible”..
  • Binlog – is the main impact in this case.. Unfortunately it’s another old historical PITA in MySQL Server, and it’s largely a time now to get it fixed (or come with a more advanced alternative).. – “nature is always finding its way”, so let’s see..
  • no comments on MariaDB 10.3 performance.. – but a good live example that just copying InnoDB code from MySQL 5.7 is not enough to get it running right..

之所以有80分是因为超出面试官的期待,给出了一个更高级的结论,面试官肯定很愿意约你过去谈谈

还有没有更高的分

也许有,但是不好说,80分那个就是优秀很好了,挖掘能力强的应届生会搞出来(肯定没有这么细致和周到,但是有几个关键点的结论就够80分了),再想出彩一点可以根据这个我的星球案例 https://plantegg.github.io/2021/05/14/%E5%8D%81%E5%B9%B4%E5%90%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%98%E6%98%AF%E4%B8%8D%E6%95%A2%E6%8B%A5%E6%8A%B1NUMA/ 去搞几台物理机开关NUMA 验证一下,然后给一个对性能影响结果的测试数据报告

或者我博客这篇也行 https://plantegg.github.io/2019/12/16/Intel%20PAUSE%E6%8C%87%E4%BB%A4%E5%8F%98%E5%8C%96%E6%98%AF%E5%A6%82%E4%BD%95%E5%BD%B1%E5%93%8D%E8%87%AA%E6%97%8B%E9%94%81%E4%BB%A5%E5%8F%8AMySQL%E7%9A%84%E6%80%A7%E8%83%BD%E7%9A%84/,找不同Intel机器验证

给出不同的MySQL参数在不同Intel 芯片下性能的差异报告:

image-20221026153750159

这种结论抛出去肯定会让面试官惊到,并对你刮目相看,至少说明你能在某个点上可以钻研很深,到哪里都要的是火车头,而不是普通工程师。

总结

从一个简单的面试题就可以看出应试人员的主观能动性,最起码你要会抄,先去抄别人的测试报告,然后验证一遍然后思考清楚每一个数据的原因(面试大概率会问)

但是大部分工程师都想临时抱佛脚,其实面试官可能会知道你不懂,但是希望看到给你几天你的深度挖掘和学习能力

最后可以从一个问题深挖、总结能力上能看出来候选人的天花板上限,而我们大部分时候都是凑合可以、又不是不能用,逼着自己向前精进一步总是很难的。

必读 成长路径

必读 成长路径

我的星球介绍

这篇是关于我星球里的内容、目标以及如何达到这个目标的一些概述

星球目标

本星球致力深度分析各种程序员领域疑难案例,通过案例带动对基础核心知识的理解,同时强化动手能力

一年星球没法让大家称为顶尖程序员(我自己都不是),只是希望用我的方法、知识、经验、案例作为你的垫脚石,帮助你快速、早日成为一个基本合格的程序员。

必会技能

在星球一年的时间你能学到什么(跟着做一定可以学会的):

视频素材

如果你发现看文章、做实验有些障碍,我特意录制了视频做演示(如果你基础好,看文章就能看懂并把实验做完,其实没必要看视频)https://articles.zsxq.com/id_blqwkgux7i0a.html

视频内容目前已经完成了:

  • 抓包技巧演示
  • QPS、并发、RT 的关系
  • tcp-rt 展示和在性能定位中的使用
  • 瓶颈定位分析——追着RT 跑
  • 单机内瓶颈定位
  • 认识CPU 和 Cache,以及测试Cache、内存时延

我在星球内一直强调视频不是高效的学习方法,因为你没有办法仔细思索、随时前后反复看等等,看完视频容易形成学懂了的错觉实际很快就忘了,但是我录完这些视频看大家的反馈我发现视频也有优点那就是:很直观、门槛低等,但是一定要注意一个错觉:以为看视频看懂了。但实际就是看视频看完了忘得比看文章快多了,所以看完视频一定要再去实验一下,实验所需要的素材基本都在星球内有了,代码等我都放在了github上

挑战技能

有些技能不好描述,或者说是一些暗知识,我们尽量去讨论这些技能的逻辑,同时对一些特别有效的工具、知识会重点突破,这些恰恰是我希望你们最终能掌握的:

  • 分析解决问题的能力,在一定的知识的基础上靠谱地去分析
  • 掌握技能而不是死知识
  • 掌握核心知识点,核心知识点是指理解了一个点很容易对一个领域有较大的突破,比如IPC对于CPU性能、比如内存墙对计算机组成原理的理解、比如RT 对性能瓶颈的定位等

知识总是学不完的,况且大多时候我们有了知识也解决不了问题,所以我们更注重能力的训练,比如这个提问:https://t.zsxq.com/0cfBnpmLw

节奏安排

如果你发现这个节奏你跟不上,那么就先去看视频,然后再按这个节奏来,如果还不行可以再去看视频,如果视频看不懂可以到微信群里讨论或者就视频里的哪个点提问,如果觉得看懂了,但是还是没法独立实验,那可以这个看懂了还是错觉,或者是基础缺的太多了

请先浏览星球专栏里的必看资源以及学习方法,做到做会而不是看会。另外每个主题后面的留言也很有价值

本星球大部分理论指导部分请看视频:https://t.zsxq.com/0dF2WvzEF (5-10节共90分钟),视频中的理论要和案例结合

案例选择

星球选用的案例尽量典型普适性强,代表基础组件基本原理等知识。

分析手段尽量通用,分析过程一定要逻辑合理每个疑问都能回答清晰。

搞清楚一个案例基本能横扫一个领域,其次在一个案例后再带3/5个相关小案例可以帮你丰富场景,多角度理解

基于以上目标一年内选择了如下4个案例:

详细描述请看这里:https://t.zsxq.com/0cyPswpVB

本星球口头禅

慢就是快,做会而不是看会,无招胜有招

慢就是快指的是不要贪多,而是要彻底搞懂一个问题、一个知识点,让这个点成为一个支柱长成体系,贪多往往啥都没有掌握

做会而不是看会:程序员是工程类(也有科学家,但我们CRUD boy肯定不是),尤其像网络包、CPU流水线都是看不到无法感受,所以建议你去抓包、去做实验体会、触摸到每个包就能够更好地理解,所以星球强调做案例

无招胜有招:尽量找我普适性强的技能,比如ping ping神功,比如抓包,比如Google搜索,你会反复看到我的案例中使用这些技能

如何在本星球获得成长的基本步骤

多和以前的学习方式对比,学了一大堆几个月后全忘了,学了很多不会解决问题,学了很多但要靠反复刷。你不应该继续像以前一样忙忙碌碌但是收获很小

  • 该买的书买了:https://t.zsxq.com/0c3P6gpJE
  • 该做的实验做了:https://t.zsxq.com/0cUhJcVNa ,反复试过后,不懂的尽量提问
  • 该看的视频看过了:https://articles.zsxq.com/id_blqwkgux7i0a.html (实验你能独立完成就不用看视频了)
  • 薅住几个case使劲干,能干多深干多深,看不懂的慢慢想,最好能在工作中找到场景实践一下
  • 学习方法一定要看
  • 不要急于求成,贪多不化,尽量单点突破(就是一个点使劲往深里干),彻底学懂一个后你会感受到加速
  • 体会到动手做和看书的差异,体会到深度学习案例和看书的差异
  • 不要相信自己看会了,不要相信自己的记忆能力
  • 为什么你有知识但是没有能力:https://t.zsxq.com/0cfBnpmLw
  • 养成记笔记,然后总结输出的习惯
  • 必看专栏一定要高优先级先看

最好能有自己的总结输出,比如博客文章,写文章是一次最好的总结,不一定要发出来,也不一定一次写完美了,我经常修改7、8年前的文章,因为随着经验的丰富有了更深入、不同的理解,这时不要写一篇新的,我都是在原来的基础上修改、扩充,这才是体系建设

成长案例

这是大学刚毕业几个月的新同学写的博客:https://yishenggong.com/2023/05/06/why-does-my-network-speed-drop-cn/

https://yishenggong.com/2023/05/22/is-20m-of-rows-still-a-valid-soft-limit-of-mysql-table-in-2023/ 你可以比较他加入星球前后的博客文章(20230315 加入星球), 第二篇是英文版上了hacker news前三

我观察到的学员成长好习惯:

  • 动手动手,不论事情大小先干起来;
  • 有自己的节奏,不贪多先把一篇文章、一个知识点薅扎实了

欢迎在星球里提问

欢迎大家提问,越具体越好

比如这个问题就很具体、很好: https://t.zsxq.com/0enzptS47 (千万不要微信上问,回答了也没有价值)

我自己一个人写写出来的东西难免自嗨,但是如果是你碰到的实际业务问题我觉得就更有代表性一些

提问肯定尽力要把问题描述具体,好重现,典型的就是之前 aws 流量降速导致MySQL QPS下降,提问的同学做得特别好的就是把这个问题自己反复分析后发现是网络流量被限速了,然后问题就很容易描述和重现,最后一大帮人帮忙分析问题,最后的结果大家都很开心学到了东西。问题在这里:https://articles.zsxq.com/id_iq5a872u8sux.html

你要是通过星球里的方法帮你解决了实际问题这是星球的最终目的,我当然最开心,如果你提了一个你工作中的问题大家一起帮你分析、讨论并最终解决了这就是最好的N对1的私教训练——觉得适合你的能力提升

我有时候绞尽脑汁写了文章然后大家不关心,有时候一个普通问题似乎大家都很嗨,我也喜欢能让你们很嗨的问题(即使我不懂也可以一起讨论)

专栏介绍

必看(一定要看的,我尽量控制必看的少)、实战案例(年度计划一定要分享和搞清楚的案例)、动手实验(做会一直是本星球的重要原则)、学习方法(磨刀不误砍柴工),剩下的就是按类别分比较好理解

其它

星主自我介绍:https://t.zsxq.com/0c33AXrCi

或者在推特找我:https://twitter.com/plantegg

个人博客:https://plantegg.github.io/2022/01/01/%E4%B8%89%E4%B8%AA%E6%95%85%E4%BA%8B/

博客存放在github,图多的文章会慢一些,可以刷新几次。

建议大家多用PC版星球( https://wx.zsxq.com ),第一次记住密码后也很方便,主要是打字看图更合适些

画图工具和素材:https://t.zsxq.com/0enaoOUBp

知识星球:https://t.zsxq.com/0cSFEUh2J 或者看看星球的介绍:https://plantegg.github.io/2023/05/10/%E7%A8%8B%E5%BA%8F%E5%91%98%E6%A1%88%E4%BE%8B%E6%98%9F%E7%90%83%E4%BB%8B%E7%BB%8D/

image-20240324161113874

image-20230407232314969

保险

保险

我的观点

  1. 不推荐任何理财型保险(你简单认为一年保费过万的都不推荐)
  2. 推荐少量消费型的保险(就是那种几乎没人给你推销,一年几百、几千的保费,没事不返还任何钱给你)
  3. 不推荐重疾险,回报率低
  4. 资源有限就优先给家庭主要收入来源的人买保险,很多人一上来给小孩买,中年男人裸奔,这搞错了
  5. 最实惠的保险是相互宝那种,可惜被获利阶层伙同傻逼们干没了

理由

基本逻辑:保险是保意外的,你想赚钱就去买房子、股票、基金、做生意(不是说这几年哈)。消费型的保险(比如人身意外伤害险、车险都算)才是保意外,以小博大,当然也是保的小概率。

任何一个保险扣除运营费用就是返还率,相互宝运营费用10%-8%,大多人没概念,这是极低了,没有营销成本,10%用在理赔的时候调查考证。但是一个理财型的保险20-30% 给一线销售,这就是为什么这些保险人反复、耐心跟你讲要买保险,为你服务,当然这是成本,值不值你自己考虑;这还没完,还有上级、经理、公司的运营工资等,要不保险公司凭什么养那么多领导家属;所以这是保险公司核心收入来源,也必然导致了价格奇高。

理赔很复杂,没事的时候当然好,真要理赔各种你没想到的事前告知,你连我这几百字都不愿意看,保险公司那条款你就更不愿意看了。所以我推荐意外险,死了就陪那种简单些,越复杂的你越搞不懂。卖保险的人是不会跟你说那么清晰的,实际上他自己都搞不清楚,真到了出险才是真正的考验!

一家三口,只买一份保险,假设预算一年5000的话,给谁买?

肯定是给创造家里主要收入来源那人,保险其实是给活人的福利,你给小朋友买,妈妈挂了,他惨不惨?收入一下子也没了,保险能给他生活费、学费?

如果给妈妈买,你看至少保额还可以供他几年。现在的父母觉得自己有爱、爱娃,当然是给小朋友买,所以我说是错的

你别拿有钱人人都买来扛哈。

为什么不推荐重疾险

重疾险本来是挺好的,出险直接给钱,是医保外的补充,正如我上面所说赔付率太低了,你还不如把保费存起来,赌概率。

买一年几百的意外险其实是能嫖到一年几万保费的人为你提供服务的

这个自己想想

保险大家都需要,都希望有,但是保险行业是最需要革命和精简的,比银行还夸张,所以我不会花太多钱补贴这帮蛀得太厉害的蛀虫

个人所得税综合汇算

昨天晚上Review个税到很晚,终于找不回来70%,这里确实有需要补税的地方;但是还有一些抵扣给我漏了;

我这次多算主要有一个2022年的bug,这个bug导致当时要退我几万税(系统自动自己算Bug),我大喜装糊涂,各种配合税务局提交资料,最后税务局人工Review的时候发现了这个bug,当然钱也不会退我,不过打电话跟我解释了,我也装糊涂就过去了

结果今年这Bug确实修复了,但是他娘的修复过头了,导致我多补70%的税,现在我只需要补30%,开心多了,这30% 是预期内的

毕竟我从2019年对个税申报太熟悉了,如图是我研究后的一些经验

几个省税的点:

1)大部分情况下奖金、工资分开计税税更少,有极小概率合并计税缴税少(比如工资低奖金高、比如奖金落在盲区的话合,因为利用了工资税扣减数不用除12)

2) 目前奖金、工资可以合并也可以单独计税,二选一,默认单独计税——不懂就在个税app上申报的时候两种都试试,哪种缴税少就用哪种

3) 股票比年终奖少扣税,同样100万,股票收入到手比年终奖多了17万(因为股票税没有盲区)

最后附送一个案例(如图),100万年终奖和100万股票收入的差别,同时100万年终奖跟工资合并计税税更少; 同时如果100万年终奖采用合并计税也比单独计税拿到手要多

目前一个人有机会将税率做得比较低,就是把收入分成3份:工资、将近、股票,算下来几乎可以按综合年入的30%以内缴税(高管个税有其它优惠我粉丝都是屌丝就不展开了,很多高管缴税可能比你少——比如去成都、天津,现在多了海南)

另外因为2023年8月才出通知提高23年的附加抵扣额度,所以今年几乎每个人都要退税,如果没有退就好好Review以下,已经提交了的还可以重新退回来重新算2022年、2021年算错了的现在还可以申请要回来! 现在打开个税APP 去Review,如果有找补回来记得给我发红包。如果你今年退税了辛苦评论区说下让我开心开心

几款不同的CPU一些数据--备查

几款不同的CPU一些数据–备查

背景

方便大家对不同的CPU混个脸熟,有个整体概念。本来发布在知识星球,但是知识星球上格式看起来太影响阅读效率了,所以特意拿出来发到博客上

简单查看CPU我一般用 lscpu(默认自带) 命令,或者用复杂点的工具:hwloc 工具安装:

1
yum install hwloc -y

安装后生成结构图片命令:

1
lstopo --logical --output-format png > kunpeng_920.png

生成字符结构,不要图片:

1
lstopo-no-graphics

后面展示的都算是整体机构,所以还会附带有内存怎么接(一个多少条,每条多大,一个Numa node插了几个物理内存条),这些我博客上都有,就不展开了。一般都是对称的(每个node、socket对称,不对称肯定发挥不出来好性能)

intel E5 2682

大概是Intel 2012年的主流服务器CPU

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 64 //整机总共64核,实际是由32个物理核通过超线程得来
On-line CPU(s) list: 0-63
Thread(s) per core: 2 //一个物理核2个超线程
Core(s) per socket: 16 //每块CPU有16个物理核
Socket(s): 2 //两路,两块物理上能买到的CPU
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 79
Model name: Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz
Stepping: 1
CPU MHz: 2499.902
CPU max MHz: 3000.0000
CPU min MHz: 1200.0000
BogoMIPS: 4999.76
Virtualization: VT-x
L1d cache: 32K //L1 data
L1i cache: 32K
L2 cache: 256K
L3 cache: 40960K //40M L3,也有人叫 LLC(last level cache), L3是一个socket下所有核共享
NUMA node0 CPU(s): 0-15,32-47 //node0
NUMA node1 CPU(s): 16-31,48-63 //node1

//进一步详细看看CPU的结构
#lstopo-no-graphics
Machine (512GB) //机器总共512G内存
NUMANode L#0 (P#0 256GB) //两路,共两个Numa Node,第一个Node 256G内存
Socket L#0 + L3 L#0 (40MB) //Node 0的 L3 40MB,32个逻辑核共享
//第一个物理核,每一个物理核都有自己的L2(256KB)和 L1(32KB+32KB), L1分数据、指令两部分
L2 L#0 (256KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0
PU L#0 (P#0) //第一个逻辑核
PU L#1 (P#32) //第二个逻辑核,这两逻辑核实际是同一个物理核,第二个逻辑核编号是32

//以下是第二个物理核,都是一样的结构……
L2 L#1 (256KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1
PU L#2 (P#1)
PU L#3 (P#33)
L2 L#2 (256KB) + L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2
PU L#4 (P#2)
PU L#5 (P#34)
L2 L#3 (256KB) + L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3
PU L#6 (P#3)
PU L#7 (P#35)
L2 L#4 (256KB) + L1d L#4 (32KB) + L1i L#4 (32KB) + Core L#4
PU L#8 (P#4)
PU L#9 (P#36)
L2 L#5 (256KB) + L1d L#5 (32KB) + L1i L#5 (32KB) + Core L#5
PU L#10 (P#5)
PU L#11 (P#37)
L2 L#6 (256KB) + L1d L#6 (32KB) + L1i L#6 (32KB) + Core L#6
PU L#12 (P#6)
PU L#13 (P#38)
L2 L#7 (256KB) + L1d L#7 (32KB) + L1i L#7 (32KB) + Core L#7
PU L#14 (P#7)
PU L#15 (P#39)
L2 L#8 (256KB) + L1d L#8 (32KB) + L1i L#8 (32KB) + Core L#8
PU L#16 (P#8)
PU L#17 (P#40)
L2 L#9 (256KB) + L1d L#9 (32KB) + L1i L#9 (32KB) + Core L#9
PU L#18 (P#9)
PU L#19 (P#41)
L2 L#10 (256KB) + L1d L#10 (32KB) + L1i L#10 (32KB) + Core L#10
PU L#20 (P#10)
PU L#21 (P#42)
L2 L#11 (256KB) + L1d L#11 (32KB) + L1i L#11 (32KB) + Core L#11
PU L#22 (P#11)
PU L#23 (P#43)
L2 L#12 (256KB) + L1d L#12 (32KB) + L1i L#12 (32KB) + Core L#12
PU L#24 (P#12)
PU L#25 (P#44)
L2 L#13 (256KB) + L1d L#13 (32KB) + L1i L#13 (32KB) + Core L#13
PU L#26 (P#13)
PU L#27 (P#45)
L2 L#14 (256KB) + L1d L#14 (32KB) + L1i L#14 (32KB) + Core L#14
PU L#28 (P#14)
PU L#29 (P#46)
L2 L#15 (256KB) + L1d L#15 (32KB) + L1i L#15 (32KB) + Core L#15
PU L#30 (P#15)
PU L#31 (P#47)
HostBridge L#0
PCIBridge
PCI 144d:a804
PCIBridge
PCI 8086:10fb
Net L#0 "eth2" //两块PCI 万兆网卡插在Socket0上,所有Socket0上的core访问网络效率更高
PCI 8086:10fb
Net L#1 "eth3"
PCIBridge
PCIBridge
PCI 1a03:2000
GPU L#2 "card0"
GPU L#3 "controlD64"
PCI 8086:8d02
Block L#4 "sda" //sda硬盘
NUMANode L#1 (P#1 256GB) //第二路,也就是第二个Node,内存、cache、核都是对称的
Socket L#1 + L3 L#1 (40MB)
L2 L#16 (256KB) + L1d L#16 (32KB) + L1i L#16 (32KB) + Core L#16
PU L#32 (P#16)
PU L#33 (P#48)
L2 L#17 (256KB) + L1d L#17 (32KB) + L1i L#17 (32KB) + Core L#17
PU L#34 (P#17)
PU L#35 (P#49)
L2 L#18 (256KB) + L1d L#18 (32KB) + L1i L#18 (32KB) + Core L#18
PU L#36 (P#18)
PU L#37 (P#50)
L2 L#19 (256KB) + L1d L#19 (32KB) + L1i L#19 (32KB) + Core L#19
PU L#38 (P#19)
PU L#39 (P#51)
L2 L#20 (256KB) + L1d L#20 (32KB) + L1i L#20 (32KB) + Core L#20
PU L#40 (P#20)
PU L#41 (P#52)
L2 L#21 (256KB) + L1d L#21 (32KB) + L1i L#21 (32KB) + Core L#21
PU L#42 (P#21)
PU L#43 (P#53)
L2 L#22 (256KB) + L1d L#22 (32KB) + L1i L#22 (32KB) + Core L#22
PU L#44 (P#22)
PU L#45 (P#54)
L2 L#23 (256KB) + L1d L#23 (32KB) + L1i L#23 (32KB) + Core L#23
PU L#46 (P#23)
PU L#47 (P#55)
L2 L#24 (256KB) + L1d L#24 (32KB) + L1i L#24 (32KB) + Core L#24
PU L#48 (P#24)
PU L#49 (P#56)
L2 L#25 (256KB) + L1d L#25 (32KB) + L1i L#25 (32KB) + Core L#25
PU L#50 (P#25)
PU L#51 (P#57)
L2 L#26 (256KB) + L1d L#26 (32KB) + L1i L#26 (32KB) + Core L#26
PU L#52 (P#26)
PU L#53 (P#58)
L2 L#27 (256KB) + L1d L#27 (32KB) + L1i L#27 (32KB) + Core L#27
PU L#54 (P#27)
PU L#55 (P#59)
L2 L#28 (256KB) + L1d L#28 (32KB) + L1i L#28 (32KB) + Core L#28
PU L#56 (P#28)
PU L#57 (P#60)
L2 L#29 (256KB) + L1d L#29 (32KB) + L1i L#29 (32KB) + Core L#29
PU L#58 (P#29)
PU L#59 (P#61)
L2 L#30 (256KB) + L1d L#30 (32KB) + L1i L#30 (32KB) + Core L#30
PU L#60 (P#30)
PU L#61 (P#62)
L2 L#31 (256KB) + L1d L#31 (32KB) + L1i L#31 (32KB) + Core L#31
PU L#62 (P#31)
PU L#63 (P#63)
HostBridge L#5
PCIBridge
PCI 8086:1521
Net L#5 "enp130s0f0" //两块PCI 千兆网卡
PCI 8086:1521
Net L#6 "enp130s0f1"
PCIBridge
PCI 144d:a804
PCIBridge
PCI 144d:a804

intel 还有一个自带的工具:cpuid-topo 可以看结构,以下是其中一个Socket的展示

img

海光

购买的AMD版权设计等搞出来国产的 x86 架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 43 bits physical, 48 bits virtual
CPU(s): 48
On-line CPU(s) list: 0-47
Thread(s) per core: 1 //我故意把超线程关掉了
Core(s) per socket: 24
Socket(s): 2
NUMA node(s): 8
Vendor ID: HygonGenuine
CPU family: 24
Model: 1
Model name: Hygon C86 7260 24-core Processor
Stepping: 1
Frequency boost: enabled
CPU MHz: 1070.950
CPU max MHz: 2200.0000
CPU min MHz: 1200.0000
BogoMIPS: 4399.54
Virtualization: AMD-V
L1d cache: 1.5 MiB //好大,不符合逻辑,后面解释
L1i cache: 3 MiB
L2 cache: 24 MiB //48个物理核总共24MB L2,但是每个物理核只能用自己的512KB
L3 cache: 128 MiB //
NUMA node0 CPU(s): 0-5
NUMA node1 CPU(s): 6-11
NUMA node2 CPU(s): 12-17
NUMA node3 CPU(s): 18-23
NUMA node4 CPU(s): 24-29
NUMA node5 CPU(s): 30-35
NUMA node6 CPU(s): 36-41
NUMA node7 CPU(s): 42-47 //搞了8个Numa Node

L1、L2太大了,好吓人,这么大不符合逻辑(太贵,没必要)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//继续看看L2 为啥这么大
#cd /sys/devices/system/cpu/cpu0

#ls cache/index2/
coherency_line_size number_of_sets shared_cpu_list type
id physical_line_partition shared_cpu_map uevent
level power/ size ways_of_associativity

#cat cache/index2/size
512K //实际是512K, 2M是4个核共享,搞了个花活,但每个核只能用自己的512K

#cat cache/index2/shared_cpu_list
0 //确认 L2只有自己用

#cat cache/index3/shared_cpu_list
0-2 //L3 给0-2这3个物理核共享,一个Die下有6个物理核,每三个共享一个8M的L3

#cat cache/index3/size
8192K //3个物理核共享8M L3

#cat cache/index1/size
64K

#cat cache/index0/size
32K

index0/index1 分别代表啥?

海光为啥搞了8个Node,请看:https://plantegg.github.io/2021/03/08/%E6%B5%B7%E5%85%89CPU/

图片可以看高清大图

img

对应的字符结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#lstopo
Machine (504GB total)
Package L#0
NUMANode L#0 (P#0 63GB)
L3 L#0 (8192KB)
L2 L#0 (512KB) + L1d L#0 (32KB) + L1i L#0 (64KB) + Core L#0 + PU L#0 (P#0)
L2 L#1 (512KB) + L1d L#1 (32KB) + L1i L#1 (64KB) + Core L#1 + PU L#1 (P#1)
L2 L#2 (512KB) + L1d L#2 (32KB) + L1i L#2 (64KB) + Core L#2 + PU L#2 (P#2)
L3 L#1 (8192KB)
L2 L#3 (512KB) + L1d L#3 (32KB) + L1i L#3 (64KB) + Core L#3 + PU L#3 (P#3)
L2 L#4 (512KB) + L1d L#4 (32KB) + L1i L#4 (64KB) + Core L#4 + PU L#4 (P#4)
L2 L#5 (512KB) + L1d L#5 (32KB) + L1i L#5 (64KB) + Core L#5 + PU L#5 (P#5)
HostBridge L#0
PCIBridge
PCIBridge
PCI 1a03:2000
GPU L#0 "controlD64"
GPU L#1 "card0"
PCIBridge
PCI 1d94:7901
Block(Disk) L#2 "sda"
NUMANode L#1 (P#1 63GB)
L3 L#2 (8192KB)
L2 L#6 (512KB) + L1d L#6 (32KB) + L1i L#6 (64KB) + Core L#6 + PU L#6 (P#6)
L2 L#7 (512KB) + L1d L#7 (32KB) + L1i L#7 (64KB) + Core L#7 + PU L#7 (P#7)
L2 L#8 (512KB) + L1d L#8 (32KB) + L1i L#8 (64KB) + Core L#8 + PU L#8 (P#8)
L3 L#3 (8192KB)
L2 L#9 (512KB) + L1d L#9 (32KB) + L1i L#9 (64KB) + Core L#9 + PU L#9 (P#9)
L2 L#10 (512KB) + L1d L#10 (32KB) + L1i L#10 (64KB) + Core L#10 + PU L#10 (P#10)
L2 L#11 (512KB) + L1d L#11 (32KB) + L1i L#11 (64KB) + Core L#11 + PU L#11 (P#11)
HostBridge L#4
PCIBridge
PCI 1c5f:0557
Block(Disk) L#3 "nvme0n1"
PCIBridge
PCI 1c5f:0557
Block(Disk) L#4 "nvme1n1"
NUMANode L#2 (P#2 63GB)
L3 L#4 (8192KB)
L2 L#12 (512KB) + L1d L#12 (32KB) + L1i L#12 (64KB) + Core L#12 + PU L#12 (P#12)
L2 L#13 (512KB) + L1d L#13 (32KB) + L1i L#13 (64KB) + Core L#13 + PU L#13 (P#13)
L2 L#14 (512KB) + L1d L#14 (32KB) + L1i L#14 (64KB) + Core L#14 + PU L#14 (P#14)
L3 L#5 (8192KB)
L2 L#15 (512KB) + L1d L#15 (32KB) + L1i L#15 (64KB) + Core L#15 + PU L#15 (P#15)
L2 L#16 (512KB) + L1d L#16 (32KB) + L1i L#16 (64KB) + Core L#16 + PU L#16 (P#16)
L2 L#17 (512KB) + L1d L#17 (32KB) + L1i L#17 (64KB) + Core L#17 + PU L#17 (P#17)
HostBridge L#7
PCIBridge
PCI 15b3:1015
Net L#5 "enp33s0f0"
OpenFabrics L#6 "mlx5_0"
PCI 15b3:1015
Net L#7 "enp33s0f1"
OpenFabrics L#8 "mlx5_1"
NUMANode L#3 (P#3 63GB)
L3 L#6 (8192KB)
L2 L#18 (512KB) + L1d L#18 (32KB) + L1i L#18 (64KB) + Core L#18 + PU L#18 (P#18)
L2 L#19 (512KB) + L1d L#19 (32KB) + L1i L#19 (64KB) + Core L#19 + PU L#19 (P#19)
L2 L#20 (512KB) + L1d L#20 (32KB) + L1i L#20 (64KB) + Core L#20 + PU L#20 (P#20)
L3 L#7 (8192KB)
L2 L#21 (512KB) + L1d L#21 (32KB) + L1i L#21 (64KB) + Core L#21 + PU L#21 (P#21)
L2 L#22 (512KB) + L1d L#22 (32KB) + L1i L#22 (64KB) + Core L#22 + PU L#22 (P#22)
L2 L#23 (512KB) + L1d L#23 (32KB) + L1i L#23 (64KB) + Core L#23 + PU L#23 (P#23)
HostBridge L#9
PCIBridge
PCI 8086:1521
Net L#9 "eno1"
PCI 8086:1521
Net L#10 "eno2"
Package L#1
NUMANode L#4 (P#4 63GB)
L3 L#8 (8192KB)
L2 L#24 (512KB) + L1d L#24 (32KB) + L1i L#24 (64KB) + Core L#24 + PU L#24 (P#24)
L2 L#25 (512KB) + L1d L#25 (32KB) + L1i L#25 (64KB) + Core L#25 + PU L#25 (P#25)
L2 L#26 (512KB) + L1d L#26 (32KB) + L1i L#26 (64KB) + Core L#26 + PU L#26 (P#26)
L3 L#9 (8192KB)
L2 L#27 (512KB) + L1d L#27 (32KB) + L1i L#27 (64KB) + Core L#27 + PU L#27 (P#27)
L2 L#28 (512KB) + L1d L#28 (32KB) + L1i L#28 (64KB) + Core L#28 + PU L#28 (P#28)
L2 L#29 (512KB) + L1d L#29 (32KB) + L1i L#29 (64KB) + Core L#29 + PU L#29 (P#29)
NUMANode L#5 (P#5 63GB)
L3 L#10 (8192KB)
L2 L#30 (512KB) + L1d L#30 (32KB) + L1i L#30 (64KB) + Core L#30 + PU L#30 (P#30)
L2 L#31 (512KB) + L1d L#31 (32KB) + L1i L#31 (64KB) + Core L#31 + PU L#31 (P#31)
L2 L#32 (512KB) + L1d L#32 (32KB) + L1i L#32 (64KB) + Core L#32 + PU L#32 (P#32)
L3 L#11 (8192KB)
L2 L#33 (512KB) + L1d L#33 (32KB) + L1i L#33 (64KB) + Core L#33 + PU L#33 (P#33)
L2 L#34 (512KB) + L1d L#34 (32KB) + L1i L#34 (64KB) + Core L#34 + PU L#34 (P#34)
L2 L#35 (512KB) + L1d L#35 (32KB) + L1i L#35 (64KB) + Core L#35 + PU L#35 (P#35)
HostBridge L#11
PCIBridge
PCI 1d94:7901
NUMANode L#6 (P#6 63GB)
L3 L#12 (8192KB)
L2 L#36 (512KB) + L1d L#36 (32KB) + L1i L#36 (64KB) + Core L#36 + PU L#36 (P#36)
L2 L#37 (512KB) + L1d L#37 (32KB) + L1i L#37 (64KB) + Core L#37 + PU L#37 (P#37)
L2 L#38 (512KB) + L1d L#38 (32KB) + L1i L#38 (64KB) + Core L#38 + PU L#38 (P#38)
L3 L#13 (8192KB)
L2 L#39 (512KB) + L1d L#39 (32KB) + L1i L#39 (64KB) + Core L#39 + PU L#39 (P#39)
L2 L#40 (512KB) + L1d L#40 (32KB) + L1i L#40 (64KB) + Core L#40 + PU L#40 (P#40)
L2 L#41 (512KB) + L1d L#41 (32KB) + L1i L#41 (64KB) + Core L#41 + PU L#41 (P#41)
NUMANode L#7 (P#7 63GB)
L3 L#14 (8192KB)
L2 L#42 (512KB) + L1d L#42 (32KB) + L1i L#42 (64KB) + Core L#42 + PU L#42 (P#42)
L2 L#43 (512KB) + L1d L#43 (32KB) + L1i L#43 (64KB) + Core L#43 + PU L#43 (P#43)
L2 L#44 (512KB) + L1d L#44 (32KB) + L1i L#44 (64KB) + Core L#44 + PU L#44 (P#44)
L3 L#15 (8192KB)
L2 L#45 (512KB) + L1d L#45 (32KB) + L1i L#45 (64KB) + Core L#45 + PU L#45 (P#45)
L2 L#46 (512KB) + L1d L#46 (32KB) + L1i L#46 (64KB) + Core L#46 + PU L#46 (P#46)
L2 L#47 (512KB) + L1d L#47 (32KB) + L1i L#47 (64KB) + Core L#47 + PU L#47 (P#47)
Misc(MemoryModule)
Misc(MemoryModule)
Misc(MemoryModule)

以上是海光的7260,还有一个CPU是海光 7280:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 2
Core(s) per socket: 32
Socket(s): 2
NUMA node(s): 8
Vendor ID: HygonGenuine
CPU family: 24
Model: 1
Model name: Hygon C86 7280 32-core Processor
Stepping: 1
CPU MHz: 1981.025
CPU max MHz: 2000.0000
CPU min MHz: 1200.0000
BogoMIPS: 3999.55
Virtualization: AMD-V
L1d cache: 32K
L1i cache: 64K
L2 cache: 512K
L3 cache: 8192K
NUMA node0 CPU(s): 0-7,64-71
NUMA node1 CPU(s): 8-15,72-79
NUMA node2 CPU(s): 16-23,80-87
NUMA node3 CPU(s): 24-31,88-95
NUMA node4 CPU(s): 32-39,96-103
NUMA node5 CPU(s): 40-47,104-111
NUMA node6 CPU(s): 48-55,112-119
NUMA node7 CPU(s): 56-63,120-127

作业:7260和7280的区别是?为什么搞了这两个差异很小的CPU?

1
2
3
4
5
6
7
//继续在7280上看看L3的大小和共享,能够识别他的Die设计理念

//7280上 L3 由8个超线程,也就是4个物理核共享
#cat cache/index3/shared_cpu_list
0-3,64-67 //就这里核数不一样
#cat cache/index3/size
8192K //L3大小和7260一样

还记得7260是3个物理核共享一个8M的L3吧,计算机的世界大多是1、2、4、8,看到3我就觉得有些别扭。评论区告诉我为什么会搞出3个核这样一个奇葩设计?(星球图解专栏里有答案)

AMD 7T83

整机256核,一路128超线程,单CPU 64个物理核,很猛了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 256
On-line CPU(s) list: 0-255
Thread(s) per core: 2
Core(s) per socket: 64
Socket(s): 2
NUMA node(s): 4
Vendor ID: AuthenticAMD
CPU family: 25
Model: 1
Model name: AMD EPYC 7T83 64-Core Processor
Stepping: 1
CPU MHz: 1638.563 //主频有点低,估计还是核太多了
CPU max MHz: 2550.0000
CPU min MHz: 1500.0000
BogoMIPS: 5090.06
Virtualization: AMD-V
L1d cache: 32K
L1i cache: 32K
L2 cache: 512K
L3 cache: 32768K
NUMA node0 CPU(s): 0-31,128-159
NUMA node1 CPU(s): 32-63,160-191
NUMA node2 CPU(s): 64-95,192-223
NUMA node3 CPU(s): 96-127,224-255 //这里展示的是4个Node,在Bios中可配置

#lstopo-no-graphics
Machine (2015GB) //2T 内存
Socket L#0 (1007GB) //单路 1T内存,一路下有两个Numa Node
NUMANode L#0 (P#0 503GB) //这个Node下有4块独立的L3
L3 L#0 (32MB) //看起来16个超线程共享这一个L3,其实这16个核应该是一个独立的Node比较好
L2 L#0 (512KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0
PU L#0 (P#0)
PU L#1 (P#128)
L2 L#1 (512KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1
PU L#2 (P#1)
PU L#3 (P#129)
L2 L#2 (512KB) + L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2
PU L#4 (P#2)
PU L#5 (P#130)
L2 L#3 (512KB) + L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3
PU L#6 (P#3)
PU L#7 (P#131)
L2 L#4 (512KB) + L1d L#4 (32KB) + L1i L#4 (32KB) + Core L#4
PU L#8 (P#4)
PU L#9 (P#132)
L2 L#5 (512KB) + L1d L#5 (32KB) + L1i L#5 (32KB) + Core L#5
PU L#10 (P#5)
PU L#11 (P#133)
L2 L#6 (512KB) + L1d L#6 (32KB) + L1i L#6 (32KB) + Core L#6
PU L#12 (P#6)
PU L#13 (P#134)
L2 L#7 (512KB) + L1d L#7 (32KB) + L1i L#7 (32KB) + Core L#7
PU L#14 (P#7)
PU L#15 (P#135)
L3 L#1 (32MB)
L2 L#8 (512KB) + L1d L#8 (32KB) + L1i L#8 (32KB) + Core L#8
PU L#16 (P#8)
PU L#17 (P#136)
L2 L#9 (512KB) + L1d L#9 (32KB) + L1i L#9 (32KB) + Core L#9
PU L#18 (P#9)
PU L#19 (P#137)
L2 L#10 (512KB) + L1d L#10 (32KB) + L1i L#10 (32KB) + Core L#10
PU L#20 (P#10)
PU L#21 (P#138)
L2 L#11 (512KB) + L1d L#11 (32KB) + L1i L#11 (32KB) + Core L#11
PU L#22 (P#11)
PU L#23 (P#139)
L2 L#12 (512KB) + L1d L#12 (32KB) + L1i L#12 (32KB) + Core L#12
PU L#24 (P#12)
PU L#25 (P#140)
L2 L#13 (512KB) + L1d L#13 (32KB) + L1i L#13 (32KB) + Core L#13
PU L#26 (P#13)
PU L#27 (P#141)
L2 L#14 (512KB) + L1d L#14 (32KB) + L1i L#14 (32KB) + Core L#14
PU L#28 (P#14)
PU L#29 (P#142)
L2 L#15 (512KB) + L1d L#15 (32KB) + L1i L#15 (32KB) + Core L#15
PU L#30 (P#15)
PU L#31 (P#143)
L3 L#2 (32MB)
L2 L#16 (512KB) + L1d L#16 (32KB) + L1i L#16 (32KB) + Core L#16
PU L#32 (P#16)
PU L#33 (P#144)
L2 L#17 (512KB) + L1d L#17 (32KB) + L1i L#17 (32KB) + Core L#17
PU L#34 (P#17)
PU L#35 (P#145)
L2 L#18 (512KB) + L1d L#18 (32KB) + L1i L#18 (32KB) + Core L#18
PU L#36 (P#18)
PU L#37 (P#146)
L2 L#19 (512KB) + L1d L#19 (32KB) + L1i L#19 (32KB) + Core L#19
PU L#38 (P#19)
PU L#39 (P#147)
L2 L#20 (512KB) + L1d L#20 (32KB) + L1i L#20 (32KB) + Core L#20
PU L#40 (P#20)
PU L#41 (P#148)
L2 L#21 (512KB) + L1d L#21 (32KB) + L1i L#21 (32KB) + Core L#21
PU L#42 (P#21)
PU L#43 (P#149)
L2 L#22 (512KB) + L1d L#22 (32KB) + L1i L#22 (32KB) + Core L#22
PU L#44 (P#22)
PU L#45 (P#150)
L2 L#23 (512KB) + L1d L#23 (32KB) + L1i L#23 (32KB) + Core L#23
PU L#46 (P#23)
PU L#47 (P#151)
L3 L#3 (32MB)
L2 L#24 (512KB) + L1d L#24 (32KB) + L1i L#24 (32KB) + Core L#24
PU L#48 (P#24)
PU L#49 (P#152)
L2 L#25 (512KB) + L1d L#25 (32KB) + L1i L#25 (32KB) + Core L#25
PU L#50 (P#25)
PU L#51 (P#153)
L2 L#26 (512KB) + L1d L#26 (32KB) + L1i L#26 (32KB) + Core L#26
PU L#52 (P#26)
PU L#53 (P#154)
L2 L#27 (512KB) + L1d L#27 (32KB) + L1i L#27 (32KB) + Core L#27
PU L#54 (P#27)
PU L#55 (P#155)
L2 L#28 (512KB) + L1d L#28 (32KB) + L1i L#28 (32KB) + Core L#28
PU L#56 (P#28)
PU L#57 (P#156)
L2 L#29 (512KB) + L1d L#29 (32KB) + L1i L#29 (32KB) + Core L#29
PU L#58 (P#29)
PU L#59 (P#157)
L2 L#30 (512KB) + L1d L#30 (32KB) + L1i L#30 (32KB) + Core L#30
PU L#60 (P#30)
PU L#61 (P#158)
L2 L#31 (512KB) + L1d L#31 (32KB) + L1i L#31 (32KB) + Core L#31
PU L#62 (P#31)
PU L#63 (P#159)
HostBridge L#0
PCIBridge
PCI 144d:a80a
PCIBridge
PCI 144d:a80a
PCIBridge
PCIBridge
PCI 1a03:2000
GPU L#0 "controlD64"
GPU L#1 "card0"
NUMANode L#1 (P#1 504GB)
L3 L#4 (32MB)
L2 L#32 (512KB) + L1d L#32 (32KB) + L1i L#32 (32KB) + Core L#32
PU L#64 (P#32)
PU L#65 (P#160)
L2 L#33 (512KB) + L1d L#33 (32KB) + L1i L#33 (32KB) + Core L#33
PU L#66 (P#33)
PU L#67 (P#161)
L2 L#34 (512KB) + L1d L#34 (32KB) + L1i L#34 (32KB) + Core L#34
PU L#68 (P#34)
PU L#69 (P#162)
L2 L#35 (512KB) + L1d L#35 (32KB) + L1i L#35 (32KB) + Core L#35
PU L#70 (P#35)
PU L#71 (P#163)
L2 L#36 (512KB) + L1d L#36 (32KB) + L1i L#36 (32KB) + Core L#36
PU L#72 (P#36)
PU L#73 (P#164)
L2 L#37 (512KB) + L1d L#37 (32KB) + L1i L#37 (32KB) + Core L#37
PU L#74 (P#37)
PU L#75 (P#165)
L2 L#38 (512KB) + L1d L#38 (32KB) + L1i L#38 (32KB) + Core L#38
PU L#76 (P#38)
PU L#77 (P#166)
L2 L#39 (512KB) + L1d L#39 (32KB) + L1i L#39 (32KB) + Core L#39
PU L#78 (P#39)
PU L#79 (P#167)
L3 L#5 (32MB)
L2 L#40 (512KB) + L1d L#40 (32KB) + L1i L#40 (32KB) + Core L#40
PU L#80 (P#40)
PU L#81 (P#168)
L2 L#41 (512KB) + L1d L#41 (32KB) + L1i L#41 (32KB) + Core L#41
PU L#82 (P#41)
PU L#83 (P#169)
L2 L#42 (512KB) + L1d L#42 (32KB) + L1i L#42 (32KB) + Core L#42
PU L#84 (P#42)
PU L#85 (P#170)
L2 L#43 (512KB) + L1d L#43 (32KB) + L1i L#43 (32KB) + Core L#43
PU L#86 (P#43)
PU L#87 (P#171)
L2 L#44 (512KB) + L1d L#44 (32KB) + L1i L#44 (32KB) + Core L#44
PU L#88 (P#44)
PU L#89 (P#172)
L2 L#45 (512KB) + L1d L#45 (32KB) + L1i L#45 (32KB) + Core L#45
PU L#90 (P#45)
PU L#91 (P#173)
L2 L#46 (512KB) + L1d L#46 (32KB) + L1i L#46 (32KB) + Core L#46
PU L#92 (P#46)
PU L#93 (P#174)
L2 L#47 (512KB) + L1d L#47 (32KB) + L1i L#47 (32KB) + Core L#47
PU L#94 (P#47)
PU L#95 (P#175)
L3 L#6 (32MB)
L2 L#48 (512KB) + L1d L#48 (32KB) + L1i L#48 (32KB) + Core L#48
PU L#96 (P#48)
PU L#97 (P#176)
L2 L#49 (512KB) + L1d L#49 (32KB) + L1i L#49 (32KB) + Core L#49
PU L#98 (P#49)
PU L#99 (P#177)
L2 L#50 (512KB) + L1d L#50 (32KB) + L1i L#50 (32KB) + Core L#50
PU L#100 (P#50)
PU L#101 (P#178)
L2 L#51 (512KB) + L1d L#51 (32KB) + L1i L#51 (32KB) + Core L#51
PU L#102 (P#51)
PU L#103 (P#179)
L2 L#52 (512KB) + L1d L#52 (32KB) + L1i L#52 (32KB) + Core L#52
PU L#104 (P#52)
PU L#105 (P#180)
L2 L#53 (512KB) + L1d L#53 (32KB) + L1i L#53 (32KB) + Core L#53
PU L#106 (P#53)
PU L#107 (P#181)
L2 L#54 (512KB) + L1d L#54 (32KB) + L1i L#54 (32KB) + Core L#54
PU L#108 (P#54)
PU L#109 (P#182)
L2 L#55 (512KB) + L1d L#55 (32KB) + L1i L#55 (32KB) + Core L#55
PU L#110 (P#55)
PU L#111 (P#183)
L3 L#7 (32MB)
L2 L#56 (512KB) + L1d L#56 (32KB) + L1i L#56 (32KB) + Core L#56
PU L#112 (P#56)
PU L#113 (P#184)
L2 L#57 (512KB) + L1d L#57 (32KB) + L1i L#57 (32KB) + Core L#57
PU L#114 (P#57)
PU L#115 (P#185)
L2 L#58 (512KB) + L1d L#58 (32KB) + L1i L#58 (32KB) + Core L#58
PU L#116 (P#58)
PU L#117 (P#186)
L2 L#59 (512KB) + L1d L#59 (32KB) + L1i L#59 (32KB) + Core L#59
PU L#118 (P#59)
PU L#119 (P#187)
L2 L#60 (512KB) + L1d L#60 (32KB) + L1i L#60 (32KB) + Core L#60
PU L#120 (P#60)
PU L#121 (P#188)
L2 L#61 (512KB) + L1d L#61 (32KB) + L1i L#61 (32KB) + Core L#61
PU L#122 (P#61)
PU L#123 (P#189)
L2 L#62 (512KB) + L1d L#62 (32KB) + L1i L#62 (32KB) + Core L#62
PU L#124 (P#62)
PU L#125 (P#190)
L2 L#63 (512KB) + L1d L#63 (32KB) + L1i L#63 (32KB) + Core L#63
PU L#126 (P#63)
PU L#127 (P#191)
HostBridge L#5
PCIBridge
PCIBridge
PCIBridge
PCI 1af4:1001
PCIBridge
PCI 1ded:1001
PCI ffff:ffff

Socket L#1 (1008GB)
NUMANode L#2 (P#2 504GB)
L3 L#8 (32MB)
L2 L#64 (512KB) + L1d L#64 (32KB) + L1i L#64 (32KB) + Core L#64
PU L#128 (P#64)
PU L#129 (P#192)
L2 L#65 (512KB) + L1d L#65 (32KB) + L1i L#65 (32KB) + Core L#65
PU L#130 (P#65)
PU L#131 (P#193)
L2 L#66 (512KB) + L1d L#66 (32KB) + L1i L#66 (32KB) + Core L#66
PU L#132 (P#66)
PU L#133 (P#194)
L2 L#67 (512KB) + L1d L#67 (32KB) + L1i L#67 (32KB) + Core L#67
PU L#134 (P#67)
PU L#135 (P#195)
L2 L#68 (512KB) + L1d L#68 (32KB) + L1i L#68 (32KB) + Core L#68
PU L#136 (P#68)
PU L#137 (P#196)
L2 L#69 (512KB) + L1d L#69 (32KB) + L1i L#69 (32KB) + Core L#69
PU L#138 (P#69)
PU L#139 (P#197)
L2 L#70 (512KB) + L1d L#70 (32KB) + L1i L#70 (32KB) + Core L#70
PU L#140 (P#70)
PU L#141 (P#198)
L2 L#71 (512KB) + L1d L#71 (32KB) + L1i L#71 (32KB) + Core L#71
PU L#142 (P#71)
PU L#143 (P#199)
L3 L#9 (32MB)
L2 L#72 (512KB) + L1d L#72 (32KB) + L1i L#72 (32KB) + Core L#72
PU L#144 (P#72)
PU L#145 (P#200)
L2 L#73 (512KB) + L1d L#73 (32KB) + L1i L#73 (32KB) + Core L#73
PU L#146 (P#73)
PU L#147 (P#201)
L2 L#74 (512KB) + L1d L#74 (32KB) + L1i L#74 (32KB) + Core L#74
PU L#148 (P#74)
PU L#149 (P#202)
L2 L#75 (512KB) + L1d L#75 (32KB) + L1i L#75 (32KB) + Core L#75
PU L#150 (P#75)
PU L#151 (P#203)
L2 L#76 (512KB) + L1d L#76 (32KB) + L1i L#76 (32KB) + Core L#76
PU L#152 (P#76)
PU L#153 (P#204)
L2 L#77 (512KB) + L1d L#77 (32KB) + L1i L#77 (32KB) + Core L#77
PU L#154 (P#77)
PU L#155 (P#205)
L2 L#78 (512KB) + L1d L#78 (32KB) + L1i L#78 (32KB) + Core L#78
PU L#156 (P#78)
PU L#157 (P#206)
L2 L#79 (512KB) + L1d L#79 (32KB) + L1i L#79 (32KB) + Core L#79
PU L#158 (P#79)
PU L#159 (P#207)
L3 L#10 (32MB)
L2 L#80 (512KB) + L1d L#80 (32KB) + L1i L#80 (32KB) + Core L#80
PU L#160 (P#80)
PU L#161 (P#208)
L2 L#81 (512KB) + L1d L#81 (32KB) + L1i L#81 (32KB) + Core L#81
PU L#162 (P#81)
PU L#163 (P#209)
L2 L#82 (512KB) + L1d L#82 (32KB) + L1i L#82 (32KB) + Core L#82
PU L#164 (P#82)
PU L#165 (P#210)
L2 L#83 (512KB) + L1d L#83 (32KB) + L1i L#83 (32KB) + Core L#83
PU L#166 (P#83)
PU L#167 (P#211)
L2 L#84 (512KB) + L1d L#84 (32KB) + L1i L#84 (32KB) + Core L#84
PU L#168 (P#84)
PU L#169 (P#212)
L2 L#85 (512KB) + L1d L#85 (32KB) + L1i L#85 (32KB) + Core L#85
PU L#170 (P#85)
PU L#171 (P#213)
L2 L#86 (512KB) + L1d L#86 (32KB) + L1i L#86 (32KB) + Core L#86
PU L#172 (P#86)
PU L#173 (P#214)
L2 L#87 (512KB) + L1d L#87 (32KB) + L1i L#87 (32KB) + Core L#87
PU L#174 (P#87)
PU L#175 (P#215)
L3 L#11 (32MB)
L2 L#88 (512KB) + L1d L#88 (32KB) + L1i L#88 (32KB) + Core L#88
PU L#176 (P#88)
PU L#177 (P#216)
L2 L#89 (512KB) + L1d L#89 (32KB) + L1i L#89 (32KB) + Core L#89
PU L#178 (P#89)
PU L#179 (P#217)
L2 L#90 (512KB) + L1d L#90 (32KB) + L1i L#90 (32KB) + Core L#90
PU L#180 (P#90)
PU L#181 (P#218)
L2 L#91 (512KB) + L1d L#91 (32KB) + L1i L#91 (32KB) + Core L#91
PU L#182 (P#91)
PU L#183 (P#219)
L2 L#92 (512KB) + L1d L#92 (32KB) + L1i L#92 (32KB) + Core L#92
PU L#184 (P#92)
PU L#185 (P#220)
L2 L#93 (512KB) + L1d L#93 (32KB) + L1i L#93 (32KB) + Core L#93
PU L#186 (P#93)
PU L#187 (P#221)
L2 L#94 (512KB) + L1d L#94 (32KB) + L1i L#94 (32KB) + Core L#94
PU L#188 (P#94)
PU L#189 (P#222)
L2 L#95 (512KB) + L1d L#95 (32KB) + L1i L#95 (32KB) + Core L#95
PU L#190 (P#95)
PU L#191 (P#223)
NUMANode L#3 (P#3 504GB)
L3 L#12 (32MB)
L2 L#96 (512KB) + L1d L#96 (32KB) + L1i L#96 (32KB) + Core L#96
PU L#192 (P#96)
PU L#193 (P#224)
L2 L#97 (512KB) + L1d L#97 (32KB) + L1i L#97 (32KB) + Core L#97
PU L#194 (P#97)
PU L#195 (P#225)
L2 L#98 (512KB) + L1d L#98 (32KB) + L1i L#98 (32KB) + Core L#98
PU L#196 (P#98)
PU L#197 (P#226)
L2 L#99 (512KB) + L1d L#99 (32KB) + L1i L#99 (32KB) + Core L#99
PU L#198 (P#99)
PU L#199 (P#227)
L2 L#100 (512KB) + L1d L#100 (32KB) + L1i L#100 (32KB) + Core L#100
PU L#200 (P#100)
PU L#201 (P#228)
L2 L#101 (512KB) + L1d L#101 (32KB) + L1i L#101 (32KB) + Core L#101
PU L#202 (P#101)
PU L#203 (P#229)
L2 L#102 (512KB) + L1d L#102 (32KB) + L1i L#102 (32KB) + Core L#102
PU L#204 (P#102)
PU L#205 (P#230)
L2 L#103 (512KB) + L1d L#103 (32KB) + L1i L#103 (32KB) + Core L#103
PU L#206 (P#103)
PU L#207 (P#231)
L3 L#13 (32MB)
L2 L#104 (512KB) + L1d L#104 (32KB) + L1i L#104 (32KB) + Core L#104
PU L#208 (P#104)
PU L#209 (P#232)
L2 L#105 (512KB) + L1d L#105 (32KB) + L1i L#105 (32KB) + Core L#105
PU L#210 (P#105)
PU L#211 (P#233)
L2 L#106 (512KB) + L1d L#106 (32KB) + L1i L#106 (32KB) + Core L#106
PU L#212 (P#106)
PU L#213 (P#234)
L2 L#107 (512KB) + L1d L#107 (32KB) + L1i L#107 (32KB) + Core L#107
PU L#214 (P#107)
PU L#215 (P#235)
L2 L#108 (512KB) + L1d L#108 (32KB) + L1i L#108 (32KB) + Core L#108
PU L#216 (P#108)
PU L#217 (P#236)
L2 L#109 (512KB) + L1d L#109 (32KB) + L1i L#109 (32KB) + Core L#109
PU L#218 (P#109)
PU L#219 (P#237)
L2 L#110 (512KB) + L1d L#110 (32KB) + L1i L#110 (32KB) + Core L#110
PU L#220 (P#110)
PU L#221 (P#238)
L2 L#111 (512KB) + L1d L#111 (32KB) + L1i L#111 (32KB) + Core L#111
PU L#222 (P#111)
PU L#223 (P#239)
L3 L#14 (32MB)
L2 L#112 (512KB) + L1d L#112 (32KB) + L1i L#112 (32KB) + Core L#112
PU L#224 (P#112)
PU L#225 (P#240)
L2 L#113 (512KB) + L1d L#113 (32KB) + L1i L#113 (32KB) + Core L#113
PU L#226 (P#113)
PU L#227 (P#241)
L2 L#114 (512KB) + L1d L#114 (32KB) + L1i L#114 (32KB) + Core L#114
PU L#228 (P#114)
PU L#229 (P#242)
L2 L#115 (512KB) + L1d L#115 (32KB) + L1i L#115 (32KB) + Core L#115
PU L#230 (P#115)
PU L#231 (P#243)
L2 L#116 (512KB) + L1d L#116 (32KB) + L1i L#116 (32KB) + Core L#116
PU L#232 (P#116)
PU L#233 (P#244)
L2 L#117 (512KB) + L1d L#117 (32KB) + L1i L#117 (32KB) + Core L#117
PU L#234 (P#117)
PU L#235 (P#245)
L2 L#118 (512KB) + L1d L#118 (32KB) + L1i L#118 (32KB) + Core L#118
PU L#236 (P#118)
PU L#237 (P#246)
L2 L#119 (512KB) + L1d L#119 (32KB) + L1i L#119 (32KB) + Core L#119
PU L#238 (P#119)
PU L#239 (P#247)
L3 L#15 (32MB)
L2 L#120 (512KB) + L1d L#120 (32KB) + L1i L#120 (32KB) + Core L#120
PU L#240 (P#120)
PU L#241 (P#248)
L2 L#121 (512KB) + L1d L#121 (32KB) + L1i L#121 (32KB) + Core L#121
PU L#242 (P#121)
PU L#243 (P#249)
L2 L#122 (512KB) + L1d L#122 (32KB) + L1i L#122 (32KB) + Core L#122
PU L#244 (P#122)
PU L#245 (P#250)
L2 L#123 (512KB) + L1d L#123 (32KB) + L1i L#123 (32KB) + Core L#123
PU L#246 (P#123)
PU L#247 (P#251)
L2 L#124 (512KB) + L1d L#124 (32KB) + L1i L#124 (32KB) + Core L#124
PU L#248 (P#124)
PU L#249 (P#252)
L2 L#125 (512KB) + L1d L#125 (32KB) + L1i L#125 (32KB) + Core L#125
PU L#250 (P#125)
PU L#251 (P#253)
L2 L#126 (512KB) + L1d L#126 (32KB) + L1i L#126 (32KB) + Core L#126
PU L#252 (P#126)
PU L#253 (P#254)
L2 L#127 (512KB) + L1d L#127 (32KB) + L1i L#127 (32KB) + Core L#127
PU L#254 (P#127)
PU L#255 (P#255)

这台机器改下BIOS设置

img

白色Channel 那里可以选择Auto/Die/Channel/Socket, 选择Socket后得到如下Node 结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 256
On-line CPU(s) list: 0-255
Thread(s) per core: 2
Core(s) per socket: 64
Socket(s): 2
NUMA node(s): 2
Vendor ID: AuthenticAMD
CPU family: 25
Model: 1
Model name: AMD EPYC 7T83 64-Core Processor
Stepping: 1
CPU MHz: 2399.192
CPU max MHz: 2550.0000
CPU min MHz: 1500.0000
BogoMIPS: 5090.50
Virtualization: AMD-V
L1d cache: 32K
L1i cache: 32K
L2 cache: 512K
L3 cache: 32768K
NUMA node0 CPU(s): 0-63,128-191
NUMA node1 CPU(s): 64-127,192-255 //每个socket下的内存交织,也就是一个Socket是一个独立的 Numa Node

鲲鹏 920

鲲鹏是ARM架构,一般都没有超线程,因为指令简单流水线较流畅,搞超线程收益不大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# lscpu
架构: aarch64
CPU 运行模式: 64-bit
字节序: Little Endian
CPU: 96
在线 CPU 列表: 0-95
每个核的线程数: 1
每个座的核数: 48
座: 2
NUMA 节点: 4
厂商 ID: HiSilicon
型号: 0
型号名称: Kunpeng-920
步进: 0x1
CPU 最大 MHz: 2600.0000
CPU 最小 MHz: 200.0000
BogoMIPS: 200.00
L1d 缓存: 6 MiB
L1i 缓存: 6 MiB
L2 缓存: 48 MiB
L3 缓存: 96 MiB
NUMA 节点0 CPU: 0-23
NUMA 节点1 CPU: 24-47
NUMA 节点2 CPU: 48-71
NUMA 节点3 CPU: 72-95

#lstopo
Machine (766GB total)
Package L#0
NUMANode L#0 (P#0 191GB)
L3 L#0 (24MB)
L2 L#0 (512KB) + L1d L#0 (64KB) + L1i L#0 (64KB) + Core L#0 + PU L#0 (P#0)
L2 L#1 (512KB) + L1d L#1 (64KB) + L1i L#1 (64KB) + Core L#1 + PU L#1 (P#1)
L2 L#2 (512KB) + L1d L#2 (64KB) + L1i L#2 (64KB) + Core L#2 + PU L#2 (P#2)
L2 L#3 (512KB) + L1d L#3 (64KB) + L1i L#3 (64KB) + Core L#3 + PU L#3 (P#3)
L2 L#4 (512KB) + L1d L#4 (64KB) + L1i L#4 (64KB) + Core L#4 + PU L#4 (P#4)
L2 L#5 (512KB) + L1d L#5 (64KB) + L1i L#5 (64KB) + Core L#5 + PU L#5 (P#5)
L2 L#6 (512KB) + L1d L#6 (64KB) + L1i L#6 (64KB) + Core L#6 + PU L#6 (P#6)
L2 L#7 (512KB) + L1d L#7 (64KB) + L1i L#7 (64KB) + Core L#7 + PU L#7 (P#7)
L2 L#8 (512KB) + L1d L#8 (64KB) + L1i L#8 (64KB) + Core L#8 + PU L#8 (P#8)
L2 L#9 (512KB) + L1d L#9 (64KB) + L1i L#9 (64KB) + Core L#9 + PU L#9 (P#9)
L2 L#10 (512KB) + L1d L#10 (64KB) + L1i L#10 (64KB) + Core L#10 + PU L#10 (P#10)
L2 L#11 (512KB) + L1d L#11 (64KB) + L1i L#11 (64KB) + Core L#11 + PU L#11 (P#11)
L2 L#12 (512KB) + L1d L#12 (64KB) + L1i L#12 (64KB) + Core L#12 + PU L#12 (P#12)
L2 L#13 (512KB) + L1d L#13 (64KB) + L1i L#13 (64KB) + Core L#13 + PU L#13 (P#13)
L2 L#14 (512KB) + L1d L#14 (64KB) + L1i L#14 (64KB) + Core L#14 + PU L#14 (P#14)
L2 L#15 (512KB) + L1d L#15 (64KB) + L1i L#15 (64KB) + Core L#15 + PU L#15 (P#15)
L2 L#16 (512KB) + L1d L#16 (64KB) + L1i L#16 (64KB) + Core L#16 + PU L#16 (P#16)
L2 L#17 (512KB) + L1d L#17 (64KB) + L1i L#17 (64KB) + Core L#17 + PU L#17 (P#17)
L2 L#18 (512KB) + L1d L#18 (64KB) + L1i L#18 (64KB) + Core L#18 + PU L#18 (P#18)
L2 L#19 (512KB) + L1d L#19 (64KB) + L1i L#19 (64KB) + Core L#19 + PU L#19 (P#19)
L2 L#20 (512KB) + L1d L#20 (64KB) + L1i L#20 (64KB) + Core L#20 + PU L#20 (P#20)
L2 L#21 (512KB) + L1d L#21 (64KB) + L1i L#21 (64KB) + Core L#21 + PU L#21 (P#21)
L2 L#22 (512KB) + L1d L#22 (64KB) + L1i L#22 (64KB) + Core L#22 + PU L#22 (P#22)
L2 L#23 (512KB) + L1d L#23 (64KB) + L1i L#23 (64KB) + Core L#23 + PU L#23 (P#23)
HostBridge L#0
PCIBridge
PCI 15b3:1017
Net L#0 "enp2s0f0"
PCI 15b3:1017
Net L#1 "enp2s0f1"
PCIBridge
PCI 19e5:1711
GPU L#2 "controlD64"
GPU L#3 "card0"
HostBridge L#3
2 x { PCI 19e5:a230 }
PCI 19e5:a235
Block(Disk) L#4 "sda"
HostBridge L#4
PCIBridge
PCI 19e5:a222
Net L#5 "enp125s0f0"
OpenFabrics L#6 "hns_0"
PCI 19e5:a221
Net L#7 "enp125s0f1"
PCI 19e5:a222
Net L#8 "enp125s0f2"
OpenFabrics L#9 "hns_1"
PCI 19e5:a221
Net L#10 "enp125s0f3"
NUMANode L#1 (P#1 192GB) + L3 L#1 (24MB)
L2 L#24 (512KB) + L1d L#24 (64KB) + L1i L#24 (64KB) + Core L#24 + PU L#24 (P#24)
L2 L#25 (512KB) + L1d L#25 (64KB) + L1i L#25 (64KB) + Core L#25 + PU L#25 (P#25)
L2 L#26 (512KB) + L1d L#26 (64KB) + L1i L#26 (64KB) + Core L#26 + PU L#26 (P#26)
L2 L#27 (512KB) + L1d L#27 (64KB) + L1i L#27 (64KB) + Core L#27 + PU L#27 (P#27)
L2 L#28 (512KB) + L1d L#28 (64KB) + L1i L#28 (64KB) + Core L#28 + PU L#28 (P#28)
L2 L#29 (512KB) + L1d L#29 (64KB) + L1i L#29 (64KB) + Core L#29 + PU L#29 (P#29)
L2 L#30 (512KB) + L1d L#30 (64KB) + L1i L#30 (64KB) + Core L#30 + PU L#30 (P#30)
L2 L#31 (512KB) + L1d L#31 (64KB) + L1i L#31 (64KB) + Core L#31 + PU L#31 (P#31)
L2 L#32 (512KB) + L1d L#32 (64KB) + L1i L#32 (64KB) + Core L#32 + PU L#32 (P#32)
L2 L#33 (512KB) + L1d L#33 (64KB) + L1i L#33 (64KB) + Core L#33 + PU L#33 (P#33)
L2 L#34 (512KB) + L1d L#34 (64KB) + L1i L#34 (64KB) + Core L#34 + PU L#34 (P#34)
L2 L#35 (512KB) + L1d L#35 (64KB) + L1i L#35 (64KB) + Core L#35 + PU L#35 (P#35)
L2 L#36 (512KB) + L1d L#36 (64KB) + L1i L#36 (64KB) + Core L#36 + PU L#36 (P#36)
L2 L#37 (512KB) + L1d L#37 (64KB) + L1i L#37 (64KB) + Core L#37 + PU L#37 (P#37)
L2 L#38 (512KB) + L1d L#38 (64KB) + L1i L#38 (64KB) + Core L#38 + PU L#38 (P#38)
L2 L#39 (512KB) + L1d L#39 (64KB) + L1i L#39 (64KB) + Core L#39 + PU L#39 (P#39)
L2 L#40 (512KB) + L1d L#40 (64KB) + L1i L#40 (64KB) + Core L#40 + PU L#40 (P#40)
L2 L#41 (512KB) + L1d L#41 (64KB) + L1i L#41 (64KB) + Core L#41 + PU L#41 (P#41)
L2 L#42 (512KB) + L1d L#42 (64KB) + L1i L#42 (64KB) + Core L#42 + PU L#42 (P#42)
L2 L#43 (512KB) + L1d L#43 (64KB) + L1i L#43 (64KB) + Core L#43 + PU L#43 (P#43)
L2 L#44 (512KB) + L1d L#44 (64KB) + L1i L#44 (64KB) + Core L#44 + PU L#44 (P#44)
L2 L#45 (512KB) + L1d L#45 (64KB) + L1i L#45 (64KB) + Core L#45 + PU L#45 (P#45)
L2 L#46 (512KB) + L1d L#46 (64KB) + L1i L#46 (64KB) + Core L#46 + PU L#46 (P#46)
L2 L#47 (512KB) + L1d L#47 (64KB) + L1i L#47 (64KB) + Core L#47 + PU L#47 (P#47)
Package L#1
NUMANode L#2 (P#2 192GB)
L3 L#2 (24MB)
L2 L#48 (512KB) + L1d L#48 (64KB) + L1i L#48 (64KB) + Core L#48 + PU L#48 (P#48)
L2 L#49 (512KB) + L1d L#49 (64KB) + L1i L#49 (64KB) + Core L#49 + PU L#49 (P#49)
L2 L#50 (512KB) + L1d L#50 (64KB) + L1i L#50 (64KB) + Core L#50 + PU L#50 (P#50)
L2 L#51 (512KB) + L1d L#51 (64KB) + L1i L#51 (64KB) + Core L#51 + PU L#51 (P#51)
L2 L#52 (512KB) + L1d L#52 (64KB) + L1i L#52 (64KB) + Core L#52 + PU L#52 (P#52)
L2 L#53 (512KB) + L1d L#53 (64KB) + L1i L#53 (64KB) + Core L#53 + PU L#53 (P#53)
L2 L#54 (512KB) + L1d L#54 (64KB) + L1i L#54 (64KB) + Core L#54 + PU L#54 (P#54)
L2 L#55 (512KB) + L1d L#55 (64KB) + L1i L#55 (64KB) + Core L#55 + PU L#55 (P#55)
L2 L#56 (512KB) + L1d L#56 (64KB) + L1i L#56 (64KB) + Core L#56 + PU L#56 (P#56)
L2 L#57 (512KB) + L1d L#57 (64KB) + L1i L#57 (64KB) + Core L#57 + PU L#57 (P#57)
L2 L#58 (512KB) + L1d L#58 (64KB) + L1i L#58 (64KB) + Core L#58 + PU L#58 (P#58)
L2 L#59 (512KB) + L1d L#59 (64KB) + L1i L#59 (64KB) + Core L#59 + PU L#59 (P#59)
L2 L#60 (512KB) + L1d L#60 (64KB) + L1i L#60 (64KB) + Core L#60 + PU L#60 (P#60)
L2 L#61 (512KB) + L1d L#61 (64KB) + L1i L#61 (64KB) + Core L#61 + PU L#61 (P#61)
L2 L#62 (512KB) + L1d L#62 (64KB) + L1i L#62 (64KB) + Core L#62 + PU L#62 (P#62)
L2 L#63 (512KB) + L1d L#63 (64KB) + L1i L#63 (64KB) + Core L#63 + PU L#63 (P#63)
L2 L#64 (512KB) + L1d L#64 (64KB) + L1i L#64 (64KB) + Core L#64 + PU L#64 (P#64)
L2 L#65 (512KB) + L1d L#65 (64KB) + L1i L#65 (64KB) + Core L#65 + PU L#65 (P#65)
L2 L#66 (512KB) + L1d L#66 (64KB) + L1i L#66 (64KB) + Core L#66 + PU L#66 (P#66)
L2 L#67 (512KB) + L1d L#67 (64KB) + L1i L#67 (64KB) + Core L#67 + PU L#67 (P#67)
L2 L#68 (512KB) + L1d L#68 (64KB) + L1i L#68 (64KB) + Core L#68 + PU L#68 (P#68)
L2 L#69 (512KB) + L1d L#69 (64KB) + L1i L#69 (64KB) + Core L#69 + PU L#69 (P#69)
L2 L#70 (512KB) + L1d L#70 (64KB) + L1i L#70 (64KB) + Core L#70 + PU L#70 (P#70)
L2 L#71 (512KB) + L1d L#71 (64KB) + L1i L#71 (64KB) + Core L#71 + PU L#71 (P#71)
HostBridge L#6
PCIBridge
PCI 19e5:3714
PCIBridge
PCI 19e5:3714
PCIBridge
PCI 19e5:3714
PCIBridge
PCI 19e5:3714
HostBridge L#11
PCI 19e5:a230
PCI 19e5:a235
PCI 19e5:a230
NUMANode L#3 (P#3 191GB) + L3 L#3 (24MB)
L2 L#72 (512KB) + L1d L#72 (64KB) + L1i L#72 (64KB) + Core L#72 + PU L#72 (P#72)
L2 L#73 (512KB) + L1d L#73 (64KB) + L1i L#73 (64KB) + Core L#73 + PU L#73 (P#73)
L2 L#74 (512KB) + L1d L#74 (64KB) + L1i L#74 (64KB) + Core L#74 + PU L#74 (P#74)
L2 L#75 (512KB) + L1d L#75 (64KB) + L1i L#75 (64KB) + Core L#75 + PU L#75 (P#75)
L2 L#76 (512KB) + L1d L#76 (64KB) + L1i L#76 (64KB) + Core L#76 + PU L#76 (P#76)
L2 L#77 (512KB) + L1d L#77 (64KB) + L1i L#77 (64KB) + Core L#77 + PU L#77 (P#77)
L2 L#78 (512KB) + L1d L#78 (64KB) + L1i L#78 (64KB) + Core L#78 + PU L#78 (P#78)
L2 L#79 (512KB) + L1d L#79 (64KB) + L1i L#79 (64KB) + Core L#79 + PU L#79 (P#79)
L2 L#80 (512KB) + L1d L#80 (64KB) + L1i L#80 (64KB) + Core L#80 + PU L#80 (P#80)
L2 L#81 (512KB) + L1d L#81 (64KB) + L1i L#81 (64KB) + Core L#81 + PU L#81 (P#81)
L2 L#82 (512KB) + L1d L#82 (64KB) + L1i L#82 (64KB) + Core L#82 + PU L#82 (P#82)
L2 L#83 (512KB) + L1d L#83 (64KB) + L1i L#83 (64KB) + Core L#83 + PU L#83 (P#83)
L2 L#84 (512KB) + L1d L#84 (64KB) + L1i L#84 (64KB) + Core L#84 + PU L#84 (P#84)
L2 L#85 (512KB) + L1d L#85 (64KB) + L1i L#85 (64KB) + Core L#85 + PU L#85 (P#85)
L2 L#86 (512KB) + L1d L#86 (64KB) + L1i L#86 (64KB) + Core L#86 + PU L#86 (P#86)
L2 L#87 (512KB) + L1d L#87 (64KB) + L1i L#87 (64KB) + Core L#87 + PU L#87 (P#87)
L2 L#88 (512KB) + L1d L#88 (64KB) + L1i L#88 (64KB) + Core L#88 + PU L#88 (P#88)
L2 L#89 (512KB) + L1d L#89 (64KB) + L1i L#89 (64KB) + Core L#89 + PU L#89 (P#89)
L2 L#90 (512KB) + L1d L#90 (64KB) + L1i L#90 (64KB) + Core L#90 + PU L#90 (P#90)
L2 L#91 (512KB) + L1d L#91 (64KB) + L1i L#91 (64KB) + Core L#91 + PU L#91 (P#91)
L2 L#92 (512KB) + L1d L#92 (64KB) + L1i L#92 (64KB) + Core L#92 + PU L#92 (P#92)
L2 L#93 (512KB) + L1d L#93 (64KB) + L1i L#93 (64KB) + Core L#93 + PU L#93 (P#93)
L2 L#94 (512KB) + L1d L#94 (64KB) + L1i L#94 (64KB) + Core L#94 + PU L#94 (P#94)
L2 L#95 (512KB) + L1d L#95 (64KB) + L1i L#95 (64KB) + Core L#95 + PU L#95 (P#95)
Misc(MemoryModule)
Misc(MemoryModule)
Misc(MemoryModule)


Node Distance:
node 0 <------------ socket distance ------------> node 2
| (die distance) | (die distance)
node 1 node 3

图形化查看(打开大图,和前面的intel 对着看)

img

思考:看如上鲲鹏机器的结构你应该知道网卡、硬盘怎么插放的了吧,然后想就近搞点优化也是可以的

飞腾2500

飞腾的解读留给大家当作业

https://plantegg.github.io/2021/05/15/%E9%A3%9E%E8%85%BEARM%E8%8A%AF%E7%89%87(FT2500)%E7%9A%84%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#dmidecode -t processor
# dmidecode 3.0
Getting SMBIOS data from sysfs.
SMBIOS 3.2.0 present.
# SMBIOS implementations newer than version 3.0 are not
# fully supported by this version of dmidecode.
Handle 0x0004, DMI type 4, 48 bytes
Processor Information
Socket Designation: BGA3576
Type: Central Processor
Family: <OUT OF SPEC>
Manufacturer: PHYTIUM
ID: 00 00 00 00 70 1F 66 22
Version: FT2500
Voltage: 0.8 V
External Clock: 50 MHz
Max Speed: 2100 MHz
Current Speed: 2100 MHz
Status: Populated, Enabled
Upgrade: Other
L1 Cache Handle: 0x0005
L2 Cache Handle: 0x0007
L3 Cache Handle: 0x0008
Serial Number: 1234567
Asset Tag: No Asset Tag
Part Number: NULL
Core Count: 64
Core Enabled: 64
Thread Count: 64
Characteristics:
64-bit capable
Multi-Core
Hardware Thread
Execute Protection
Enhanced Virtualization
Power/Performance Control
#lscpu
Architecture: aarch64
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 1
Core(s) per socket: 64
Socket(s): 2
NUMA node(s): 16
Model: 3
BogoMIPS: 100.00
L1d cache: 32K
L1i cache: 32K
L2 cache: 2048K //2M?太大了,不真实,估计和海光一样骚
L3 cache: 65536K
NUMA node0 CPU(s): 0-7
NUMA node1 CPU(s): 8-15
NUMA node2 CPU(s): 16-23
NUMA node3 CPU(s): 24-31
NUMA node4 CPU(s): 32-39
NUMA node5 CPU(s): 40-47
NUMA node6 CPU(s): 48-55
NUMA node7 CPU(s): 56-63
NUMA node8 CPU(s): 64-71
NUMA node9 CPU(s): 72-79
NUMA node10 CPU(s): 80-87
NUMA node11 CPU(s): 88-95
NUMA node12 CPU(s): 96-103
NUMA node13 CPU(s): 104-111
NUMA node14 CPU(s): 112-119
NUMA node15 CPU(s): 120-127
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
node distances:
node 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0: 10 20 40 30 20 30 50 40 100 100 100 100 100 100 100 100
1: 20 10 30 40 50 20 40 50 100 100 100 100 100 100 100 100
2: 40 30 10 20 40 50 20 30 100 100 100 100 100 100 100 100
3: 30 40 20 10 30 20 40 50 100 100 100 100 100 100 100 100
4: 20 50 40 30 10 50 30 20 100 100 100 100 100 100 100 100
5: 30 20 50 20 50 10 50 40 100 100 100 100 100 100 100 100
6: 50 40 20 40 30 50 10 30 100 100 100 100 100 100 100 100
7: 40 50 30 50 20 40 30 10 100 100 100 100 100 100 100 100
8: 100 100 100 100 100 100 100 100 10 20 40 30 20 30 50 40
9: 100 100 100 100 100 100 100 100 20 10 30 40 50 20 40 50
10: 100 100 100 100 100 100 100 100 40 30 10 20 40 50 20 30
11: 100 100 100 100 100 100 100 100 30 40 20 10 30 20 40 50
12: 100 100 100 100 100 100 100 100 20 50 40 30 10 50 30 20
13: 100 100 100 100 100 100 100 100 30 20 50 20 50 10 50 40
14: 100 100 100 100 100 100 100 100 50 40 20 40 30 50 10 30
15: 100 100 100 100 100 100 100 100 40 50 30 50 20 40 30 10

飞腾的核有点多,我省略了一些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#lstopo-no-graphics --logical
Machine (503GB total)
Package L#0 + L3 L#0 (64MB)
NUMANode L#0 (P#0 31GB)
L2 L#0 (2048KB) //4个物理core共享2M,是不是和AMD(海光)那个设计有点像
L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
L2 L#1 (2048KB)
L1d L#4 (32KB) + L1i L#4 (32KB) + Core L#4 + PU L#4 (P#4)
L1d L#5 (32KB) + L1i L#5 (32KB) + Core L#5 + PU L#5 (P#5)
L1d L#6 (32KB) + L1i L#6 (32KB) + Core L#6 + PU L#6 (P#6)
L1d L#7 (32KB) + L1i L#7 (32KB) + Core L#7 + PU L#7 (P#7)
HostBridge L#0
PCIBridge
PCIBridge
PCIBridge
PCI 1000:00ac
Block(Disk) L#0 "sdh"
Block(Disk) L#1 "sdf" // 磁盘挂在Node0上
PCIBridge
PCI 8086:1521
Net L#13 "eth0"
PCI 8086:1521
Net L#14 "eth1" //网卡挂在node0上
PCIBridge
PCIBridge
PCI 1a03:2000
GPU L#15 "controlD64"
GPU L#16 "card0"
NUMANode L#1 (P#1 31GB) //都被我省略了
NUMANode L#2 (P#2 31GB)
NUMANode L#3 (P#3 31GB)
NUMANode L#4 (P#4 31GB)
NUMANode L#5 (P#5 31GB)
NUMANode L#6 (P#6 31GB)
NUMANode L#7 (P#7 31GB) //第1个Socket的最后一个Node
L2 L#14 (2048KB)
L1d L#56 (32KB) + L1i L#56 (32KB) + Core L#56 + PU L#56 (P#56)
L1d L#57 (32KB) + L1i L#57 (32KB) + Core L#57 + PU L#57 (P#57)
L1d L#58 (32KB) + L1i L#58 (32KB) + Core L#58 + PU L#58 (P#58)
L1d L#59 (32KB) + L1i L#59 (32KB) + Core L#59 + PU L#59 (P#59)
L2 L#15 (2048KB)
L1d L#60 (32KB) + L1i L#60 (32KB) + Core L#60 + PU L#60 (P#60)
L1d L#61 (32KB) + L1i L#61 (32KB) + Core L#61 + PU L#61 (P#61)
L1d L#62 (32KB) + L1i L#62 (32KB) + Core L#62 + PU L#62 (P#62)
L1d L#63 (32KB) + L1i L#63 (32KB) + Core L#63 + PU L#63 (P#63)
Package L#1 + L3 L#1 (64MB) //第二个Socket,也是8个Node
NUMANode L#8 (P#8 31GB)
L2 L#16 (2048KB)
L1d L#64 (32KB) + L1i L#64 (32KB) + Core L#64 + PU L#64 (P#64)
L1d L#65 (32KB) + L1i L#65 (32KB) + Core L#65 + PU L#65 (P#65)
L1d L#66 (32KB) + L1i L#66 (32KB) + Core L#66 + PU L#66 (P#66)
L1d L#67 (32KB) + L1i L#67 (32KB) + Core L#67 + PU L#67 (P#67)
L2 L#17 (2048KB)
L1d L#68 (32KB) + L1i L#68 (32KB) + Core L#68 + PU L#68 (P#68)
L1d L#69 (32KB) + L1i L#69 (32KB) + Core L#69 + PU L#69 (P#69)
L1d L#70 (32KB) + L1i L#70 (32KB) + Core L#70 + PU L#70 (P#70)
L1d L#71 (32KB) + L1i L#71 (32KB) + Core L#71 + PU L#71 (P#71)
HostBridge L#7
PCIBridge
PCIBridge
PCIBridge
PCI 15b3:1015
Net L#17 "eth2" //node8 上的网卡,eth2、eth3做了bonding
PCI 15b3:1015
Net L#18 "eth3"
PCIBridge
PCI 144d:a808
PCIBridge
PCI 144d:a808

不知名的一款CPU

当练习看看,随便看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#lscpu
Architecture: aarch64
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 1
Core(s) per socket: 128
Socket(s): 1
NUMA node(s): 2
Model: 0
BogoMIPS: 100.00
L1d cache: 64K
L1i cache: 64K
L2 cache: 1024K
L3 cache: 65536K
NUMA node0 CPU(s): 0-63
NUMA node1 CPU(s): 64-127

#free -g
total used free shared buff/cache available
Mem: 1007 160 511 0 335 840
Swap: 0 0 0

#lstopo-no-graphics
Machine (1008GB) + Socket L#0 (1008GB)
NUMANode L#0 (P#0 504GB)
L3 L#0 (64MB)
L2 L#0 (1024KB) + L1d L#0 (64KB) + L1i L#0 (64KB) + Core L#0 + PU L#0 (P#0)
L2 L#1 (1024KB) + L1d L#1 (64KB) + L1i L#1 (64KB) + Core L#1 + PU L#1 (P#1)
L2 L#2 (1024KB) + L1d L#2 (64KB) + L1i L#2 (64KB) + Core L#2 + PU L#2 (P#2)
L2 L#3 (1024KB) + L1d L#3 (64KB) + L1i L#3 (64KB) + Core L#3 + PU L#3 (P#3)
L2 L#4 (1024KB) + L1d L#4 (64KB) + L1i L#4 (64KB) + Core L#4 + PU L#4 (P#4)
L2 L#5 (1024KB) + L1d L#5 (64KB) + L1i L#5 (64KB) + Core L#5 + PU L#5 (P#5)
L2 L#6 (1024KB) + L1d L#6 (64KB) + L1i L#6 (64KB) + Core L#6 + PU L#6 (P#6)
L2 L#7 (1024KB) + L1d L#7 (64KB) + L1i L#7 (64KB) + Core L#7 + PU L#7 (P#7)
L2 L#8 (1024KB) + L1d L#8 (64KB) + L1i L#8 (64KB) + Core L#8 + PU L#8 (P#8)
L2 L#9 (1024KB) + L1d L#9 (64KB) + L1i L#9 (64KB) + Core L#9 + PU L#9 (P#9)
L2 L#10 (1024KB) + L1d L#10 (64KB) + L1i L#10 (64KB) + Core L#10 + PU L#10 (P#10)
L2 L#11 (1024KB) + L1d L#11 (64KB) + L1i L#11 (64KB) + Core L#11 + PU L#11 (P#11)
L2 L#12 (1024KB) + L1d L#12 (64KB) + L1i L#12 (64KB) + Core L#12 + PU L#12 (P#12)
L2 L#13 (1024KB) + L1d L#13 (64KB) + L1i L#13 (64KB) + Core L#13 + PU L#13 (P#13)
L2 L#14 (1024KB) + L1d L#14 (64KB) + L1i L#14 (64KB) + Core L#14 + PU L#14 (P#14)
L2 L#15 (1024KB) + L1d L#15 (64KB) + L1i L#15 (64KB) + Core L#15 + PU L#15 (P#15)
L2 L#16 (1024KB) + L1d L#16 (64KB) + L1i L#16 (64KB) + Core L#16 + PU L#16 (P#16)
L2 L#17 (1024KB) + L1d L#17 (64KB) + L1i L#17 (64KB) + Core L#17 + PU L#17 (P#17)
L2 L#18 (1024KB) + L1d L#18 (64KB) + L1i L#18 (64KB) + Core L#18 + PU L#18 (P#18)
L2 L#19 (1024KB) + L1d L#19 (64KB) + L1i L#19 (64KB) + Core L#19 + PU L#19 (P#19)
L2 L#20 (1024KB) + L1d L#20 (64KB) + L1i L#20 (64KB) + Core L#20 + PU L#20 (P#20)
L2 L#21 (1024KB) + L1d L#21 (64KB) + L1i L#21 (64KB) + Core L#21 + PU L#21 (P#21)
L2 L#22 (1024KB) + L1d L#22 (64KB) + L1i L#22 (64KB) + Core L#22 + PU L#22 (P#22)
L2 L#23 (1024KB) + L1d L#23 (64KB) + L1i L#23 (64KB) + Core L#23 + PU L#23 (P#23)
L2 L#24 (1024KB) + L1d L#24 (64KB) + L1i L#24 (64KB) + Core L#24 + PU L#24 (P#24)
L2 L#25 (1024KB) + L1d L#25 (64KB) + L1i L#25 (64KB) + Core L#25 + PU L#25 (P#25)
L2 L#26 (1024KB) + L1d L#26 (64KB) + L1i L#26 (64KB) + Core L#26 + PU L#26 (P#26)
L2 L#27 (1024KB) + L1d L#27 (64KB) + L1i L#27 (64KB) + Core L#27 + PU L#27 (P#27)
L2 L#28 (1024KB) + L1d L#28 (64KB) + L1i L#28 (64KB) + Core L#28 + PU L#28 (P#28)
L2 L#29 (1024KB) + L1d L#29 (64KB) + L1i L#29 (64KB) + Core L#29 + PU L#29 (P#29)
L2 L#30 (1024KB) + L1d L#30 (64KB) + L1i L#30 (64KB) + Core L#30 + PU L#30 (P#30)
L2 L#31 (1024KB) + L1d L#31 (64KB) + L1i L#31 (64KB) + Core L#31 + PU L#31 (P#31)
L2 L#32 (1024KB) + L1d L#32 (64KB) + L1i L#32 (64KB) + Core L#32 + PU L#32 (P#32)
L2 L#33 (1024KB) + L1d L#33 (64KB) + L1i L#33 (64KB) + Core L#33 + PU L#33 (P#33)
L2 L#34 (1024KB) + L1d L#34 (64KB) + L1i L#34 (64KB) + Core L#34 + PU L#34 (P#34)
L2 L#35 (1024KB) + L1d L#35 (64KB) + L1i L#35 (64KB) + Core L#35 + PU L#35 (P#35)
L2 L#36 (1024KB) + L1d L#36 (64KB) + L1i L#36 (64KB) + Core L#36 + PU L#36 (P#36)
L2 L#37 (1024KB) + L1d L#37 (64KB) + L1i L#37 (64KB) + Core L#37 + PU L#37 (P#37)
L2 L#38 (1024KB) + L1d L#38 (64KB) + L1i L#38 (64KB) + Core L#38 + PU L#38 (P#38)
L2 L#39 (1024KB) + L1d L#39 (64KB) + L1i L#39 (64KB) + Core L#39 + PU L#39 (P#39)
L2 L#40 (1024KB) + L1d L#40 (64KB) + L1i L#40 (64KB) + Core L#40 + PU L#40 (P#40)
L2 L#41 (1024KB) + L1d L#41 (64KB) + L1i L#41 (64KB) + Core L#41 + PU L#41 (P#41)
L2 L#42 (1024KB) + L1d L#42 (64KB) + L1i L#42 (64KB) + Core L#42 + PU L#42 (P#42)
L2 L#43 (1024KB) + L1d L#43 (64KB) + L1i L#43 (64KB) + Core L#43 + PU L#43 (P#43)
L2 L#44 (1024KB) + L1d L#44 (64KB) + L1i L#44 (64KB) + Core L#44 + PU L#44 (P#44)
L2 L#45 (1024KB) + L1d L#45 (64KB) + L1i L#45 (64KB) + Core L#45 + PU L#45 (P#45)
L2 L#46 (1024KB) + L1d L#46 (64KB) + L1i L#46 (64KB) + Core L#46 + PU L#46 (P#46)
L2 L#47 (1024KB) + L1d L#47 (64KB) + L1i L#47 (64KB) + Core L#47 + PU L#47 (P#47)
L2 L#48 (1024KB) + L1d L#48 (64KB) + L1i L#48 (64KB) + Core L#48 + PU L#48 (P#48)
L2 L#49 (1024KB) + L1d L#49 (64KB) + L1i L#49 (64KB) + Core L#49 + PU L#49 (P#49)
L2 L#50 (1024KB) + L1d L#50 (64KB) + L1i L#50 (64KB) + Core L#50 + PU L#50 (P#50)
L2 L#51 (1024KB) + L1d L#51 (64KB) + L1i L#51 (64KB) + Core L#51 + PU L#51 (P#51)
L2 L#52 (1024KB) + L1d L#52 (64KB) + L1i L#52 (64KB) + Core L#52 + PU L#52 (P#52)
L2 L#53 (1024KB) + L1d L#53 (64KB) + L1i L#53 (64KB) + Core L#53 + PU L#53 (P#53)
L2 L#54 (1024KB) + L1d L#54 (64KB) + L1i L#54 (64KB) + Core L#54 + PU L#54 (P#54)
L2 L#55 (1024KB) + L1d L#55 (64KB) + L1i L#55 (64KB) + Core L#55 + PU L#55 (P#55)
L2 L#56 (1024KB) + L1d L#56 (64KB) + L1i L#56 (64KB) + Core L#56 + PU L#56 (P#56)
L2 L#57 (1024KB) + L1d L#57 (64KB) + L1i L#57 (64KB) + Core L#57 + PU L#57 (P#57)
L2 L#58 (1024KB) + L1d L#58 (64KB) + L1i L#58 (64KB) + Core L#58 + PU L#58 (P#58)
L2 L#59 (1024KB) + L1d L#59 (64KB) + L1i L#59 (64KB) + Core L#59 + PU L#59 (P#59)
L2 L#60 (1024KB) + L1d L#60 (64KB) + L1i L#60 (64KB) + Core L#60 + PU L#60 (P#60)
L2 L#61 (1024KB) + L1d L#61 (64KB) + L1i L#61 (64KB) + Core L#61 + PU L#61 (P#61)
L2 L#62 (1024KB) + L1d L#62 (64KB) + L1i L#62 (64KB) + Core L#62 + PU L#62 (P#62)
L2 L#63 (1024KB) + L1d L#63 (64KB) + L1i L#63 (64KB) + Core L#63 + PU L#63 (P#63)
HostBridge L#0
PCIBridge
PCIBridge
PCI 1a03:2000
GPU L#0 "controlD64"
GPU L#1 "card0"
PCIBridge
PCI 1b4b:9235
HostBridge L#4
PCI 1ded:8001
PCI 1ded:8003
NUMANode L#1 (P#1 504GB)
L3 L#1 (64MB)
L2 L#64 (1024KB) + L1d L#64 (64KB) + L1i L#64 (64KB) + Core L#64 + PU L#64 (P#64)
L2 L#65 (1024KB) + L1d L#65 (64KB) + L1i L#65 (64KB) + Core L#65 + PU L#65 (P#65)
L2 L#66 (1024KB) + L1d L#66 (64KB) + L1i L#66 (64KB) + Core L#66 + PU L#66 (P#66)
L2 L#67 (1024KB) + L1d L#67 (64KB) + L1i L#67 (64KB) + Core L#67 + PU L#67 (P#67)
L2 L#68 (1024KB) + L1d L#68 (64KB) + L1i L#68 (64KB) + Core L#68 + PU L#68 (P#68)
L2 L#69 (1024KB) + L1d L#69 (64KB) + L1i L#69 (64KB) + Core L#69 + PU L#69 (P#69)
L2 L#70 (1024KB) + L1d L#70 (64KB) + L1i L#70 (64KB) + Core L#70 + PU L#70 (P#70)
L2 L#71 (1024KB) + L1d L#71 (64KB) + L1i L#71 (64KB) + Core L#71 + PU L#71 (P#71)
L2 L#72 (1024KB) + L1d L#72 (64KB) + L1i L#72 (64KB) + Core L#72 + PU L#72 (P#72)
L2 L#73 (1024KB) + L1d L#73 (64KB) + L1i L#73 (64KB) + Core L#73 + PU L#73 (P#73)
L2 L#74 (1024KB) + L1d L#74 (64KB) + L1i L#74 (64KB) + Core L#74 + PU L#74 (P#74)
L2 L#75 (1024KB) + L1d L#75 (64KB) + L1i L#75 (64KB) + Core L#75 + PU L#75 (P#75)
L2 L#76 (1024KB) + L1d L#76 (64KB) + L1i L#76 (64KB) + Core L#76 + PU L#76 (P#76)
L2 L#77 (1024KB) + L1d L#77 (64KB) + L1i L#77 (64KB) + Core L#77 + PU L#77 (P#77)
L2 L#78 (1024KB) + L1d L#78 (64KB) + L1i L#78 (64KB) + Core L#78 + PU L#78 (P#78)
L2 L#79 (1024KB) + L1d L#79 (64KB) + L1i L#79 (64KB) + Core L#79 + PU L#79 (P#79)
L2 L#80 (1024KB) + L1d L#80 (64KB) + L1i L#80 (64KB) + Core L#80 + PU L#80 (P#80)
L2 L#81 (1024KB) + L1d L#81 (64KB) + L1i L#81 (64KB) + Core L#81 + PU L#81 (P#81)
L2 L#82 (1024KB) + L1d L#82 (64KB) + L1i L#82 (64KB) + Core L#82 + PU L#82 (P#82)
L2 L#83 (1024KB) + L1d L#83 (64KB) + L1i L#83 (64KB) + Core L#83 + PU L#83 (P#83)
L2 L#84 (1024KB) + L1d L#84 (64KB) + L1i L#84 (64KB) + Core L#84 + PU L#84 (P#84)
L2 L#85 (1024KB) + L1d L#85 (64KB) + L1i L#85 (64KB) + Core L#85 + PU L#85 (P#85)
L2 L#86 (1024KB) + L1d L#86 (64KB) + L1i L#86 (64KB) + Core L#86 + PU L#86 (P#86)
L2 L#87 (1024KB) + L1d L#87 (64KB) + L1i L#87 (64KB) + Core L#87 + PU L#87 (P#87)
L2 L#88 (1024KB) + L1d L#88 (64KB) + L1i L#88 (64KB) + Core L#88 + PU L#88 (P#88)
L2 L#89 (1024KB) + L1d L#89 (64KB) + L1i L#89 (64KB) + Core L#89 + PU L#89 (P#89)
L2 L#90 (1024KB) + L1d L#90 (64KB) + L1i L#90 (64KB) + Core L#90 + PU L#90 (P#90)
L2 L#91 (1024KB) + L1d L#91 (64KB) + L1i L#91 (64KB) + Core L#91 + PU L#91 (P#91)
L2 L#92 (1024KB) + L1d L#92 (64KB) + L1i L#92 (64KB) + Core L#92 + PU L#92 (P#92)
L2 L#93 (1024KB) + L1d L#93 (64KB) + L1i L#93 (64KB) + Core L#93 + PU L#93 (P#93)
L2 L#94 (1024KB) + L1d L#94 (64KB) + L1i L#94 (64KB) + Core L#94 + PU L#94 (P#94)
L2 L#95 (1024KB) + L1d L#95 (64KB) + L1i L#95 (64KB) + Core L#95 + PU L#95 (P#95)
L2 L#96 (1024KB) + L1d L#96 (64KB) + L1i L#96 (64KB) + Core L#96 + PU L#96 (P#96)
L2 L#97 (1024KB) + L1d L#97 (64KB) + L1i L#97 (64KB) + Core L#97 + PU L#97 (P#97)
L2 L#98 (1024KB) + L1d L#98 (64KB) + L1i L#98 (64KB) + Core L#98 + PU L#98 (P#98)
L2 L#99 (1024KB) + L1d L#99 (64KB) + L1i L#99 (64KB) + Core L#99 + PU L#99 (P#99)
L2 L#100 (1024KB) + L1d L#100 (64KB) + L1i L#100 (64KB) + Core L#100 + PU L#100 (P#100)
L2 L#101 (1024KB) + L1d L#101 (64KB) + L1i L#101 (64KB) + Core L#101 + PU L#101 (P#101)
L2 L#102 (1024KB) + L1d L#102 (64KB) + L1i L#102 (64KB) + Core L#102 + PU L#102 (P#102)
L2 L#103 (1024KB) + L1d L#103 (64KB) + L1i L#103 (64KB) + Core L#103 + PU L#103 (P#103)
L2 L#104 (1024KB) + L1d L#104 (64KB) + L1i L#104 (64KB) + Core L#104 + PU L#104 (P#104)
L2 L#105 (1024KB) + L1d L#105 (64KB) + L1i L#105 (64KB) + Core L#105 + PU L#105 (P#105)
L2 L#106 (1024KB) + L1d L#106 (64KB) + L1i L#106 (64KB) + Core L#106 + PU L#106 (P#106)
L2 L#107 (1024KB) + L1d L#107 (64KB) + L1i L#107 (64KB) + Core L#107 + PU L#107 (P#107)
L2 L#108 (1024KB) + L1d L#108 (64KB) + L1i L#108 (64KB) + Core L#108 + PU L#108 (P#108)
L2 L#109 (1024KB) + L1d L#109 (64KB) + L1i L#109 (64KB) + Core L#109 + PU L#109 (P#109)
L2 L#110 (1024KB) + L1d L#110 (64KB) + L1i L#110 (64KB) + Core L#110 + PU L#110 (P#110)
L2 L#111 (1024KB) + L1d L#111 (64KB) + L1i L#111 (64KB) + Core L#111 + PU L#111 (P#111)
L2 L#112 (1024KB) + L1d L#112 (64KB) + L1i L#112 (64KB) + Core L#112 + PU L#112 (P#112)
L2 L#113 (1024KB) + L1d L#113 (64KB) + L1i L#113 (64KB) + Core L#113 + PU L#113 (P#113)
L2 L#114 (1024KB) + L1d L#114 (64KB) + L1i L#114 (64KB) + Core L#114 + PU L#114 (P#114)
L2 L#115 (1024KB) + L1d L#115 (64KB) + L1i L#115 (64KB) + Core L#115 + PU L#115 (P#115)
L2 L#116 (1024KB) + L1d L#116 (64KB) + L1i L#116 (64KB) + Core L#116 + PU L#116 (P#116)
L2 L#117 (1024KB) + L1d L#117 (64KB) + L1i L#117 (64KB) + Core L#117 + PU L#117 (P#117)
L2 L#118 (1024KB) + L1d L#118 (64KB) + L1i L#118 (64KB) + Core L#118 + PU L#118 (P#118)
L2 L#119 (1024KB) + L1d L#119 (64KB) + L1i L#119 (64KB) + Core L#119 + PU L#119 (P#119)
L2 L#120 (1024KB) + L1d L#120 (64KB) + L1i L#120 (64KB) + Core L#120 + PU L#120 (P#120)
L2 L#121 (1024KB) + L1d L#121 (64KB) + L1i L#121 (64KB) + Core L#121 + PU L#121 (P#121)
L2 L#122 (1024KB) + L1d L#122 (64KB) + L1i L#122 (64KB) + Core L#122 + PU L#122 (P#122)
L2 L#123 (1024KB) + L1d L#123 (64KB) + L1i L#123 (64KB) + Core L#123 + PU L#123 (P#123)
L2 L#124 (1024KB) + L1d L#124 (64KB) + L1i L#124 (64KB) + Core L#124 + PU L#124 (P#124)
L2 L#125 (1024KB) + L1d L#125 (64KB) + L1i L#125 (64KB) + Core L#125 + PU L#125 (P#125)
L2 L#126 (1024KB) + L1d L#126 (64KB) + L1i L#126 (64KB) + Core L#126 + PU L#126 (P#126)
L2 L#127 (1024KB) + L1d L#127 (64KB) + L1i L#127 (64KB) + Core L#127 + PU L#127 (P#127)
HostBridge L#5
PCIBridge
PCI 8086:0b60
HostBridge L#7
PCIBridge
PCIBridge
PCIBridge
PCI 1af4:1001
PCIBridge
PCI 1ded:1001
PCI ffff:ffff

总结

希望通过具体又不同的CPU案例展示,让你对CPU的结构有一些整体认识

请问:Hygon C86 7260 这块CPU每个Die的L2、L3分别是多大?

请思考,最近10年CPU的性能没啥大的进不了(如下图红色部分,每年3%),但是这么多年工艺还在进步,集成的晶体管数量

img

//这张图每一本计算机体系结构的教材都有引用(没有的话这教材可以扔了),你知道我博客里哪篇文章放了这图吗?从这个图你还能解析出来哪些东西?

你要不要搞副业

你要不要搞副业?

最近网上看到很多讨论搞副业和远程工作的,我也说点自己的经验+看法

当然这完全是出于个人认知肯定不是完全对的、也不一定适合你,看看当个参考,经验重在真实

结论

年轻人最好的副业就是做好本职工作,深耕多积累自己的专业方向,只有当你在主业上再也无法精进的时候可以考虑跳槽或者副业, 搞副业相对适合大多年纪大的人,他们触碰到了自己的天花板,可以折腾玩玩等等

我搞过的副业

我搞过很多副业,多到我不好意思说出来。low到檫玻璃,大到开厂、买船,但是你看就是没去折腾抄房子(这些年只有炒房子的这个副业赚钱最稳、最快)。我也特别关心别人的副业、主业,熟的会打破砂锅问到底,所以下面说的只保证真实

最大一笔副业

通过SEO接了一个国外一个订单,交给长三角的工厂代工,赚了几十万,一次性,几乎没有成本

当时帮一个做工厂的朋友做网站,域名空间都是我掏钱(要给我我没好意思要,本身不值钱),让留个邮箱厂长没有,后来留的我的。

然后来了几个咨询的介绍给厂里了,最后成了两个客户。但是有一个韩国客户(采购是广州一个提篮子的公司),去厂里谈了几次细节谈不好,我就出马给把细节、打样、交货谈好了。

最后做好后发货直接到韩国,发一次运费几万块(到付),其中有一批压坏了点那个区的顺丰经理过来道歉、给定做包装箱……

缺点是做完就没有了,那个产品不具有持续性,如果可以持续我应该能继续搞,另外借着这个客户去厂里跑得多,也发展了一些其他客户利润太薄加上后来真个行情不好就实在做不下去了,产品烂大街没人要了,珠三角那个生产模仿能力都太强了

之前介绍给厂里的两个客户,厂里自己对接的,其中一个厂里赚了一些钱,另外一个飞单好几十万,人家直接注销公司赖账的玩法,所以你看风险很多。不过要是去接这个单就不会出现这种情况,你最后尾款飞几千万把块我是有预期的,整个一个订单一分钱都没拿到简直就是傻子做生意,也纵容了坏人

比如很多人靠白嫖样品吃饭,我的策略是:样品、打样都要收钱,但是正式下单就抵扣货款,这么做能淘汰90%的虚假用户,节省自己的时间。比如便宜样品可以免费但是邮费到付、你亲自上门当然可以送几个。

知识星球总结

做星球的话10万粉丝算是凑合,百万粉丝洒洒水啦,几万粉丝很痛苦

知识星球不适合IT技术类,他们有平台的流量,全靠自己运营;相对来说极客时间、慕课之类的能有平台给你导流;

星球的优点是入门门槛低

我的星球数据

开星球的时候就承诺过了,要公布数据,当时也有一部分原因是对运营一个星球的数据有着好奇

9个月的星球运营500多成员,一年收入大几万,这还只是第一年,主要靠我的推特3万多粉丝里面划拉人员过去,第二年就不会有这么多成员了,因为你不可能一年再涨2万新粉丝

我的粉丝转化率是2%,算是还不错的了,所以如果你有10万粉丝大概能有1000-2000铁粉,那差不多一年能靠这些有个20来万的收入,所以算还凑合,可以简单养家。

上点我的星球运营真实数据,先看最重要的收入数据

image-20231221090708084

星球刚开通前三个月收入最高,把一年的收入都提前拿走了,我这虽然才9个月,后面三个月也不用看了,几乎可以忽略:

image-20231221090758574

运营效果,来估算转化率

image-20231221090420085

我的星球讲究干货,宁缺毋滥,所以也没有其他星球常用的运维手段:作业、打卡(我恨死打卡这种傻逼行为了)

续费的话,我的星球是本月15号开通续费,我也没发通知,居然有人续费了,我猜应该是平台自动通知的:

image-20231221094647500

星球总结

  • 程序员成功的星球都是靠贩卖焦虑、offer、算法、面试,所以你真要想搞不要想着自己技术多好,要想想你有没有适合拿offer(这个活该赚钱)的本领
  • 星球的活跃度靠打卡
  • 搞一些有流量的好朋友互相吹捧、交换粉丝

带货

这个门槛最低,你看到好的产品复制链接,到淘宝联盟上做下链接转换:https://pub.alimama.com/?forward=http%3A%2F%2Fpub.alimama.com%2Fportal%2Feffect%2Forder%2FoverviewOrder%2Fpage%2Findex.htm#!/index?curValue=nav_0&forward=

到处发然后就能拿佣金了,目前国内个人带货扛把子就是个程序员,还是个高中毕业考不上大学找个培训班入行的程序员,会用Delphi写个群发工具,然后管理一堆微信、QQ群;让别人去帮他带货他能提成,这个段位又高级了一层

只靠自己的朋友圈肯定是不行的,起步得是百万粉丝才行,或者你有渠道总能搞到好的货品

给你们贴个我2023年10月的带货数据,当个参考,就是在3万粉丝的推特上带的货,转换率肯定是很惨的,为这131块的佣金你可以搜搜我发了多少推:

image-20231221092640430

这个工作完全可以远程——算是你们理想中的远程工作吗?但是这个市场必然只能容纳很少的人,搞好了是可以发财的 :)

如果你口才好、煽动力强不去搞自播带货都对不住自己

为什么不推荐搞副业

副业就是副业,要不怎么不叫主业呢?真搞好了、容易搞好必然有更多的人进来把他从副业做成主业!

先把主业搞好,尤其是年轻人。副业超过主业的毕竟是极少极少,还有点运气和背景成分

投入小(钱、时间都算)可以轻度参与混点经验,但不要抱太高期望

比如我就做过统计:

拉了一下记账软件上历年的数据,古早年代没记账就没有了,最近几年收入的话95%以上都是工资性收入,投资大概率是亏钱的,房租能有点、外快能有点,放到整体几乎可以忽略

开支的话也他妈主要是买房+房贷,如果不考虑首付+提前还贷倒是占比不夸张,日常开支真用不了多少钱,万幸几乎没有医疗开支

主业确定没法精进、跳槽之类的,这时可以考虑下副业,当然如果你碰到了副业的“好机会” 也可以尝试一下

建议

先试试做做博客、公众号,看自己能运营到多少粉丝,你平时上网刷口水文章也是打发,然后试试带货

程序员方向基本不来钱,虽然这些行业很赚钱,但是这里也聚集了相对聪明人,你能搞他们也能搞相对更红海一些

可以跳出技术方向或者横向关联的方向多动动脑子,门槛低竞争就必然大,比如教英语和教程序员肯定英语的市场大多了

组织活动,比如组织大家打羽毛球、滑雪,羽毛球需要水平差不多的、人多一点才好玩,一般去场馆8折拿下场地,然后大家AA费用,赚这2折的差价,一次一般能赚80块,一周多组织几次,搞得好的话一个月也有2000块,关键是顺便自己打打球,真当副业的话也很香!再要多赚也很难,不过可续性很强

上次从黄牛手里买了个医院的专家号,2000块,你以为他们有渠道?其实他们建个微信群,找一堆有闲缺钱的人,接到需求了就到群里喊一嗓子,谁有本事抢到了从2000块里分几百,这种专家号根据难易程度从几百块到几千块,真是市场化了

当然还有一些灰产黑产大家就不要碰了我也不说了,大家耗子尾汁,赚钱是应该的但是要合法

写得很零散,没有什么详细的分析和套路,就是罗列事实和数据,你可以根据自己的情况来分析考虑

你要有什么好建议和经验欢迎在推特上 @plantegg 给我留言、私信,特别好的我会收集到博客上,这篇博客我会持续更新……

最后放个我星球的广告

image-20230407232314969

王强2012在北大的演讲——读书毁了我

王强2012在北大的演讲——读书毁了我

视频版本50分钟,不含问答,建议看文字版,这是视频: https://weibo.com/6033438343/Nxw2Fj2oN?pagetype=profilefeed

我为什么要发这篇

到处都是私域、卖货、视频等,好的文字不多了,这篇对应视频的文字版找起来不容易,所以特意在我的博客上备一份(我的博客极少极少极少发别人的东西),也希望你备份一下。

王强是新东方合伙人,口才一流、演讲技能一流,当脱口秀看吧。

我就只能羡慕这种智商一流的人,这人智商在北大里估计都是前10%,而你我是北大都考不上的,所以他说的方法你就看看好了,不适合你,但值得你从中间提炼适合你的不分,读经典拿书,读不懂就不要像他一样死磕,找些浅显的、增加你经验的书先看看,回头再来读经典

但大多时候我们都不知道哪些是经典,对别人是经典对你还是经典吗?

这人是个程序员,学了C 和CPP,对你有点参考意义

在我的知识星球就一直强调:不要跟着信息流跑,多去看最早发表的东西(多年沉淀的干货等等)

image-20231219105757910

下面是正文,扯淡栩栩如生,那不是重点。我就不给大家划重点了,都是重点:) ,文字版来自这里:https://book.douban.com/review/10286767/

演讲正文——读书毁了我

王强:谢谢小平。因为小平在读书上花的时间比较少,因为我都替他读了,他只问我结论是什么,他的知识并没有落后,而我视力在衰减。当然老俞,当年我引他进入读黄色小说的境界,至今老俞还不肯自拔,他是黄种人的代表,所以他成功了。作为人生,我今年51岁,我和老俞同年同月生,不是同一天,也不是同一个地方,因为老俞比我大一周,小平比我大六岁,是我的兄长,当年克强同志是北大团委书记,他直接受克强同志领导的北大团委文化部部长,我是直接受徐小平同志掌管的第一任北大学生艺术团团长,我当时管的是英达、英壮这样的人。而俞敏洪是北大最有特权的艺术团的观众,因为经常拉幕的时候缺一个人,我们说老俞能不能帮帮忙,老俞说能让我看吗,我说当然。所以从此老俞锻炼了强大拉幕能力。所以任何细节不要忽略,都是人生。

我今天想跟大家分享为什么读书在人的生命成长中非常重要。我这个题目叫”读书毁了我”,很多读者没看到这本书的内容就开始评论,说我是标题党,撒狗血。我说不是我撒,因为当年我的很多文章结集的时候徐晓,她是中国最伟大的女编辑之一,被称为京城四大美编,美女编辑。当年我说马云怎么有领袖魅力,他有领子有袖子,但没有领袖魅力,走到街上城管一定第一个扑向他,因为连人长的都不一样,像是从外星回来的,而俞敏洪长的就跟季羡林一样,就像去外星的人。小平虽然是天使,但是从体重来说,给他四双翅膀他也飞不起来。所以人啊,当你不知道要做什么事情,当你做的事情不能带给社会意义的时候,当你做的事情的意义不能给人的生命产生共鸣的时候,你的存在实际上是被人忽略的。

我现在自豪的是,我现在经常回忆,北大这个地方怎么产生企业家?因为我是内蒙古来的,我以为是学术的殿堂,清华可能产生企业家,因为他们搞科技,高科技,北大当年我们就是精神自由的三角地,都是自焚的地方,它只是结束肉体的地方,让灵魂再生的地方,从来不是做什么上市,这些好象与北大没关,但是人生经历这么多年,我发现北大为什么产生这样的人。

我就拿32楼举例,我们住的16楼没了,当时我和老俞作为北大年轻教师住在16楼,但是拿32楼文科男科楼讲,当时北大英文系来说,我们住在二层,这些年一过,发现诞生一个伟大的企业,那就是在教育界的俞敏洪为代表的新东方。再往第三层,我忽然发现当年有一个来自山西的青年,天天在水房里光着上半身,一盆冷水浇下来,唱着夜里寻他千百度,你在哪呢,天天念百度两个字,因为他是北大图书馆系的,后来诞生了百度李彦宏,当时哪能想到,因为从任何知识储备,他不能做企业,他不仅是学图书馆系,而且专业简直离成功太远,他是古典文献编目专业,清朝以后的事他都不管了,他直接奔甲骨文去了。所以他天天念where are you,那时一下雨雨水就没过膝盖,当时找不到了,where are you,搜索就开始了。

再往上走,四层楼住着北大中文系的,当年都是产生愤怒诗人,连名字都是愤怒的不得了,黄怒波。这么多年刮目相看,他要买下冰岛,他成为了中坤集团的创始人。更匪夷所思的是,北大中文系的女生楼里出来一个长相非常平和的人,她充满着激情,最后由于自己解决终身的情感问题,她就是后来创造了世纪佳人。这些人,是中文系的、图书馆系、英文系,这些与金融、融资、管理完全没关,但是我后来想怎么会出现这么一些奇特的企业,由这些人做的,我就想到北大给了一个东西,就是怎么样塑造你生命的东西,那是对知识的渴望、饥饿,超过了性本身。当年我们对性的渴望,但是校规非常严格,同性只能找同性。但是我们还没有得到同性方面的启蒙,当时洗澡堂,一个水龙头下,十个男生光溜溜的彼此互帮互学,那一个水龙头下十个手,像董存瑞炸碉堡的感觉。

但是我们就这么过来的,为什么我发现北大这个氛围是崇尚超越世俗吸引力的更伟大的东西,那就是对知识的诉求。我不知道你们现在读书状况什么样,整个八十年代北大最神圣的地方两个地方,一个是厕所,一个是图书馆,图书馆从早上六点,如果你不能到达写着邓小平题字的北京大学图书馆下面排队,你这一天与图书馆的座位已经无缘了,所以大部分人凌晨四点就起来了,然后带着一个冷馒头,从厨房吃剩下的或者从同学那偷来的,俞敏洪经常偷我馒头。然后借一堆书放在这里,睡也睡在桌子前面。所以当年读书氛围非常好,如果市场上出现一本书,你如果去晚了根本的得不到。我在中文系选了中国现代文学史,第一次讲到围城,我赶快到北大图书馆,没下课我就去了,但是没想到没了,结果等到快毕业的时候我才借到这本书,这就是当年北大的状况。而正是这样,读经典,读那些能够改变我们生命轨迹的那些书籍,成了北大人最后离开校门走到世界,不管你走到哪个领域,最后比别人走的稍微远一点的保证,因为那些书不是字,它也是生命,而这些生命比起你自己的生命来说,它能引领你的生命,它能型塑你的生命,所以我说这个世界上只有两种文字,一类文字是文字垃圾,(Informed )随处可得;但是有一类是非常好的,(Form you )就是它能够把你变成完全不同的另一个。所以我这个书题目叫读书毁了我,当年起的时候,徐晓给我提的题目,说这个题目在她心中好多年。她说你这个文字挺适合这个,我说”读书毁了我”,这个东西大家看到以后会非常奇怪,怎么会毁了你吗?她说毁就跟北京人说的,一团泥逐渐成型,就成了崭新的东西。我想如果毁用在这个意义上,它必须能够彻底摧毁你旧我,过去的我,狭隘封闭的我,然后诞生一个崭新的、开阔的、阳光的我,那读书就全部有了意义,这也就是当年北大为什么那些人天天想到的不是世俗的追求,但是到了世俗里一看,稍微一动他就得到了所谓世俗追求的东西呢?我觉得这是北大给了我们吸取信息的能力,分析问题能力,所以我今天想跟大家分析分析读书。

我当年在新东方接受采访的时候,我说要读书只读一流的书,做人只做一流的人。为什么这么说?因为现在信息充斥的海洋里,我们人生有幸,但是我们要读的接受的信息太多了,如何辨别书?什么东西该读呢?跟大家分享一下我读书的选择,第一,畅销书我坚决不读,不是我牛,看不起畅销,因为我知道我生命有限,已经51岁了,再向苍天借30年,我已经80岁了,所以我还有30年读书的时间,我只能读人类历史上没被大浪淘沙过的东西,所以我现在读书越来越往前读,中国的典籍越读越遇到先秦,西方也顶多读到二十世纪中叶,因为我觉得那个时候的人,他们创作文字,他们的文字是他生命的写照。比如说现在翻译小说,坦率的讲,我只选择那些真正的以生命完成一部译作的大家们的作品,哪怕这个作品并不时髦。比如说《悲惨世界》,李丹翻译,本来他可以成为另一个徐悲鸿,但是他们放弃了,几十年如一日,文革如此惨烈,李丹最后剩几卷没有翻,他的太太继续翻,这本著作我是一读再读。像朱生豪翻了27本莎士比亚的剧,但是你现在再读任何一本,哪能找到朱生豪当年用汉字表现出的莎士比亚。所以我常常更小平说,有一天我们一定要拍朱生豪的电影,这个电影叫做《莎士比亚在中国》,如果没有朱生豪,全世界四分之一的人不会第一时间知道还有莎士比亚,所以莎士比亚的墓地应该旁边有一个朱生豪的碑,多么伟大,四分之一的人口是通过朱生豪第一时间知道的英国还有一个莎士比亚。

所以我觉得读一流的书就要衡量,这个作家进入书前的状态是什么?他是为了满足市场的需求,所谓市场的利益,还是他倾其鲜血、生命和经历融入的东西呢?坦率的讲,我在北大整整呆了十年,做了四年学生,当了六年老师,离开的时候是英语系的讲师,当然我的宿命也从此定了,只能讲,没当教授,坐不下来,更没有博导那个肌肉。但是我作为见证,俞敏洪、小平他们当年都是如饥似渴的在读书,尽管领域不同。老俞主管肉体,小平是超越肉体和灵魂的东西。当年小平是我们当中第一个出国的,我记得那天下着毛毛细雨,小平当年住在北大小院,32楼前面的一个小院,最早北大出版社的地方,他住在那里,因为他是团委干部,所以有四合院的那种感觉。那说要离开了,要到美国,然后到加拿大去追求他的音乐梦,我就知道,他当时为凑足他的机票,他珍藏了作为任何一个学生很难想象的格罗夫音乐辞典,到处拍卖,他希望获得飞到美国的机票。他终于卖出了,用一半的钱请我在西门一个火锅店吃了火锅,最后大家挥泪离别,从此我步上小平的后尘,我也要到国外去,老俞也想步我们的后尘,但是国外暂时不需要他。

为什么读经典能够改变我们呢?文学的功能是什么呢?在我看,文学的功能就像我在序里说的,如果一个真正有力量的文字,它一定是能够对我们的审美产生奇异的再造,它对我们对真的追求有奇异的启示,它对我们对善的追求有如饥似渴的充电的感觉,所以我们对人类最高的价值,真的、善的和美的就会变成我们的血液,一旦人身体里有这三样东西,你在社会上走向现实中,你就不会轻易的被世俗的所谓流行的价值、暂时的价值,甚至非常糟糕的价值轻易扭转。我的这个读书基因从这开始,从我中学,我分两个阶段,一个是中学,一个是北大。我之所以能进北大,一半我认为是老天眷顾了我,因为大家知道,我是第三届大学生,小平是第一届,克强是78级,克强比你低一级,但现在比你高很多级,这就是人生最后不一样的东西。所以人生,体重太大,最后他也走不太远,所以大家现在要减肥。

高中我是来自内蒙古,我们那个学校在当地有一个叫包头的地方,都不算是优秀学校,但是为什么我能够走进北大呢?我忽然怀念起我当时在高中遇到的一批中国我认为最顶级的老师,为什么这些老师会到包头呢?感谢文化大革命,全是右派,一个一个发配到包头,结果被我遇上了,他们教会我全部的东西都是以他们各自的方式告诉我,真的、善的、美的,一定是从那些流传在人类时间长河里面没被淘汰的文字中,存在那里。你如果不断的在这样的文字中熏陶的时候,当你离开这些文字的时候,这些文字就变成了你的世界,所以从单词word到world中间只差一个字l,这个L,这就是文字、阅读和真正人生世界的完全最简单的逻辑关系。如果你读到的不是真文字,你遇到的不是真语言,你最后见到的一定是虚幻的世界,不是真实的世界。这也是为什么读书真正要对你产生作用,会产生什么呢?它一定要和你真正的生命融汇在一起,而几千百年来,没有被淘汰的著作,因为一代代人如果都这么选择的话,你一定要相信人类的选择,而不是现在市场的选择,更不是广告词的选择。所以这是非常关键的,我在序言里提到,去年我写了一篇文章,其中谈到葡萄牙诗人佩索阿,其中有一个诗写的是小河和村庄的关系,点清了我心目中文字怎么和你生命世界在一起,它必须对你生命产生极强的冲击,这个书才值得读,或者你真正领悟这本书,所以他的诗也是我从英文翻译过来的,他说,塔古斯河美过我村庄的那条小河,但是塔古斯河又美不过流进我村庄的小河,因为塔古斯河不是流经我村庄的小河。太美了,为什么?文字如果不属于你的村庄,它不能流穿你的灵魂,这个书不值得一读,而真正传统的经典有穿透生命力的这种力量。

我回到高中,我怎么认识到什么是一流的书呢?随便举个例子,我感谢文化大革命,把这些有文化的人推到内蒙古这个没文化的地方,教我古典文学的王传真老师,现在这些老师全都去世了,包括我大学的老师,大部分都已经不在了。但是这些高中老师教我古典文学的王传真老师,我第一次上他课的时候忽然发现什么叫大师,王老师告诉我们去新华书店买《古文观止》,中华书局第一版的。然后他说,你们要听懂我的课,这个假期必须做一件事,买来这个课本,他不讲,他拿出一套油印印出来的厚厚一叠古文,标点全部隐去了,他说你们这个假期玩完了以后,你就去读读我这个自己刻印出来的东西,然后按照你全部的理解,使出你全部的工具来给这些文章,按照你的理解给它们加以标点,我们在没有走进古文的世界,这个东西既刺激也似乎不可能,但是我为了下学期听懂王传真老师的课,我从我爸箱子里翻出他爸给他留下的当年最老版的辞海,我开始一个一个的,每天以十个字的速度往前运行,整整三个月我没干别的,因为越往前走越觉得这里深不可测,但是我的梦想是一定要听到王老师的讲解,因为这是他对我们唯一要求。结果就乱标点,但是我一天以十个字的功夫不断的往前进,最后50篇文章被我标点了。等到王老师到我面前给我面试的时候,他随便说了几句,我基本背出来之后,他说了两点,第一,你的标点全错了。第二,孺子可教,因为你全标了,就是你这个努力,我觉得可以。其实当老师,有的时候非常充满智慧,我们的胡校长胡适,胡适不判作文的,他没有时间,他有时间要搞新文化运动,作业算什么。但是据说,上作文的课每次都能给出学生成绩,后来据他的学生回忆,胡适判作业那是胡判,他今天晚上吃完饭,收了几十份作业,你写了文章,他开始把桌椅放在离靠门半米远的地方,泡一杯清茶,然后扔作业,哪个扔的最远最高分,为什么?写的多,不管你写的怎么样,你下了苦功。别人一扔不远,零分,写的不多。扔的远,够份量,一百分,胡判定就要开始出来。

而且我当时,我怎么走到英文这个道路上,一流的书上来直接读《古文观止》就可以了,看似很艰难,但是读完全部启蒙的古文书,我再读人教的那些太简单了,因为你的制高点不一样,一流书、二流书、三流书区别在这。比如英文,老俞就没有遇到我这样的老师,今天还说着印度人非常理解的英语,但是到了美国就崩溃了,因为他是印度籍的移民。我这个英文老师学俄语,英文不太懂。但是这个老师一片真诚,他知道该给学生什么样重要的价值,怎么让英文走进你的生命。上了他第一堂课,他觉得我的两个眼睛不断的盯着他,两耳竖着,像狼犬一样,他说你真心想学英文吧?我说当然,上您的课厕所都忘了。他说王强你到我办公室。当天下午在他办公室他说了一句话,他说从此你要上我的课。我说老师我就想学英文。他说我教不了正经的英文,我的底子我自己知道,你要想学真正的英文,我给你想办法,你就不用上我的课。第二天下午4点,下了自习,他把我叫到他办公室,从黑皮兜里掏出旧报纸包的东西,把慢慢打开,一打开,我一看,是一个断了一角的黑色的绞盘,唱盘,叫LP,大唱盘,你们现在连CD都不用了,那个大唱盘这么大,他说王强你要跟这个学,这是什么呢?这是我从废品站几年前搜集到的东西,它是BBC英国广播公司出的一套经典英文教材,从明天起,每天下午四点你只要答应我一件事,不要回家,来跟我学。后来我就非常兴奋,第二天我拿到这个光盘以后就跟着他,他把我领到学校的广播间,那时候他把团旗往窗户上一盖,门外面挂着闲人莫进,正在录音。然后他用当年我们中学唯一的手摇唱机,跪在地上,他一边给我摇,一边让我赶快重复,而且说你这个课本永远在我手里,等到你全部的课本能够背答入流的时候,你就成就了。结果他做了一件事,每个礼拜都这样,最后倒背如流的时候,他把这页撕掉了,所以我这个课本越学越少,最后只剩下封底的时候,他说王强你可以毕业了。我忽然意识到,我离开了文字的课本,但这些东西全在我身上,所以等到我到北大,作为英语系的学生第一年入的时候,在我们班50个人中,只有我说的着流畅的英语。为什么?他们不知道来自一个内蒙古包头的,别说英语,汉语都不沾边际的,说蒙古话的人,能说如此好的英语。其实我没有学任何东西,就是破唱盘和破唱机,一摇、一摇,摇过了一两百页的篇幅,这些篇幅被老师扔进垃圾堆的时候,我发现他让一流的英文教材完全引入到我的灵魂中,我感谢他。

教我历史的老师让我有了进北大的冲动,为什么?他是南京大学太平天国专业毕业的,学了五年,最后被打到包头,他讲历史,我听的如痴如醉。这个老师爱流鼻涕,历史长河,源源不断。而且这些老师,我不仅跟他们学读书,我从他们做人也学到了品性,就是一个字-真,最崇尚的就是真。这个老师非常有意思,他看我非常好学,他希望我每个礼拜三天到他家,那时候肉是供应的,那时候我已经是中学学生,老师为了让我安心在他家读历史著作,在他的引导下从《左传》开始,一篇一篇给我解释,每个月他家四个人,一人二两肉的份额,炒完以后只是我俩来分享,所以我非常歉疚。他说王强你要学好知识,肉体先要活着,他说我觉得你是可培养的,他展示了一流思想和一流文字真正的胶合。他上课非常有特点,从来不备课,这样一个顶级的老师,在我们学校从来没评过优秀老师,所以优秀是靠你真正生命才能支撑的。而且这个老师从来不服学校的规矩,从来不备课,他觉得跟其他老师没法备课。我记得每天早上九点都是历史课,大冬天穿着棉袄,历史书插在裤腰上,带着历史的温暖就进来了,而且第一个动作就是背向我们,掏历史,那是他的故事,他对知识如此娴熟,书没有打开一页,因为历史都在他的心里。而且他讲任何一个孤零零的事件都要放到更大的范围,讲完五四运动,他一定看看亚洲在干什么,欧洲在干什么,全世界在干什么,我们通过上中国史已经连通了世界,从此我才知道原来读懂中国史必须放在世界历史的框架中才可能。这样的老师简直让我叹为观止,就是他一句话让我升起了北大梦。他说我这个岁数这辈子实现一个梦想没戏了,什么梦想呢?他说我是学历史出身的,但是我对历史上的宏观描述,社会主义、共产主义的发展描述我有疑问,什么是社会主义,什么是共产主义呢?当时国内翻译说,社会主义是各尽所能,按劳分配的社会,这里各尽所能,但是按照你能够多做多得,能够给你分配你应该得的东西,这是社会主义分配原则。共产主义当时分析说,各尽所能,按需分配,他说同学们,作为我一个学历史的人,我的历史意识告诉我这个翻译不精准,如果共产主义和社会主义,一个按劳分配,一个按需分配,都存在”分配”的话,这两个社会没有区别,按照我的理解,那个时候人类精神极为发达,那个世界应该是各尽所能各取所需的时代,你自己决定你贡献什么,你拿回什么,这才是他向往的共产主义,和社会主义你需要我给你,不需要我不给你,这个没有什么本质区别他。他们说你们将来如果报答我作为你们的师恩,你们如果想学外语的话,读读马克思的原典,告诉我这个是不是对。八十年代的时候,所有发达国家,最后管理这个国家的都是学文的,学文的人可以看到全部,甚至看到没有存在的东西。所以你们学文的人应该比学理的更加聪明。后来我带着这个准备报考北大中文系,因为当时我的作文非常好,他说王强你千万别报北大中文系,你的中文已经完全达到了自学成才的程度,你将来要毙掉所有北大中文系的学生,你只需要一个东西,比他们多学一种语言,就这句话让我改了志愿,变成了英文系,因为老师告诉我,你看世界要多一种语言,你的世界就会宽广一下。

就是这样,我最后终于改换了志愿,到了北大英文系。我到校第一件事就是搞清楚,马克思论断是不是我的老师想像的,正好朱光潜先生翻完经济学手稿我一看与我老师的论断一字不差,社会主义分配原则是各尽所能按劳分配,共产主义一定会达到人类精神高度发达和自由,然后各尽所能,各取所需,我告诉我老师消息的时候,他说你真是我的学生。就是这样一个老师,他让我知道,历史你要读懂要站在什么高度。

再讲一个例子,教数学的老师,南开大学数学系毕业,我当时非常讨厌数学,我喜欢文,我们班一大半学生学不懂数学,但是只有这个老师的课上没有人上厕所,为什么?他对数学知识的了如指掌,比如他讲几何,他只带三只粉笔,从来不带教具,他要画个圆,先点圆心,往后一站,再往上一扑,动作一点都不停,你下课以后发现这个圆在哪衔接的不知道。他说画40几度角,他画完以后,很多学生下来拿两角尺去量非常准。所以后来上他这个班的学生,连不喜欢数学都要盯着他,因为觉得这是艺术课,结果这个班最后90%多的人都进了理科大学。当时令我难忘的是,八十年代,那时候我记得是考大学前一年,出来一个陈景润,数学家,非常伟大,突然光明日报第一版发了《哥德巴赫猜想》,当天下午我平生第一次知道有讲座的形式,说让大家带着板凳到操场上听讲座,讲《哥德巴赫猜想》,前面部分讲什么是哥德巴赫猜想,第二部由讲汉语的老师讲这个报告文学为什么是优秀的报告文学。结果我们坐着小板凳,太阳底下,第一次听什么叫偶数等等,听完以后没听明白,但是觉得陈景润很伟大,后来我的数学尽管是考文科的,那年我还考了59分。我们那年,80年和你进清华是同样一个卷子,77分就可以被清华大学数学系录取,我们59分,我们这是参考分,但是俞敏洪参考分0分,太悲惨了,一点没参考价值。

就是那个东西把我引到数论,所以在中学时我就读华罗庚、王袁的这些论著,懵懵懂懂,试图要读点爱因斯坦的著作,而且读了徐池报告文学我知道优秀报告文学是这样产生的,以后我也写了无数的小的报告文学,结果没有一处发表,所以到了北大之后我一直想写诗,我的诗集叫《野性的14行》,俞敏洪最后也写诗,他是北大最后一个没有自焚的未遂诗人。我们当年带着这个,知道了各个领域,要想走进这个领域,必须站在最高的地方,当时至少最优秀的地方我才能一览众山小。

到了北大更不得了,因为我们见到的那些人,都是大家见不到的那些大师级的人物。比如我是英语系的,英语系所有泰斗都是直接教过我们的,像李副宁(音)先生,不论刮风下雨,李先生的裤脚总是捻上来,一尘不染,他总是提前五分钟走进教室,也是把新概念往上一放就侃侃而谈,上第一个星期我们忽然觉得,每次上完课李先生这四块黑板没有擦过一个字,但是他写满了,在往下一周忽然发现,每当李先生写到这的时候,我们能推算出什么时候下课铃响起来,这真是大师,所以我说我将来当老师一定要当李先生这样的老师,他是中国英语教学的泰斗,像当年朱光潜老师,操着一口安徽桐城话讲什么是美学,尽管我们听不懂,他的桐城话非常难懂,但是就是在这样的情况下,我们看着朱先生最后完成了他的一步一步伟大译作,在他生命走到90多岁的时候,还每天馋着拐棍颤颤巍巍的到北大图书馆完成他的最后一部译作《新科学》。

这些老师给我们震撼如此之大,所以我们一下子扑到了北大的读书氛围中。他们给我们开了全部的书单,都是人类历史上经典的东西,因为他们说过,如果你没窥探过人类过去的最高的封边的时候,你就不知道你现在站到的地方究竟离海平面多高。所以当时所有教授都跟我们说,要读那些真正经过时间考验而不被淘汰的东西。所以在北大我的读书激情一下子被点燃起来,当然俞敏洪也被我的激情点燃起来了,但是俞敏洪呢,他当时基础稍微弱一点,有一次他得了肺结核,他住在西边享受那个传染病院,我去看他,他说王班长,我是他的班长,他是我帮助的同学,我们班四年始终保持倒数第一的同学,底子非常厚,这种人一站起来非常稳的,你想连续四年保持不变,倒数第一,太难。他说王班长,你从北大寄给一本莎士比亚的14行诗怎么样?我记得我回去以后给他写了长长的信,大概50多页,最后结论说,老俞读书要从基本功抓起,你一年以后我再替你借莎士比亚14行,至今老俞没读过14行,但是他用人生写出了15行。所以这就是当年我们在北大读书的氛围,就是读这些经典,人类熟悉的,甚至很多人追求时髦不屑一读的东西,对我们的生命,对我们的审美,对我们对真理的理解和渴望,对我们对语言和世界的关系,以及型塑生命的力量有了直接的感觉,就是这样一步一步推着我们走到今天。无论我在北大当年教书的时候,还是到了美国,还是从美国回来,我的读书的这个激情,选择所谓一流书的概念一直伴随着我,所以我认为我人生最大捷径就是花了时间非常痛苦啃了一流的书。举个例子,当年我到了美国,我改行,我不学英美文学,因为我发现到了美国来错地方,不能在美国生存,我学了十年的英文,在美国一点用没有,我不能教美国人英文来生存,那是李阳要做的事。我知道在美国生存要有一个技能,就改成计算机,但是学计算机谈何容易,计算机在八十年代是第一代计算机时代,主机,主机两个特点,体积庞大,造价昂贵,一台上百万,当时直属教育部重点院校才拨一台,安放在北大的南北阁。那个时候特别羡慕计算机系的,因为只有计算机系当年在北大四年,他们有一方面特权是任何系没法超过的,就是洗澡,到洗澡堂,计算机系人优惠洗澡,为什么?他们要消毒。为什么消毒?因为计算机如此昂贵,发展初期人们搞不清楚计算机病毒是怎么出来的。这个也应该拍成电影,北大当年就两个澡堂,一男一女,我们当时分的非常清楚。老头老太太管的非常严,比你们现在门卫森严多了,不仅要有洗澡票,还要有学生证,两证具全才能进去,而且还要看哪个系。你说哪系的?中文系的,明天再来,今天比较紧张。那个人回去了,一看哪个系的?计算机系的,赶快进去,今天你们是专场。另外一个,刚打了篮球,老师我必须洗,晚上要跟女朋友约会。老师说拿出学生证,考古系的,捣什么乱,明天也不要来,他们只有校庆的时候才能来,这才代表北大的历史。所以当时我觉得世界上两个东西我没见过,一个是上帝,一个是计算机,我到了美国学了计算机,我崩溃了,但是我想到老师教我的读书,为什么崩溃?因为到了纽约州立大学,录取我很容易,我记得第一堂课让我崩溃,第一堂课上微积分,十年我没摸过数学,上来我就危机了,就分裂了,而且讲课的是印度籍的老师,我想当时在北大练听力怎么没练过这个东西呢?所以同学们,学习不一定标准就是最实用的,我崩溃了。而且这个老师头上缠了发黑的白布,我听的越来越崩溃,我多少次想冲上去问他,你也是人,我也是人,咱们俩怎么这么难沟通。后来我想到,什么叫君子,该动手的时候不动手,该出手的时候不出手。

我想,我作为北大六年老师,我也没白练啊,我赶快到书店拿下计算机两本一流的著作,学西语言,上面有几百种西语言,但是我找到薄薄的不到两百页的著作,我不断的在读,不断的读,又不像我北大读经典一样,这本书我最后读的基本上找不到页玛的时候,我忽然发现我对C语言找到奇特的理解,我知道它为什么诞生,它优越在哪,它比较其他的语言,比如纯粹的学术语言,比较机器的语言,它好在哪。后来我学C++语言的时候我又找到了发明C++语言写的东西,看似非常精简,因为在他来说都不是问题,仍然不到两百页的书,我苦读整整一年,最后忽然我对这之间的世界完全了如指掌,最后我是我们班被老师评价为优秀的学生,当你熟悉一种语言的思维方式的时候,你很难跳到其他世界,因为是完全不同的,他是解决C不能解决的问题,而我由于掌握全部一流的平台,我非常正确的走进了两条道路,而且走的非常正确,老师给我非常高的评价,这就导致了我后来在纽约州立大学,尽管第一学期几乎想要抹去自己,我常常说这哪能听懂,尤其是印度籍教授。我经常利用上厕所的时间跑到操场上想,上帝,你把我微积分了吧。但是这两本一流的著作,让我走进真正这两个语言思维的精髓,我后来一下在这两个中间,一旦跳跃,我就变成超越所有本科学生天天在市场上抓关于C++这个介绍、那个介绍,读十本书也没有摸到真正C++核心的东西,所以我的读书基因在美国又一次拯救了我,使我经过两年半的艰难困苦的努力获得了纽约州立大学数学系机系的科学硕士学位,是我们班第一个走进美国一家伟大的软件公司,叫做贝尔传讯公司,我完成了我的转折,后来才有了95年一天深夜,老俞一番鬼魅的电话打到了我家,我做了人生的选择,才有了三个合伙人的雏形。

这就是我跟大家分享的,读书要读一流的书,做人要做一流的人。谢谢大家。

提问

​ 主持人:感谢王强老师分享的读书经历,下面进入提问环节。

​ 提问:王强老师刚才说读书要读一流的书,做人要做一流的人,在您看来什么样的人才是一流的人?

​ 王强:第一,真诚。第二,有激情。第三,开放,对什么都容易吸收。第四,阳光,你如果自己自焚,你也让别人照亮。第五,要有梦想,而且为了梦想不断往前走。第六,在大是大非面前,一定要有原则,而原则高于一切,善的就是善的,恶的就是恶的,所以我们做新东方,我就是按照这样的东西走到今天,也面对老俞基本是这样,所以我在老俞面前随时就拍桌子,因为只要偏离任何原则的东西,所以新东方的人给我一个外号。

​ 徐小平:说王强老师叫做脆弱如钢,俞敏洪老师叫坚强如芦苇,我叫芦苇钢。王老师说的第一词叫真诚,有这样一个细节,俞敏洪拿着书说,你有一天会让我嫉妒的。当时我在加拿大学完英文硕士,做一个私人老师,非常不成功,回到新东方的时候老俞说了一句话,老俞说小平,你很快就让我嫉妒的,他把对朋友的一种赞美、认同表达出来。我们三个人在一起的时候真的是坦诚相见的,虽然我们从来没有在一起洗过澡,大家心里有什么东西说出来,所以新东方历史上所谓的争吵,恰恰使新东方成为伟大企业的真髓所在,有什么说出来。所以在合伙人里面,俞敏洪说过一句话,他说我们来美国之前,我们不是真吵,我们是不同观点、不同角度的交锋,是思想的汇集,所以你们今后做人要学会这种东西,就是真诚、沟通、交流。

​ 提问:我今天注意到俞敏洪发了一篇博客,特别澄清电影和新东方之间的差别,一再想撇清这中间的关系,我想听听您怎么说,您在单口相声当中总是把他当成一个捧哏,不断的调侃。

​ 王强:他现在也是这样,老俞看完这个电影说,这个主人公离我比较远吧,怎么没有雄起的时候,我说这个电影最大的意义就在这,连这样的人都能成功,别人更能成功。

​ 徐小平:这个电影,第一他没有参与,事实上是这样的,2011连的3月份,韩三平找我,要拍摄一般部关于中国梦的电影,然后我找俞老师,我说我来写,我在新东方一直负责新东方的宣传公关、企业形象、品牌建设、营销,当时老俞说千万不要写,后来我告诉韩三平我们不写了,他说不行,你不写我们就找别人写,你不写我们就把新东方写的很坏。事实上后来我用两个礼拜拿出那个剧本,但是既然俞敏洪不想写,就写了海归回国创业的故事,海归回国和两个朋友创办了英语学校,是一个爱情故事,后来陈导说新东方会不会告我们,我说这个片子如果出来不符合我们之间的价值观、我们的友谊观,我根本不跟你合作,一部电影算什么。一直到了11年的年底,他来找我,我是3月份写出来的,剧本出来以后,我把我的剧本寄给王老师和俞老师,我提供了最初在新东方的素材,我的剧本给你们看,我要经得起友谊的审查,而陈导的剧本要经得起市场的审查。等到最后电影出来以后,俞老师看完以后觉得我这么伟大的人物怎么写的这么窝囊。这就是电影的目的,如果你这样窝囊的人都能够做到这么成功,对当代青年是有意义的嘛。所以俞老师也就一如既往忍气吞声的接受了这个片子。

​ 提问:您刚才说一流的书,您给我们推荐一些一流的书。

​ 王强:一流的书很多的,但是确实很难,因为我也特别怕推荐这个书,如果读完以后跟你生命确实没有交际的话,确实浪费时间。比如对于西方文明史的理解,至少有几部著作大家一定要读,从文艺复兴时代就是博格哈特的《意大利文艺复兴史文化史》,但是荷兰大史学家写的《中世纪的秋天》,读完这两部作品你对中世纪文艺复兴的本质有非常好的了解。到了《历史的研究》,汉语翻了一卷的结本,这个是作者花了三十多年的时间,用五千多页的篇幅研究各个存在的文明形态,研究他们怎么繁荣消亡的,最后得出两个东西,所有文明符合两个东西,如何面对挑战和回应,所以读完这几个东西,从中世纪到文艺复兴,再到二十世纪人的历史,有了非常宏观的东西,按照他们所指引的方向再往近读。

​ 提问:我想问王强老师一个问题,我感觉王洋的角色是最温情的,最初他似乎是愤青,你在创业中是否也扮演这样的角色?

​ 王强:我在三人创业中更接近邓超的角色,前一部分挺像我的,小平这个角色也是相反,在新东方我称之为小平是最有远见人,新东方所有历史大发展第一启动者就是小平同志。但是小平的性格,我过于钢,我是直接和老俞yes or no,小平有一点像王洋那样的,你这拍两下,那拍两下。

​ 提问:在合伙创业过程中难免冲突的时候,每个人应该怎么做?

​ 徐小平:制度,议事规则。

​ 提问:是什么让你们最终要合伙的?是因为个人感情吗?

​ 徐小平:有一个学生转了我们三个人的照片,说他们三个人搞鸡搞了三十年。我想简单说,创业一开始,合伙人往往是互补,互相需要。如果能坚持到最后靠的是什么呢?共同的价值观。什么是价值观?什么东西最重要,当两个东西摆在一起,什么最重要,比如你爱上一个人,你妈妈说他不行,我们不喜欢,你为此让你爸爸妈妈难受,还是你追求你的真爱,这就是价值观。比如说新东方的价值观是什么,就是新东方这个品牌,我们对同学的吸引力,包含我们对学生的承诺,我们相信这个东西有价值,比起我多一个点、少一个点,一个点新东方能值五千美元,但是我们共同的把这个品牌做好做大,你的东西才用不完。所以新东方有非常杰出的人,他不认同这个品牌,他就离开了。但是我跟王强、俞敏洪,我们在最痛苦的时候都知道这个品牌是我们共同的价值观,新东方要把中国最优秀的人才,让他们看到另外一个世界,最终能够把中国这个世界变得和最美好的世界一样美好,我们完成这个历史使命。

​ 提问:我也是非常喜欢读书的,在看很多作品的时候本来就非常晦涩难懂,你刚才说你读很难懂的书的时候还反复读,我想问是什么样的心态让你读不懂还可以反复读。

​ 王强:书写出来的文字两种,有力量和没有力量。书有两种,一类是硬性的书,一类是软性的书,黑格尔、康德、尼采、柏拉图这些都是硬书,硬书你要想从中获得养分,唯有一个捷径,就是不断的读,因为你不可能靠一遍,畅销书一遍不用读完你就理解了,这些畅销书和那些真正书籍的区别。所以当你一遍一遍进入的时候……

time_zone 是怎么打爆你的MySQL的

time_zone 是怎么打爆你的MySQL的

基础知识

这篇关于time_zone 的总结写得非常好Time_zone ,建议先读完做个基础知识的打底

Mysql日期和时间存储数据类型

存储类型 存储值示例 解释 适用场景
Datetime YYYY-MM-DD HH:MM:SS 时间日期类型。DB时区切换它的值不时区相关常见名词解释变, 但时区切换后代表的时间信息已改变. 使用简单、直观、方便。适用于无需考虑时区的业务场景,例如国内业务
Timestamp 名词1547077063000 解释以UTC时间戳来保存, DB时区切换它代表的时间信息值不会变,但是会随着连接会话的时区变化而变化。 内部以4个字节储存, 最大值可表示到2037年. 适用于客户端需要支持多时区自适应的场景,因精度有限,不推荐使用
Date GMTYYYY-MM-DD 全称Greenwich Mean Time 格林威治(也称:格林尼治)时间,也叫世界时(Universal Time),也叫世界标准时间。是指位于英国伦敦郊区的【皇家格林尼治天文台】的标准时间,是本初子午线上的地方时,是0时区的区时。GMT格林威治时间可认为是以前的标准时间日期类型,不包含时间信息 不关注时区只需要显示日期的场景
Varchar UTCYYYY-MM-DD HH:MM:SS 全称Coodinated Universal Time 协调世界时,又称世界统一时间、世界标准时间、国际协调时间。它是以原子时(物质的原子内部发射的电磁振荡频率为基准的时间计量系统)作为计量单位的时间,计算结果极其严谨和精密。它比GMT时间更来得精准,误差值必须保持在0.9秒以内,倘若大于0.9秒就会通过闰秒来”解决”。UTC时间是现在使用的世界时间标准字符串类型,可以用时间字符串来表示日期时间类型,格式可自定义,如果用ISO标准时间格式存储,则可以包含时区信息:yyyy-MM-dd’T’HH:mm:ss.SSS+HH:MM 自定义存储日期时间格式,可包含时区信息,适用于只需要显示时间的场景,不方便计算
Bigint DST1547077063000 Daylight Saving Time的简称,又称“日光节约时制”和“夏令时间”,也叫夏时制。表示为了节约能源,人为规定时间的意思。在这一制度实行期间所采用的统一时间称为“夏令时间”,在欧洲和北美用得比较多数字类型,可以存储时间戳,表示某个时刻,稳定性最好 存储某个时刻,可以表达时间的确定性,存储/网络传输稳定性最好

时区相关常见名词解释

名词 解释
GMT 全称Greenwich Mean Time 格林威治(也称:格林尼治)时间,也叫世界时(Universal Time),也叫世界标准时间。是指位于英国伦敦郊区的【皇家格林尼治天文台】的标准时间,是本初子午线上的地方时,是0时区的区时。GMT格林威治时间可认为是以前的标准时间
UTC 全称Coodinated Universal Time 协调世界时,又称世界统一时间、世界标准时间、国际协调时间。它是以原子时(物质的原子内部发射的电磁振荡频率为基准的时间计量系统)作为计量单位的时间,计算结果极其严谨和精密。它比GMT时间更来得精准,误差值必须保持在0.9秒以内,倘若大于0.9秒就会通过闰秒来”解决”。UTC时间是现在使用的世界时间标准
DST Daylight Saving Time的简称,又称“日光节约时制”和“夏令时间”,也叫夏时制。表示为了节约能源,人为规定时间的意思。在这一制度实行期间所采用的统一时间称为“夏令时间”,在欧洲和北美用得比较多
PDT 全称Pacific Daylight Time太平洋夏季时间,也称夏令时。每年的3月份第二个星期日凌晨2点开始至11月份第一个星期日凌晨2点结束,第一天23个小时。「北美的西海岸太平洋沿岸地区,大城市有:温哥华,西雅图,旧金山,洛杉矶,拉斯×××,圣迭戈,萨克拉门托,波特兰等」
PST 全称Pacific Standard Time太平洋标准时间,也称冬令时。从11月份第一个星期日凌晨2点开始至次年3月份第二个星期日凌晨2点结束,第一天25个小时。
CST CST可视为中国、古巴的标准时间或美国、澳大利亚的中部时间CST可以表示如下4个不同的时区的缩写:中国标准时间:China Standard Time UT+8:00古巴标准时间:Cuba Standard Time UT-4:00美国中部时间:Central Standard Time (USA) UT-6:00澳大利亚中部时间:Central Standard Time (Australia) UT+9:30因此具体含义需要根据上下文环境确定具体含义。在中国就表示东八区”北京时间”
UTC+08:00 基于UTC标准时间的时区偏移量,可表示东八区。UTC±[hh]:[mm]形式表示某个时区的区时,由UTC和偏移量组成。UTC+08:00就表示东八区时区的本地时间 = 世界协调时间UTC + 时区偏移量(+8h)
ISO 在时间日期上它全称是ISO 8601,是一种日期/时间表示方法的规范。规定了一种明确的、国际上都能理解的日历和时钟格式。在Java语言中常见格式:●ISO.DATE:yyyy-MM-dd, e.g. “2023-02-03”●ISO.TIME:HH:mm:ss.SSSXXX, e.g. “10:30:00.000-11:00”●ISO.DATE_TIME:yyyy-MM-dd’T’HH:mm:ss.SSSXXX, e.g. “2022-10-31T01:30:00.000-05:00”.
时间戳 时间戳一般指的UNIX时间,或类UNIX系统(比如Linux、macOS等)使用的时间表示方式。定义为:从UTC时间的1970-1-1 0:0:0起到现在的总秒数(秒是毫秒、微妙、纳秒的总称),可简单理解为某个时刻

问题

一般MySQL Server 实例都会设置 time_zone 为 system,方便实例部署在不同的国家、时区也都能很好兼容,这是很合理的设置。

如果我们的 SQL 中有一个列类型是 timestamp 的话,意味着:

timestamp 数据类型会存储当时 session的时区信息,读取时会根据当前 session 的时区进行转换;而 datetime 数据类型插入的是什么值,再读取就是什么值,不受时区影响。也可以理解为已经存储的数据是不会变的,只是 timestamp 类型数据在读取时会根据时区转换

如果MySQL 读取 timestamp 字段时,需要做时区转换,当 time_zone 设置为 system 时,意味着MySQL 要去follow OS系统时区,也就是把读到的timestamp 根据OS系统时区进行转换,这个转换调用OS 的glibc 的时区函数来获取 Linux OS 的时区,在这个函数中会加 mutex 锁,当并发高时,会出现 mutex 竞争激烈,每次只有一个线程获得锁,释放锁时会唤醒所有等锁线程,但最终只有一个能获取,于是一下子导致系统 sys飙高、上下文切换飙高。每读取一行带 timestamp 字段时,都会通过这个 glibc 的时区函数导致锁竞争特别激烈最终 QPS 拉胯厉害。

想一想,你一个SQL查1万行,10个并发这点流量其实一点都不过分,但是这里需要10*1万次转换,锁争抢就激烈了。

分析参考这个: https://opensource.actionsky.com/20191112-mysql/

perf 以及火焰图如下:

image-20230830101924021

img

timezone

解决

在中国可以将 time_zone=’+8:00’ 将 time_zone 固定死,不再需要follow OS 时区,所以也不需要调用glibc 获取系统时区,避免了前面所说的锁竞争

这个经验来自无数次线上故障复盘,因为 time_zone 设置为 system 是个默认行为,所以要全部改过来还真不容易,给了我们就业机会 :)

当然学习总是希望交叉起来,既有深度又有宽度你才能掌握更好,所以请趁热打铁:

进一步学习

东八区CST 被JDBC 驱动错误识别成了美国的中央时间,官方修复

实验

在我们 99块钱的 ECS 启动一个MySQL 的Docker 容器(配置简单,换MySQL版本对比也方便)

1
docker run --name mysql --network host -v /plantegg/test/my.cnf:/etc/my.cnf   -e MYSQL_ROOT_PASSWORD=123 -d mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

my.cnf配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# cat /plantegg/test/my.cnf
[mysqld]
#skip_grant_tables=1

#innodb
innodb_flush_log_at_trx_commit=0
innodb_buffer_pool_instances=8
innodb_max_dirty_pages_pct=60
innodb_io_capacity=6000
innodb_open_files=615350
innodb_buffer_pool_size = 64G

#binlog
binlog_cache_size=32K
max_binlog_cache_size=2147483648
max_binlog_size=1000M
sync_binlog=0

#for manager
#lower_case_table_names=1
#sql_mode = 'NO_ENGINE_SUBSTITUTION'

slow_query_log=0
general_log=0
default_authentication_plugin=mysql_native_password

max_connections=2000
max_user_connections=2000
max_connect_errors=65536
max_allowed_packet=1073741824
connect_timeout=8
net_read_timeout=30
net_write_timeout=60
back_log=1024

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
#user=mysql

[client]
#socket=/var/run/mysqld/mysqld.sock

先创建一个Database ren,然后在里面再创建一个表t,如下:

1
2
3
4
5
6
CREATE DATABASE `ren` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ /*!80016 DEFAULT ENCRYPTION='N' */

Create Table: CREATE TABLE `t` (
`ts` timestamp NULL DEFAULT NULL,
`dt` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

插入一条数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
insert into t values('2021-12-02 16:45:39','2021-12-02 16:45:39');

//然后反复多次执行如下SQL,让数据条数不断翻倍,直到100万条左右
insert into t select * from t;

MySQL [ren]> select count(*) from t;
+----------+
| count(*) |
+----------+
| 1048576 |
+----------+
1 row in set (0.060 sec)

MySQL [ren]> show global variables like '%zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | UTC |
| time_zone | SYSTEM | —————— 注意这里默认是System,
+------------------+--------+
2 rows in set (0.002 sec)

现在我们基本得到了一个100万行的测试表,接下来就要实验验证,同时开30个并发来查 ts列(timestamp, 要做时区转换) VS 查 dt 列(不需要做时区转换),对比他们的效率:

1
2
3
4
for i in {1..30}; do  (time mysql -h127.0.0.1 -P3306 -uroot -p123 ren -e " select ts from t " >>tmp ) & done

---上面30次 select每次基本需要20多秒,下面30次 select 每次基本需要4秒左右,性能差异有5倍
for i in {1..30}; do (time mysql -h127.0.0.1 -P3306 -uroot -p123 ren -e " select dt from t " >>tmp ) & done

可以清楚地看到 查ts 需要20秒左右,查 dt 需要4秒左右,差了5倍,结合我们前面的理论讲解,肯定可以想到这是在做时区转换有额外的开销,其实这还好只是开销大了几倍,有没有一种可能因为glibc 加锁导致整个系统雪崩了?大家可以试试能否搞出雪崩的场景来

Perf 安装和使用命令:

1
2
yum install perf -y
perf top -p mysqld-pid

比如用 perf top 可以看到查 timestamp 才有如下图前两行的 futex_wait_setup/libc-2.28 的wcscoll_l , 对比一下查 datetime 是完全看不到这些内核、libc的消耗的:

64 核机器 CPU 使用率(CPU 核数越多反而性能越差)

image-20241012175910202

image-20241012175910202

如果只给 MySQLD 4 核反而跑得更快了,明显在锁上的 CPU 消耗降低了很多:

image-20241012175910202

image-20241012175910202

停下来花点时间来分析他们的性能差异,多结合理论表述这篇,另外反过来想想如果你不知道这个原因,但是你看到这个现象(timestamp 和 datetime 性能差5倍的时候),你怎么来分析是为什么?

96核环境下对比

找个核数多的机器做同样的测试,比如以下数据是在96核机器上完成,让锁竞争更激烈,实际是把问题更加明显化

image-20240308084631703

从 top 也可以看到CPU 都花在了sys(内核态系统调用)上,这明显是不符合逻辑的。同时也可以看到96个核基本都跑满,整个MySQLD 进程的CPU 消耗接近 9600%,又回到了我们常说的CPU 有使用没有效率,不过站在CPU的角度是有效率的,这个效率都是在做锁相关的事情,但是站在业务角度是没有效率的:

image-20240308084600599

在这么明显的不正常情况下可以进一步通过 perf record 来采集调用关系,通过调用关系来回溯是哪个函数导致的锁争抢从而找到问题

从这里也可以看到这个问题在不同核数下表现完全不一样,如果只是一个核很少的实例那么看起来问题还没那么明显,只是慢了,但是到了96核下这个SQL 反而全崩了,这个SQL 完全查不出结果(CPU 都在sy 上干抢锁的内耗上,能查出才怪),核数越多这个问题就越严重,也即内耗越严重,如果有业务流量源源不断地进来就类似雪崩了:

1
2
3
4
5
6
7
8
9
# mysql -h127.0.0.1 -P3306 -uroot -p123 ren -e "show processlist"
+------+-----------------+-----------------+------+---------+---------+------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+------+-----------------+-----------------+------+---------+---------+------------------------+------------------+
| 1195 | root | localhost:46528 | ren | Query | 556 | executing | select ts from t |
| 1196 | root | localhost:46530 | ren | Query | 556 | Sending to client | select ts from t |
| 1197 | root | localhost:46532 | ren | Query | 556 | executing | select ts from t |
| 1198 | root | localhost:46538 | ren | Query | 556 | executing | select ts from t |
| 1199 | root | localhost:46540 | ren | Query | 556 | executing | select ts from t |

代码分析

从下图可以看到 70% 的 CPU 时间消耗在 Time_zone_system::gmt_sec_to_TIME() 方法的调用上,就是以下这一段的代码。

timezone

对应代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
void Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const {
struct tm tmp_tm;
time_t tmp_t = (time_t)t;
localtime_r(&tmp_t, &tmp_tm);
localtime_to_TIME(tmp, &tmp_tm);
tmp->time_type = MYSQL_TIMESTAMP_DATETIME;
adjust_leap_second(tmp);
}

//继续下钻来看一下 __tz_convert() 的实现,代码如下
/* Return the `struct tm' representation of *TIMER in the local timezone.
Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
struct tm *
__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
{
long int leap_correction;
int leap_extra_secs;
if (timer == NULL)
{
__set_errno (EINVAL);
return NULL;
}
__libc_lock_lock (tzset_lock);
/* Update internal database according to current TZ setting.
POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
This is a good idea since this allows at least a bit more parallelism. */
tzset_internal (tp == &_tmbuf && use_localtime, 1);
if (__use_tzfile)
__tzfile_compute (*timer, use_localtime, &leap_correction,
&leap_extra_secs, tp);
else
{
if (! __offtime (timer, 0, tp))
tp = NULL;
else
__tz_compute (*timer, tp, use_localtime);
leap_correction = 0L;
leap_extra_secs = 0;
}
if (tp)
{
if (! use_localtime)
{
tp->tm_isdst = 0;
tp->tm_zone = "GMT";
tp->tm_gmtoff = 0L;
}
if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
tp->tm_sec += leap_extra_secs;
else
tp = NULL;
}
__libc_lock_unlock (tzset_lock);
return tp;
}

代码最终会使用 atomic_compare_and_exchange_val_24_acq() 尝试对 futex 加锁。

futex 作为多个 thread 间共享的一块内存区域在多个 client thread(多个会话/查询)竞争的场景下会引发系统调用而进入系统态,导致 SYS 系统态 CPU 使用率上升。

并且该临界区保护的锁机制限制了时区转换方法 __tz_convert() 的并发度,进而出现多个会话/查询 等待获取锁进入临界区的情况,当冲突争抢激烈的场景下引发卡顿

进一步验证

这几个算是你可以接着做的一些小任务

  • 将 time_zone 从system 改成 ‘+08:00’ 再查 timestamp 列看看是不是就不存在这个问题了,反复改来改去稳定确认
  • 换MySQL 5.6/5.7试试这个问题,默认用的MySQL 8.0
  • 换低版本的OS 内核试试这个问题,我测试用的5.10,你可以试试3.10
  • 构造雪崩,也就是随着并发、行数的加大系统陷入抢锁等锁,基本无法响应业务查询了
  • 在这个基础上,各种折腾、折腾,会折腾就是能力

总结

借着 MySQL 的时区转换我们把这个问题重现了,让我们通过实际测试来验证这个差异,下次我相信你会对这个问题印象深刻的

当然我们做这个实验不是为了证明这个问题,这个知识点本身价值不是特别大,而是希望你能学到:

  1. 设计实验,根据你的目的设计实验
  2. 根据实验重现的现象反过去分析为什么——虽然你知道原因,但是如果不知道你会怎么思考
  3. 尝试分析问题的手段、技巧,比如 perf、比如for 循环

希望能看到你们更多的不同实验现象和分析

localhost和127.0.0.1的区别

localhost和127.0.0.1的区别

背景

有人告诉我localhost和127.0.0.1的区别是localhost 不经过网卡,所以性能也高。把我惊到了,因为我还真不知道这个知识点,于是去特别去验证了一下:这是个错误的理解。正确的解释是:localhost会解析成127.0.0.1 然后接下来的流程和127.0.0.1 一模一样

我用Google搜了下标题,果然得到如下图:

image-20230910100147730

红框里是排第一、第四的文章,都大言不惭地说localhost不经过网卡、不受防火墙限制等。

我也看了下第二、第三的文章,这两篇都是说在MySQL命令行中连 localhost 的时候,MySQL命令行会判断 localhost 这个字符串认为是本地连接然后不走DNS 解析流程(走的话就肯定解析成了127.0.0.1),从而绕过OS 的内核网络协议栈用MySQLD 启动的时候生成的 unix-socket 管道直接连上MySQLD,这样效率更高。

错误信息大概就是在MySQL这个特殊场景下演变而来的,英文搜索就没有这个错误污染信息

但这不是我要说的重点,我想说的是自己动手去求证!这一直都是我们星球里强调的能力和目标,我把这条发到Twitter上后有无数的初学者跑出来质疑或者一知半解不去验证就丢一个结论,这是我比较痛恨的。比如:

  • Localhost 写死了在 /etc/hosts(那我就要问,你清空/etc/hosts localhost还能工作吗?)

  • Localhost 不走网卡(但凡抓个包就知道走了,我估计他们抓了,抓的是eth0. 这里有个小小的歧义 loopback 本地回环网卡算不算网卡)

所以我特意再写篇文章再验证下各种质疑,并让大家看看是怎么验证的,我希望你们可以跟着验证一遍而不是只要知道个结论

结论

Localhost 会按dns解析流程进行解析,然后和127.0.0.1 一样。在特殊的程序中比如 MySQL client 会对localhost提前做特别处理。

完整的区别见这篇英文(Google 英文第一篇就是)总结:

image-20230910101843256

验证

问题1:经过网卡吗?

Ping localhost/127.0.0.1,然后 tcpdump -i any icmp or icmp6 [说明:any(抓所有网卡)icmp (精确点只抓ping包) ],可以明显抓到网络包,所以你可以理解为经过网卡。这指的是这个网络包完整地经过了内核协议栈,加tcp包头、ip包头、mac 包头等等。

而很多人理解的不经过网卡是指不走内核协议栈(毕竟是本机),加tcp包头、ip包头、mac 包头然后又脱mac包头、脱ip包头、tcp包头,有点像没必要的折腾。比如你通过unix socket 连就不走内核协议栈,性能要高一些

严格来说是没经过物理意义上的网卡,因为 lo 是一块虚拟网卡,不需要插网线,不会真的走到网卡、网线然后回来。如果让内核重新设计,让127.0.0.1 不过经过内核协议栈行不行?我觉得是完全可以的,当时为什么这么设计我也不懂。

总之,我强调经过网卡是从完整经过了内核协议栈、用 tcpdump 能抓到这个概念上来说的,为了跟别人说用127.0.0.1比用本机物理IP 性能要好而言(实际没有区别),你如果用本机物理IP 也同样走 lo 网卡

问题2:localhost和127.0.0.1 的关系

如图是我在centos、微软azure(应该是个ubuntu)、macOS下做的测试:

image-20230910103644707

问题3:如果/etc/hosts 中没有写死 localhost 127.0.0.1 会怎么样?

如下图,ping的时候即使没有 /etc/hosts 也可以把localhost 解析成127.0.0.1,为什么呢?所以接着我就 nslookup 看一下是哪个 DNS server做的这事,最后我用114.114.114.114 这个公网的DNS 做了解析,就不认识localhost了,说明去掉 /etc/hosts 之后 会把localhost 发给dns server解析,标准的dns(比如114.114.114.114,8.8.8.8) 都不会返回127.0.0.1 ,但是有些特定的实现为了省事帮你解析到127.0.0.1了

image-20230910104133832

问题4:127.0.0.1比localhost少了查/etc/hsots 到底快多少?

这个问题来自这个评论:https://twitter.com/InnerHack/status/1700012845302436087 所以我去验证了一下,特别强调这个数据意义不大,但是你们可以学会用strace,命令:

1
strace -tt ping -c 1 localhost

然后你得到如下图,从strace时间戳你可以看到 localhost 解析成127.0.0.1 的过程,再后面就是ping 127.0.0.1(这里也说明了前面的结论,两者是一样的,就是多了域名解析)

image-20230910104733229

域名解析的时候,先去找/etc/hosts 没找到再去找 /etc/resolv.conf 拿dns server ip然后把localhost发给这个dns server 解析,tcpdump抓包如下,红框是dns server返回的结果:

image-20230910105107629

问题5:127.0.0.1 和127.1 的关系

127.1 会自动补全成127.0.0.1

问题6:为什么还是抓不到包

ping localhost的时候没有包,只有127.1有,如下图:

image-20240505103504490

这是对提示信息敏感度不够,仔细看上图右下角的 ::1 这是个ipv6地址;也就是localhost被默认指向了这个 ipv6(localhost其实可以随便配置指向哪里,新一点的OS 默认都是指向 ipv6了),抓包命令多加一个 icmp6 (一个协议名字,默认不抓这个协议) 就能抓到了:tcpdump -i any icmp6

总结

唯有动手能解释一切,不要空逼逼(不是说你们,是说Twitter上那帮人,我是被他们留言多了逼着写了这篇)

我是欢迎一切有理有据的质疑,事实文中很多信息来源于别人的质疑,然后我去验证

然后好多验证手段你们可以学学,比如nslookup/tcpdump/strace 等。

我给的文章链接也可以仔细读读,能学到很多东西,每一次进步都来自你深挖、展开能力。

RFC6761 中对 localhost 有详细的说明,且已经定义的非常清楚:localhost 表示Loopback Address(127.0.0.1 或 ::1),另外应用程序可以对这个域做特殊识别处理,可以不走DNS解析流程。

如果你觉得看完对你很有帮助可以通过如下方式找到我

find me on twitter: @plantegg

知识星球:https://t.zsxq.com/0cSFEUh2J

开了一个星球,在里面讲解一些案例、知识、学习方法,肯定没法让大家称为顶尖程序员(我自己都不是),只是希望用我的方法、知识、经验、案例作为你的垫脚石,帮助你快速、早日成为一个更合格的程序员。

争取在星球内:

  • 养成基本动手能力,对各种技能试试,祛魅
  • 拥有起码的分析推理能力–按我接触的程序员,大多都是没有逻辑的
  • 知识上教会你几个关键的知识点
image-20240324161113874

解决Java/MySQL性能问题的思路

解决 Java/MySQL 性能问题的思路

10年前写的,重新发一下

系统性能问题

  • CPU(基本上WEB服务器没有多少IO,主要是CPU有瓶颈)
    • top/vmstat 观察CPU使用率,Load负载,r/b线程数量等;
    • IO(数据库大多数时候瓶颈是IO,主要是索引没建好;如果数据库CPU紧张的话,检查一下是不是order by/group by 等操作太多)
    • vmstat 观察IO/Util吞吐,磁盘最怕随机读写了(比如:索引命中后,需要离散地从磁盘读数据)
    • 对于数据库来说最怕内存不够的时候使用Swap了,所以尽量增大分配给数据库的内存,一旦有Swap就要引起注意了

Java程序问题(运行慢)

​ 先通过 top 查看整个CPU资源使用情况;
​ 通过top -Hp pid查看java进程的每一个线程占用CPU的情况;
​ 如果有一个线程占用CPU过高,有两种可能:
​ 没有内存了,Java垃圾回收线程不停地运行尝试回收内存,但是每次无法收回,确认:
​ jstat -gcutil pid 1s 观察10多秒钟就能发现了,看是不是内存使用率接近100%了
​ 类似于死循环(hash冲突攻击),就是一个线程一直占用一个核的所有CPU资源(其实一个线程总是占用一个核超过50%的资源都是不太正常的),解决:
​ 用我的checkPerf脚本,定位这个线程具体执行的任务(能具体到某一行),对应看代码解决。

    如果有很多线程,每个线程占用的CPU都不多(基本都在10%以下),那基本是正常的,只是程序并发确实很高。

如果死锁:
    jstack -l pid 多执行几次,统计一下stack中总是在等待哪些锁,可以对锁id进行排序统计(sort uniq grep)
上面列出来的都是明显的瓶颈,最可怕的是哪里都没有明显的瓶颈,哪里都要偷一点点CPU资源走,这是可以试试JProfiler这样更专业一点的工具,同时要配合自己对业务的了解来解决。

一旦触发频繁地抛出异常,CPU占用率会急剧地上升(抛异常比正常情况下会慢2个数量级)主要是由于:Throwable的构造函数中会调用native的fillInStackTrace(),这个方法就会构造整个异常栈了。

Java内存的问题,如果有内存泄露(就是执行完fgc/old gc后不能回收的内存不断地增加):
怎么确认没有内存了:
jps -lmv pid 先确认你的参数,也就是你给JVM分配了多大的堆(-Xmx 比如1G); 然后jstat -gcutil pid 1s 看看GC运行情况,如果(O/E 两列基本接近100%的话就是内存不够了)
内存不够分两种:一种是真的不够,就是你们的系统很庞大需要1G以上的内存,而你只分配了1G,这个没什么好说的,增大内存,物理内存不够就投钱买;
第二一种是你们的代码写的烂,有内存泄露,这样的话分配多少内存都不够,得找出是否有内存泄露,看接下的解决方案

快速解决:jmap -histo:live pid  来统计所有对象的个数(String/char/Integer/HashEntry 这样的对象很多很正常,主要是盯着你们公司的包名下的那些对象)
每隔一分钟执行一次上面的命令,执行5次以上,看看你们公司报名下的对象数量哪个在一直增加,那基本上就是这个对象引起了泄露;
用课堂上的工具HouseMD(java -Xbootclasspath/a:/usr/java/jdk1.6.0_29/lib/tools.jar -jar housemd-assembly-0.2.2.jar pid)来动态监控创建这个对象的地方(一般来说很多时候创建了这些对象把他们丢到一个HashMap然后就不管了),分析一下有没有释放!
    >trace -s -d ClassName

上面的方法实在没法定位就用: jmap -dump:live,format=b,file=heap.bin pid 导出整个内存(耗时间,需要很大的内存的机器才能对这个导出文件进行分析,会将JVM锁住一段时间)
    在Eclipse的插件EMA中打开这个文件(2G的物理文件需要4G以上的内存,5G以上的需要将近20G的内存来分析了)
    盯着你们公司报名的那些对象,看看引用关系,谁拿着这些对象没释放(是否是必要的),可以一直追查的RootReference

MySQL 数据库的性能问题

大部分情况下是磁盘IO的问题(索引没建好、查询太复杂);

  • 索引问题的话分析慢查询日志,explain 他们挨个解决。

  • 偶尔也有数据库CPU不够的情况,如果并发高CPU不够很正常,如果并发不高,那很可能就是group by/order by/random之类的操作严重消耗了数据库的CPU

    1
    2
    3
    mysql -e "show full processlist" | grep -v Sleep | sort -rnk6 查看那些SQL语句执行的太长
    拿出这个SQL语句分析他们的执行计划: explain SQL 然后改进;
    分析慢查询日志,统计top10性能杀手的语句,挨个explain他们,然后改进(具体改进办法具体分析,这里只谈思路)

总结一下数据库问题就只有这三招:show full processlist/分析慢查询日志/explain(然后建好联合索引)

补充一个数据库连接数不够的问题,很多人碰到了,不知道怎么解决:

  • 在mysql 命令行里执行:show variables like ‘%max_connections%’; 看看你们的数据实际配置是多少(比如1000)
  • show full processlist 数一下多少行,一行代表一个连接,比如这里是1000行,那基本上就是连接数不够了,你要解决的为什么你的数据库需要这么多连接
  • 接下来分析这些连接是从哪来的IP,然后问你自己:根据你们的服务类型的特点需要这么多连接吗?

数据库性能问题提问请给出:

  • show full processlist;
  • 查询语句;
  • 表结构(包括索引结构);
  • 数据库引擎类型;