单元测试的必要性

很多人都在质疑单元测试的必要性,今天我们就来探讨下,单元测试对一个服务或者框架来说,到底有多重要
查看更多 →

APISIX 与 腾讯 Oteam 的故事

本文主要讲述了ApachaAPISIX解决程序中的什么问题,以及在腾讯内部是如何服务于各个业务项目为研发们肩负的。
查看更多 →

常见算法思想

查看更多 →

后台任务漫谈

查看更多 →

API认证授权

本文记录了常见的API认证(Authentication)和授权(Authorization)协议,包括 ACL, RBAC, ABAC,OAuth2.0
查看更多 →

Nginx在云上环境的性能最佳实践

Nginx在云上环境的性能最佳实践 目录 背景 Nginx的CPU相关设置 k8s的CPU策略 方案对比 结论 背景 最近有用户反馈 ApacheAPISIX 在云原生环境下存在几个问题: 无法获取容器准确核数 配置了多核的情况下吞吐量增长缓慢 这里先简单介绍项目相关的情况,APISIX 是一个基于 Openresty 的开源网关。而 Openresty 其实就是 Nginx + LuaJIT,那么我们要调查问题其实跟 Nginx 是脱不开关系的。 Nginx的CPU相关设置 首先看看第一个问题:无法获取容器准确核数,这个问题的起因是因为在 Nginx 配置中使用了 worker_processes auto; auto 意味 Nginx 会自动获取 CPU 核数,然后根据核数创建 worker。不幸的是,在容器当中它获取到的是 母机的核数 导致 Nginx 会在容器中创建数十个甚至上百个 worker,多个 worker 间的资源竞争和上下文切换都会降低它的性能。 为了核验 Nginx 是否真的获取的是母机核数,我翻了下 Nginx 相关的代码,截取核心片段如下: src/os/unix/ngx_posix_init.c #include <ngx_config.h>#include <ngx_core.h>#include <nginx.h> ngx_int_t ngx_ncpu; ngx_int_t ngx_max_sockets; ngx_uint_t ngx_inherited_nonblocking; ... #if (NGX_HAVE_SC_NPROCESSORS_ONLN) if (ngx_ncpu == 0) { ngx_ncpu = sysconf(_SC_NPROCESSORS_ONLN); 查看 sysconf 的文档发现底层调用的 get_nprocs_conf(3), 继续查看它的源码,核心片段如下:
查看更多 →

APISIX 插件

编写APISIX的插件的常见姿势以及简单介绍
查看更多 →

Prometheus笔记

Prometheus笔记 Prometheus metrics 名称必须满足: [a-zA-Z_:][a-zA-Z0-9_:]* label 名必须满足 [a-zA-Z0-9_]* Prometheus远程存储优化 Prometheus 以每两个小时为一个块,存储到磁盘中,内存保存近两个小时的内容,同时也会写 WAL(write-ahead-log),预写日志文件wal以128MB的段存储在目录中。这些文件包含尚未压缩的原始数据,因此它们比常规的块文件要大。Prometheus将至少保留3个预写日志文件,但是高流量服务器可能会看到三个以上的WAL文件,因为它需要保留至少两个小时的原始数据。 这些块会在后台被压缩成更大的块以节省磁盘,最大长度取决于 storage.tsdb.max-block-duration 参数的设置,默认为保留时间的 10%。 一般来说 storage.tsdb.max-block-duration = storage.tsdb.min-block-duration = 2h 就相当于禁用了压缩功能, 但是别让它们低于 2h,否则有以下的问题: 落盘过于频繁,这会很大程度影响 Promethues 的吞吐量。 由于 WAL 和落盘之前的内存都需要保留两个小时,所以这部分的内存是没办法释放的。 注意 storage.tsdb.max-block-duration 和 storage.tsdb.min-block-duration 指的都是落盘后的块大小,在内存中用于存储最近两小时数据的内存是不可控的,Prometheus 会在落盘后在后台再去压缩合并这些数据。 参考Remote write tuning rate vs irate 它们都用于计算一个时间区间内指标的每秒变化率,两者的决定性差别在于: rate 使用整个时间区间所有点计算出平均变化速率,它会削平峰值 irate 使用时间区间内最后的两个数据点作为变化速率 从它们两者的计算公式我们可以得到以下推论: 当选择的计算区间内仅仅包含两个数据点时,rate 和 irate 没有区别 我们使用 rate 来查看某个数据在较长一段时间内的变化趋势,它会消除一些细节防止影响趋势的展示 使用 irate 来查看某个数据在一段时间内的细小抖动和完整的变化。 使用 rate 时尽量选择较长的时间,而 irate 则反之(太长会丢失很多变化) relabel_config vs metric_relabel_configs relabel_config 发生在 metric_relabel_configs,通常用于挑选 target
查看更多 →

WASM小记

WASM小记 这几天工作需要,了解了一下WASM(WebAssembly),做个笔记备忘一下 背景 WASM 最初诞生的目标是为了解决在浏览器中执行效率的问题,由于JS是一个动态语言,因此对语言其进行优化时会出现一些意向不到的情况,比如上一秒是Object的变量,下一秒就变成了Array,这就导致编译器必须不停地去重新编译成字节码并优化。 为了解决了这个问题,最早出现的解决方案就是 asm.js,类似 WASM,它的目标是将 js 编译成一个相对静态的语言,但是本质还是 js,还是需要在浏览器中编译成字节码,可以参考如下例子: function asmJs() { 'use asm'; let myInt = 0 | 0; let myDouble = +1.1; } 为了彻底解决这个问题且获得更好的扩展性,2015年,WASM 诞生了:作为一个规范,它指导各种语言编译成特定格式的字节码,类似: 20 00 42 00 ..... 再借由 runtime 去执行它。这种模式让我想到了 java/.net,也都是先编译成中间语言(Intermediate Language),再到 CLR/JVM 上去执行,如果 .net/java 当年也能支持不同语言编译到IL,是不是就没WASM什么事了? 开个玩笑,.net 也好 java 也好,都是有历史包袱的,而且出发点也并不是为了适配多语言。WASM诞生的目的就是为了提供一个沙盒环境去运行不同的代码,因此在规范上考虑会周全很多。 简单介绍 说完了背景,我们来看看 WASM 的工作流程是怎样的。 简单来说,我们构建一个 WASM 模块只需要几个步骤: 通过特定工具,比如 AssemblyScript,emscripten,前者是将 TypeScripe 编译成 WASM 字节码,后者支持多种语言。 找一个运行时来运行 WASM 字节码,现在主流浏览器基本都已经内置了 WASM 的运行时,可以直接执行 WASM 文件 就是这么简单两步,我们就可以体验 WASM 的快乐了,更多的编译和运行工具参考:Benchmark of WebAssembly runtimes - 2021 Q1
查看更多 →

简单易懂的 pprof 手册

简单易懂的 pprof 手册 推荐阅读 实战Go内存泄露 High Performance Go Workshop 完整格式: go tool pprof <format> [options] [binary] <source> ... 省略 <format> 可以使用交互式的控制台,或者换成为 -http 可以启动一个 web 服务器查看性能分析图 go tool pprof -http [host]:[port] [options] [binary] <source> ... <source> 支持三种格式: profile.pb.gz: 压缩的 profile 文件,可以通过 -proto 格式输出 pprof的 http 接口 legacy_profile: 遗留格式,不推荐 pprof 的 http 服务的路径如 /debug/pprof/{res}, res 支持以下几种类型采样: allocs: 内存分配 blocks: 阻塞操作 cmdline: 显示程序启动命令 goroutine: 协程 heap: 堆内存信息 mutex: 锁争用信息 profile: cpu threadcreat: 系统线程 trace: 程序运行跟踪信息 我们通常可以有几种方式进行采样:
查看更多 →