perf: use picoev as default Server for improve response concurrency
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
# veb 优化分析 - v-hono 可借鉴的优化策略
|
||||
|
||||
## veb 核心优化策略
|
||||
|
||||
### 1. 使用 picoev 事件驱动模型
|
||||
veb 使用 `picoev` 作为底层事件循环,这是一个高性能的事件驱动 I/O 库。
|
||||
|
||||
```v
|
||||
// veb 使用 picoev 处理连接
|
||||
mut pico := picoev.new(
|
||||
port: params.port
|
||||
raw_cb: ev_callback[A, X]
|
||||
user_data: pico_context
|
||||
timeout_secs: params.timeout_in_seconds
|
||||
family: params.family
|
||||
host: params.host
|
||||
)!
|
||||
pico.serve()
|
||||
```
|
||||
|
||||
**v-hono 可借鉴:** 考虑使用 picoev 替代 `net.http.Server`,可以显著提升并发性能。
|
||||
|
||||
### 2. 预分配缓冲区
|
||||
veb 预先分配了读写缓冲区,避免每次请求都分配内存:
|
||||
|
||||
```v
|
||||
// 预分配缓冲区
|
||||
pico_context.buf = unsafe { malloc_noscan(picoev.max_fds * max_read + 1) }
|
||||
pico_context.incomplete_requests = []http.Request{len: picoev.max_fds}
|
||||
pico_context.file_responses = []FileResponse{len: picoev.max_fds}
|
||||
pico_context.string_responses = []StringResponse{len: picoev.max_fds}
|
||||
```
|
||||
|
||||
**v-hono 可借鉴:** 使用对象池或预分配缓冲区减少 GC 压力。
|
||||
|
||||
### 3. 编译时路由生成
|
||||
veb 使用 V 语言的编译时反射 `$for` 在编译时生成路由表:
|
||||
|
||||
```v
|
||||
fn generate_routes[A, X](app &A) !map[string]Route {
|
||||
mut routes := map[string]Route{}
|
||||
$for method in A.methods {
|
||||
$if method.return_type is Result {
|
||||
http_methods, route_path, host := parse_attrs(method.name, method.attrs)
|
||||
routes[method.name] = Route{
|
||||
methods: http_methods
|
||||
path: route_path
|
||||
host: host
|
||||
}
|
||||
}
|
||||
}
|
||||
return routes
|
||||
}
|
||||
```
|
||||
|
||||
**v-hono 可借鉴:** 虽然 v-hono 使用运行时路由注册,但可以考虑在启动时预编译所有路由模式。
|
||||
|
||||
### 4. 快速响应发送
|
||||
veb 使用 `strings.Builder` 构建响应,避免字符串拼接:
|
||||
|
||||
```v
|
||||
fn fast_send_resp_header(mut conn net.TcpConn, resp http.Response) ! {
|
||||
mut sb := strings.new_builder(resp.body.len + 200)
|
||||
sb.write_string('HTTP/')
|
||||
sb.write_string(resp.http_version)
|
||||
sb.write_string(' ')
|
||||
sb.write_decimal(resp.status_code)
|
||||
// ...
|
||||
send_string(mut conn, sb.str())!
|
||||
}
|
||||
```
|
||||
|
||||
**v-hono 可借鉴:** 使用 `strings.Builder` 替代字符串拼接构建 HTTP 响应。
|
||||
|
||||
### 5. 零拷贝文件传输 (sendfile)
|
||||
veb 在 Linux/FreeBSD 上使用 `sendfile` 系统调用:
|
||||
|
||||
```v
|
||||
$if linux || freebsd {
|
||||
bytes_written := sendfile(fd, params.file_responses[fd].file.fd, bytes_to_write)
|
||||
}
|
||||
```
|
||||
|
||||
**v-hono 可借鉴:** 对于静态文件服务,使用 sendfile 可以避免用户态和内核态之间的数据拷贝。
|
||||
|
||||
### 6. 智能连接管理
|
||||
veb 根据响应大小选择不同的发送策略:
|
||||
|
||||
```v
|
||||
// 小响应直接发送
|
||||
if completed_context.res.body.len < max_read {
|
||||
fast_send_resp(mut conn, completed_context.res) or {}
|
||||
} else {
|
||||
// 大响应使用流式传输
|
||||
params.string_responses[fd].open = true
|
||||
params.string_responses[fd].str = completed_context.res.body
|
||||
// 注册写事件
|
||||
pv.add(fd, picoev.picoev_write, ...)
|
||||
}
|
||||
```
|
||||
|
||||
**v-hono 可借鉴:** 根据响应大小采用不同的发送策略。
|
||||
|
||||
### 7. 路由匹配优化
|
||||
veb 的路由匹配策略:
|
||||
1. 先匹配精确路由(不含参数)
|
||||
2. 再匹配参数路由
|
||||
3. 使用简单的字符串分割和比较
|
||||
|
||||
```v
|
||||
// 精确匹配优先
|
||||
if !route.path.contains('/:') && url_words == route_words {
|
||||
// 直接调用处理器
|
||||
app.$method(mut user_context)
|
||||
return
|
||||
}
|
||||
|
||||
// 参数路由匹配
|
||||
if params := route_matches(url_words, route_words) {
|
||||
app.$method(mut user_context, method_args)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
**v-hono 可借鉴:** v-hono 已经实现了类似的静态/动态路由分离,但可以进一步优化参数提取。
|
||||
|
||||
### 8. 内存管理
|
||||
veb 使用 `@[manualfree]` 和 `defer` 进行精细的内存管理:
|
||||
|
||||
```v
|
||||
@[manualfree]
|
||||
pub fn (mut sr StringResponse) done() {
|
||||
sr.open = false
|
||||
sr.pos = 0
|
||||
sr.should_close_conn = false
|
||||
unsafe { sr.str.free() }
|
||||
}
|
||||
```
|
||||
|
||||
**v-hono 可借鉴:** 对于频繁分配的对象,考虑手动内存管理。
|
||||
|
||||
## v-hono 优化建议
|
||||
|
||||
### 高优先级
|
||||
1. **使用 picoev 替代 http.Server** - 这是最大的性能提升点
|
||||
2. **预分配缓冲区** - 减少每次请求的内存分配
|
||||
3. **使用 strings.Builder** - 优化响应构建
|
||||
|
||||
### 中优先级
|
||||
4. **实现真正的 Keep-Alive** - 需要 picoev 支持
|
||||
5. **优化 LRU 缓存** - 减少时间调用,使用更高效的数据结构
|
||||
6. **路由预编译** - 启动时预编译所有正则表达式
|
||||
|
||||
### 低优先级
|
||||
7. **sendfile 支持** - 静态文件零拷贝传输
|
||||
8. **响应大小分级处理** - 小响应直接发送,大响应流式传输
|
||||
9. **手动内存管理** - 对热点路径进行优化
|
||||
|
||||
## 性能对比总结
|
||||
|
||||
| 特性 | veb | v-hono | 差距原因 |
|
||||
|------|-----|--------|----------|
|
||||
| 事件模型 | picoev | http.Server | picoev 更高效 |
|
||||
| Keep-Alive | ✅ 支持 | ❌ 不支持 | http.Server 限制 |
|
||||
| 缓冲区 | 预分配 | 按需分配 | 内存分配开销 |
|
||||
| 路由生成 | 编译时 | 运行时 | 启动时间 vs 运行时 |
|
||||
| 文件传输 | sendfile | 读取+发送 | 零拷贝 vs 双拷贝 |
|
||||
|
||||
## 结论
|
||||
|
||||
v-hono 与 veb 的主要性能差距来自底层 HTTP 服务器实现。如果 v-hono 切换到 picoev,性能应该能接近甚至超过 veb。
|
||||
Reference in New Issue
Block a user