案例学习-Sysbench压测故障

背景: 故障源于知识星球的一个案例: 我们的数据库需要做在线升级丝滑的验证,所以构造了一个测试环境,客户端Sysbench 用长连接一直打压力,同时Server 端的数据库做在线升级,这个在线升级会让 Server进程重启,所以毫无疑问连接会断开重连,所以期望升级的时候 Sysbench端 QPS 跌0几秒钟然后快速恢复。 但是每次升级都是 Sysbench端 QPS永久跌0,再也不能恢复,所以需要分析为什么,问题出在哪里?有人说是服务端的问题因为只有服务端做了变更 整个测试过程中 Sysbench 是配置的2个连接去压 Server 故障重现: https://articles.zsxq.com/id_zj5qazqa4odz.html 下面也保留一份。 1. 数据库 1 docker run -it -d --net=host -e MYSQL_ROOT_PASSWORD=123 --name=plantegg mysql 2. 安装依赖包 1 2 3 yum install -y java-1.8.0-openjdk.x86_64 java-1.8.0-openjdk-devel.x86_64 podman-docker.noarch wireshark sysbench mysql.x86_64 mysql -h127.1 -uroot -p123 3. 生成数据库 1 mysql -h127.1 -uroot -p123 -e "create database test" 4. 生成测试数据 1 sysbench --mysql-user='root' --mysql-password='123' --mysql-db='test' --mysql-host='127.0.0.1' --mysql-port='3306' --tables='16' --table-size='10000' --range-size='5' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --time='1180' --report-interval='1' --histogram='on' --threads=1 oltp_read_only prepare 5. 压测 1 sysbench --mysql-user='root' --mysql-password='123' --mysql-db='test' --mysql-host='127.0.0.1' --mysql-port='3306' --tables='16' --table-size='10000' --range-size='5' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --time='1180' --report-interval='1' --histogram='on' --threads=1 oltp_read_only run 6. kill,mysql进程,复现故障 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # mysql -h127.1 -uroot -p123 Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 14 Server version: 8.3.0 MySQL Community Server - GPL Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> show processlist; +----+-----------------+-----------------+------+---------+------+------------------------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-----------------+-----------------+------+---------+------+------------------------+------------------+ | 5 | event_scheduler | localhost | NULL | Daemon | 94 | Waiting on empty queue | NULL | | 13 | root | 127.0.0.1:33492 | test | Sleep | 0 | | NULL | | 14 | root | 127.0.0.1:51398 | NULL | Query | 0 | init | show processlist | +----+-----------------+-----------------+------+---------+------+------------------------+------------------+ MySQL [(none)]> kill 13; Query OK, 0 rows affected (0.000 sec) ...

2024-04-01 · 7 min · 1320 words · Garlic Space

LeetCode - First Duplicate Value

问题: 给定一个整数数组,编写一个函数,返回从左到右读取数组时出现多次的第一个整数。数组元素取值范围是整数1到n, 数组长度为n. 比较特殊情况 [2,3,4,2,3,5] 返回2 [2,3,4,4,2,5] 返回4, 虽然2也是重复数字但是再2之后。 解答: 遍历查找, 两次嵌套循环,同时标注最小索引。 1 2 3 4 5 6 7 8 9 10 11 def firstDuplicateValue(array): # Write your code here. max = len(array) value = -1 for i in range(len(array)): for j in range(len(array)): if (j > i and array[j] == array[i]): if (j < max): max = j value = array[i] return value 使用哈希表 ...

2024-03-18 · 1 min · 202 words · Garlic Space

MQTT

MQTT ( Message Queuing Telemetry Transport).它是一种轻量级的发布-订阅网络协议,用于在设备之间传输消息。 MQTT 专为硬件资源有限或网络带宽有限的远程位置连接而设计,非常适合 machine-to-machine (M2M) 通信和物联网 (IoT) 应用。 历史: Andy Stanford-Clark (IBM ) 和 Arlen Nipper(当时在Eurotech, Inc.工作)于 1999 年编写了该协议的第一个版本。 它用于监控SCADA工业控制系统内的石油管道。目标是建立一个带宽高效、重量轻且消耗很少电池电量的协议,因为这些设备是通过卫星链路连接的,而卫星链路在当时是极其昂贵的。 从历史上看,“MQTT”中的“MQ”来自IBM MQ(当时的“MQSeries”)产品线,代表“消息队列”,其实他并没有队列。 涉及几个版本: v3.1, 3.1.1 ,5.0。应用比较广泛的是3.1.1版本。MQTT-SN(传感器网络的 MQTT)是主要协议的变体,针对非 TCP/IP 网络上的电池供电嵌入式设备,例如Zigbee。 from wiki https://en.wikipedia.org/wiki/MQTT#cite_note-6 优势及缺点 1. 优势 效率和低带宽使用:MQTT消息小且需要最小的带宽,使得该协议成为具有有限处理能力的IoT设备和带宽受限网络环境的理想选择。 轻量级协议:其简单性和低代码占用使其易于在具有有限内存和处理能力的设备上实施,例如微控制器和小型传感器。 解耦通信:发布-订阅模型允许设备和服务器之间进行解耦通信。发布者和订阅者不需要彼此了解,提高了系统的可扩展性和灵活性。 服务质量等级:MQTT支持三个级别的服务质量(QoS)进行消息传递,使用户可以根据应用程序要求选择更快的传递但可靠性较低,或者传递速度较慢但保证传递。 保留消息:MQTT代理可以保留主题上的消息,确保新订阅者立即收到最后发布的消息,即使在他们订阅之前就已发送。 Last Will 和 Testament (LWT)功能:如果设备意外断开连接,允许设备发布消息到指定的主题,使得设备断开连接的监控和通知更加方便。 安全性:支持使用SSL/TLS进行消息加密的安全通信,除了应用层安全实践,如身份验证和授权。 2. 缺点 依赖代理:中心代理架构可能成为失败的单一点。如果代理关闭,整个消息系统将受到影响。 安全开销:虽然MQTT支持SSL/TLS,但实施这些安全措施可能会增加复杂性和开销,特别是在非常受限的设备上。 服务质量开销:更高的QoS级别(1和2)确保消息传递,但引入了额外的开销,这可能影响性能,特别是在受限网络上。 消息载荷:MQTT不强制执行任何载荷格式,这意味着消息的解释取决于发布者和订阅者之间的协议。这种灵活性很强大,但如果不仔细管理,也可能导致不一致。 代理性能和可扩展性:MQTT系统的性能和可扩展性可能严重依赖于代理的能力。大量的消息或大量的客户端需要一个健壮、配置良好的代理。 其中MQTT的payload格式是没有要求的, 可以是二进制, 名为字符串, json/xml或者自定义个格式, 对于业务的哦通讯协议要双方协定好。 使用场景 1. 物联网(IoT) MQTT 在 IoT 中得到广泛使用,用于将各种设备、传感器和执行器连接到互联网或其他网络。这使得可以远程监控和控制设备,如智能家电、环境传感器和工业机器。 智能家居:远程控制照明、供暖、安全系统和其他家用电器。 农业:监控土壤湿度和温度传感器,以优化灌溉系统。 2. 工业自动化 ...

2024-03-17 · 3 min · 560 words · Garlic Space

curl support TLCP using TASSL

TLCP 传输层密码协议TLCP 对应 TLS协议, 在GB/T 38636-2020规范中定义。支持国密sm2, sm3, sm4密钥套件。增加加密证书, 6.4.5.3章节中提到 选择ECC, ECDHE算法,密钥交换算法使用用加密证书公钥。 https://blog.csdn.net/shenshaojun/article/details/114576162 这里对密钥体系进行了说明, 目前没看到标准里介绍,加密证书CA生成,并拥有私钥。这样的涉及对于信息保密性要依赖CA机构? CURL curl工具目前还不支持TLCP,一般需要进行简单修改。 目前支持国密库: GMSSL Tongsuo 铜锁 江南天安TASSL TencentKonaSMSuite curl支持TLCP: GMSSL 开源版本 : https://github.com/pengtianabc/curl-gm Tongsuo : https://github.com/Tongsuo-Project/curl CURL compile using TASSL 具体实现:https://github.com/weida/Curl-with-TASSL-support-for-TLCP 需要注意新版本curl的参数使用二分查找,参数需要自己排序 1 2 3 4 "src/tool_getparam.c" /* this array MUST be alphasorted based on the 'lname' */ static const struct LongShort aliases[]= { ... 目前测试环境仅有linux版本,只提了个linux patch。 参考及引用: https://zhuanlan.zhihu.com/p/564452283 https://www.cnblogs.com/anding/p/17627553.html 图片from陳丁光

2024-02-16 · 1 min · 65 words · Garlic Space

http3 - nginx with quictls

nginx 从1.25开始支持QUIC和http3 1 2 3 4 5 6 7 # quictls 编译安装 ./Configure --prefix=$HOME/quictls --openssldir=$HOME/openssl-quic -fPIC no-shared make && make install # nginx 编译安装 auto/configure --with-debug --with-http_v3_module --with-http_v2_module --with-cc-opt="-I $HOME/quictls/include" --with-ld-opt="-L $HOME/quictls/lib64" --prefix=$HOME/nginx-quic --with-cc-opt="-DNGX_QUIC_DEBUG_PACKETS -DNGX_QUIC_DEBUG_CRYPTO" --with-openssl=$HOME/install/openssl make && make install nginx.conf 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 user root; worker_processes 1; error_log logs/error.log debug; #pid logs/nginx.pid; events { worker_connections 1024; } http { log_format quic '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" "$http3"'; access_log logs/access.log quic; server { # for better compatibility it's recommended # to use the same port for quic and https listen 443 quic reuseport; listen 443 ssl ; http3 on; http2 on; quic_retry on; ssl_early_data on; #server_name server_name; ssl_certificate certs/cert.pem; ssl_certificate_key certs/priv.key; ssl_protocols TLSv1.3; add_header Alt-Svc 'h3=":443"; ma=86400'; location / { index index.html index.htm; } } } ...

2024-02-16 · 2 min · 283 words · Garlic Space

Product of Array Except Self

问题: Given an array arr[] of n integers, construct a Product Array prod[] (of the same size) such that prod[i] is equal to the product of all the elements of arr[] except arr[i]. 解答: 遍历数组循环跳过当前元素,需要两层循环, 时间复杂度O(n^2),空间复杂度O(n) 1 2 3 4 5 6 7 8 9 def arrayOfProducts(array): products = [1 for _ in range(len(array))] for i in range(len(array)): runningProduct = 1 for j in range(len(array)): if i != j: runningProduct = runningProduct * array[j] products[i] = runningProduct return products ...

2024-01-08 · 2 min · 229 words · Garlic Space

io_uring echo-server

io_uring io_uring是Linux特有的异步I/O API。io_uring的名称来自用户空间和内核空间之间共享的环形缓冲区。在内核和用户空间之间进行通信使用环形缓冲区作为主要的通信模式。这种思想在业务系统中还是挺常见的: 比如用MQ、Kafka消息队列推送信息。一个接收队列, 一个发送队列,另外设计上也有Actor模型的影子, 应用和kernel, 分别是两个actor, 而actor的邮箱就是 SQ, CQ两个队列, 对于应用程序, 消息发送到SQ, 从CQ中获取结果,对于kernel是从SQ中获取信息, 将处理结果发送到CQ中。 传统echoserver 做一个简单echoserver。 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 #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define BUF_SIZE 512 int main(int argc, char const* argv[]) { int serverfd, clientfd; struct sockaddr_in server, client; int len; int port = 1234; char buffer[BUF_SIZE]; if (argc == 2) { port = atoi(argv[1]); } serverfd = socket(AF_INET, SOCK_STREAM, 0); if (serverfd < 0) { perror("create socket"); exit(1); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(port); len = sizeof(server); if (bind(serverfd, (struct sockaddr*)&server, len) < 0) { perror("bind socket"); exit(1); } if (listen(serverfd, 2048) < 0) { perror("listen socket"); exit(1); } while (1) { len = sizeof(client); if ((clientfd = accept(serverfd, (struct sockaddr*)&client, &len)) < 0) { perror("accept error"); exit(4); } memset(buffer, 0, sizeof(buffer)); int size = read(clientfd, buffer, sizeof(buffer)); if (size < 0) { perror("read error"); exit(5); } if (size == 0) { close(clientfd); continue; } if (write(clientfd, buffer, size) < 0) { perror("write error"); exit(6); } close(clientfd); } close(serverfd); return 0; } 使用python写一个客户端 ...

2024-01-07 · 11 min · 2176 words · Garlic Space

C struct检查成员是否存在

如何判断C struct中是否存在某一成员,最开始想法是通过offsetof宏定义 1 2 #define offsetof(st, m) \ ((size_t)&(((st *)0)->m)) C语言的offsetof()宏是ANSI C标准库中的一个特性,位于stddef.h头文件中。它用于计算给定结构体或联合体类型中某个成员的偏移量(以字节为单位), 但是这种方式仅能检查存在的成员, 不存在编译会有下面类似报错 1 XXX.c:11:35: error: ‘struct MyStruct’ has no member named ‘member3’; did you mean ‘member1’? 生成成员名的map C/C++ 不支持反射,与例如 Java 或 C# 不同。这意味着在 C/C++ 中,你不能在运行时"检测"未知结构(或类)的成员,你必须在编译时知道它 - 通常是通过 #include 包含定义结构的头文件。实际上,你不能访问未定义结构的内容 - 只能传递指针。 from https://cplusplus.com/forum/beginner/283156/ 同样作者给出了一个解决方案,那就是把对象放到map中, 对于C语言的,可以使用脚本处理一下。 大概思路根据脚本解析结构体,生成包含成员的数组,通过数组判断 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 # generate_struct_member_array.py import re def filter_content(content): # Remove comments content = re.sub(r'\/\*[\s\S]*?\*\/|\/\/.*', '', content) # Remove #define statements content = re.sub(r'#define\s+\w+\s+\w+', '', content) return content def parse_header(header_content): struct_pattern = re.compile(r'struct\s+(\w+)\s*{([^}]*)};', re.DOTALL) structs = struct_pattern.findall(header_content) struct_member_arrays = [] for struct_name, struct_body in structs: members = re.findall(r'\b\w+\s+(\w+)\s*(?:\[\w*\])?;', struct_body) struct_member_arrays.append((struct_name, members)) return struct_member_arrays def generate_array_code(struct_member_arrays): code = "" for struct_name, members in struct_member_arrays: code += f"const char *{struct_name}_member_names[] = {{\n" for member in members: code += f'\t"{member}",\n ' code = code.rstrip(', ') code += "};\n" return code def write_to_file(file_path, content): with open(file_path, 'w') as output_file: output_file.write(content) def read_and_generate(input_file_path, output_file_path): # Read the input header file content with open(input_file_path, 'r') as header_file: header_content = header_file.read() # Filter content (remove comments and #define statements) filtered_content = filter_content(header_content) # Parse the header file struct_member_arrays = parse_header(filtered_content) # Generate code for arrays array_code = generate_array_code(struct_member_arrays) # Write generated code to a new file write_to_file(output_file_path, array_code) print(f"Generated code has been written to {output_file_path}") # Specify the path to the input header file and the output header file input_header_file_path = 'hello.h' output_header_file_path = 'generated_define.h' # Read the input header file, generate code, and write to the output header file read_and_generate(input_header_file_path, output_header_file_path) hello.h ...

2024-01-01 · 5 min · 979 words · Garlic Space

SNI

SNI是TLS协议扩展, 在握手的开始标识其尝试连接的主机名, 当多个HTTPS服务部署在同一IP地址上,客户端就可以通过这个标识指定它将使用哪一个服务, 同时服务端也无需使用相同的证书,它在概念上相当于HTTP/1.1基于名称的虚拟主机。SNI扩展最早在2003年的RFC 3546中出现。 HTTP服务通过 Http header “Host”, 来选择指定服务, HTTPS服务就是通过这个SNI来区分。通过可以通过nginx来验证一下 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 #user nobody; worker_processes 1; #error_log logs/error.log; error_log logs/error.log debug; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { access_log logs/access.log ; server { listen 8443 ssl ; server_name test; ssl_certificate certs/cert.crt; ssl_certificate_key certs/cert.key; location / { return 200 "https-test\r\n"; } } server { listen 8443 ssl ; server_name garlic; ssl_certificate certs/cert2.crt; ssl_certificate_key certs/cert.key; location / { return 200 "https-garlic\r\n"; } } server { listen 8443 ssl ; server_name 10.10.10.10; ssl_certificate certs/cert3.crt; ssl_certificate_key certs/cert.key; location / { root html; index index.html index.htm; } } server { listen 9443 ssl ; server_name snitest; ssl_certificate certs/cert4.crt; ssl_certificate_key certs/cert.key; location / { root html; index index.html index.htm; } } server { listen 8080 ; server_name http-test; location / { return 200 "http-test\r\n"; } } server { listen 8080 ; server_name http-garlic; location / { return 200 "http-garlic\r\n"; } } } ...

2023-12-11 · 5 min · 858 words · Garlic Space

LeetCode-longest-peak

问题 Given an array arr[] with N elements, the task is to find out the longest sub-array which has the shape of a mountain. A mountain sub-array consists of elements that are initially in ascending order until a peak element is reached and beyond the peak element all other elements of the sub-array are in decreasing order. Input: arr = [1, 3, 1, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5] Output: 11 Explanation: There are two sub-arrays that can be considered as mountain sub-arrays. The first one is from index 0 – 2 (3 elements) and next one is from index 2 – 12 (11 elements). As 11 > 2, our answer is 11. ...

2023-11-26 · 2 min · 345 words · Garlic Space