-
Notifications
You must be signed in to change notification settings - Fork 235
[codex] Fix Redis long-run memory retention #331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| name: Redis Long Run | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| rounds: | ||
| description: "Number of Redis traffic rounds after warmup" | ||
| required: false | ||
| default: "8" | ||
| batch_size: | ||
| description: "Redis commands per round" | ||
| required: false | ||
| default: "2000" | ||
| growth_limit_mb: | ||
| description: "Allowed heap growth after warmup in MB" | ||
| required: false | ||
| default: "64" | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| redis-long-run: | ||
| runs-on: ubuntu-22.04 | ||
| timeout-minutes: 90 | ||
| steps: | ||
| - uses: actions/checkout@v4.2.2 | ||
| with: | ||
| submodules: recursive | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v5.3.0 | ||
| with: | ||
| go-version: '1.23.3' | ||
|
|
||
| - name: Build | ||
| run: | | ||
| /bin/bash init_env.sh | ||
| make clean && make build-bpf && make | ||
|
|
||
| - name: Provision LVH VM | ||
| uses: cilium/little-vm-helper@v0.0.28 | ||
| with: | ||
| test-name: redis-long-run | ||
| image-version: '5.15-20240912.022020' | ||
| cpu: 2 | ||
| mem: '4G' | ||
| host-mount: ./ | ||
| install-dependencies: 'true' | ||
| cmd: | | ||
| chmod +x /host/kyanos | ||
|
|
||
| - name: Install VM dependencies | ||
| uses: cilium/little-vm-helper@v0.0.28 | ||
| with: | ||
| provision: 'false' | ||
| cmd: | | ||
| apt-get update | ||
| apt-get install -y redis-tools python3 curl | ||
|
|
||
| - name: Run Redis long-run test | ||
| uses: cilium/little-vm-helper@v0.0.28 | ||
| env: | ||
| REDIS_LONG_RUN_ROUNDS: ${{ github.event.inputs.rounds || '8' }} | ||
| REDIS_LONG_RUN_BATCH_SIZE: ${{ github.event.inputs.batch_size || '2000' }} | ||
| REDIS_LONG_RUN_GROWTH_LIMIT_MB: ${{ github.event.inputs.growth_limit_mb || '64' }} | ||
| REDIS_LONG_RUN_OUTPUT_DIR: /host/testdata/output/redis-long-run | ||
| with: | ||
| provision: 'false' | ||
| cmd: | | ||
| set -euxo pipefail | ||
| mkdir -p /host/testdata/output/redis-long-run | ||
| bash /host/testdata/test_redis_long_run.sh 'sudo /host/kyanos' | ||
|
|
||
| - name: Upload long-run artifacts | ||
| if: always() | ||
| uses: actions/upload-artifact@v4.6.1 | ||
| with: | ||
| name: redis-long-run-artifacts | ||
| path: testdata/output/redis-long-run |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| package protocol | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func newTestRedisMessage(seq uint64, timestamp uint64, byteSize int, isReq bool) *RedisMessage { | ||
| return &RedisMessage{ | ||
| FrameBase: NewFrameBase(timestamp, byteSize, seq), | ||
| payload: fmt.Sprintf("payload-%d", seq), | ||
| command: "GET", | ||
| isReq: isReq, | ||
| } | ||
| } | ||
|
|
||
| func TestRedisMatchTrimsPendingRequestsWithoutResponses(t *testing.T) { | ||
| reqQueue := ParsedMessageQueue{} | ||
| for i := 0; i < maxPendingParsedMessages+128; i++ { | ||
| reqQueue = append(reqQueue, newTestRedisMessage(uint64(i+1), uint64(i+1), 64, true)) | ||
| } | ||
|
|
||
| parser := RedisStreamParser{} | ||
| reqStreams := map[StreamId]*ParsedMessageQueue{0: &reqQueue} | ||
|
|
||
| records := parser.Match(reqStreams, map[StreamId]*ParsedMessageQueue{}) | ||
|
|
||
| require.Empty(t, records) | ||
| require.Contains(t, reqStreams, StreamId(0)) | ||
| assert.Len(t, *reqStreams[0], maxPendingParsedMessages) | ||
| assert.Equal(t, uint64(129), (*reqStreams[0])[0].Seq()) | ||
| } | ||
|
|
||
| func TestRedisMatchTrimsPendingResponsesWithoutRequests(t *testing.T) { | ||
| respQueue := ParsedMessageQueue{} | ||
| for i := 0; i < maxPendingParsedMessages+64; i++ { | ||
| respQueue = append(respQueue, newTestRedisMessage(uint64(i+1), uint64(i+1), 64, false)) | ||
| } | ||
|
|
||
| parser := RedisStreamParser{} | ||
| respStreams := map[StreamId]*ParsedMessageQueue{0: &respQueue} | ||
|
|
||
| records := parser.Match(map[StreamId]*ParsedMessageQueue{}, respStreams) | ||
|
|
||
| require.Empty(t, records) | ||
| require.Contains(t, respStreams, StreamId(0)) | ||
| assert.Len(t, *respStreams[0], maxPendingParsedMessages) | ||
| assert.Equal(t, uint64(65), (*respStreams[0])[0].Seq()) | ||
| } | ||
|
|
||
| func TestRedisMatchRemovesEmptyQueuesAfterSuccessfulMatch(t *testing.T) { | ||
| reqQueue := ParsedMessageQueue{ | ||
| newTestRedisMessage(1, 100, 16, true), | ||
| } | ||
| respQueue := ParsedMessageQueue{ | ||
| newTestRedisMessage(2, 200, 16, false), | ||
| } | ||
|
|
||
| parser := RedisStreamParser{} | ||
| reqStreams := map[StreamId]*ParsedMessageQueue{0: &reqQueue} | ||
| respStreams := map[StreamId]*ParsedMessageQueue{0: &respQueue} | ||
|
|
||
| records := parser.Match(reqStreams, respStreams) | ||
|
|
||
| require.Len(t, records, 1) | ||
| assert.NotContains(t, reqStreams, StreamId(0)) | ||
| assert.NotContains(t, respStreams, StreamId(0)) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,6 +85,50 @@ VSCODE 直接打开项目即可,.vscode/launch.json 添加配置如下: | |
|
|
||
| 注意添加 `--debug-output` 参数。 | ||
|
|
||
| ## 性能分析(Profiling) | ||
|
|
||
| Kyanos 提供了 pprof 端点用于运行时性能分析和调试。你可以使用 `--pprof` 标志启用 pprof HTTP 服务器: | ||
|
|
||
| ```bash | ||
| ./kyanos watch --pprof | ||
| ``` | ||
|
|
||
| 默认情况下,pprof 服务器监听 `localhost:6060`。你可以使用 `--pprof-addr` 标志自定义监听地址: | ||
|
|
||
| ```bash | ||
| ./kyanos watch --pprof --pprof-addr="0.0.0.0:9090" | ||
|
||
| ``` | ||
|
|
||
| 可用的 pprof 端点: | ||
|
|
||
| | 端点 | 说明 | | ||
| |------|------| | ||
| | `/debug/pprof/` | 索引页面,显示所有可用的 profile | | ||
| | `/debug/pprof/heap` | 内存堆 profile | | ||
| | `/debug/pprof/profile` | CPU profile(默认 30 秒) | | ||
| | `/debug/pprof/goroutine` | Goroutine 堆栈信息 | | ||
| | `/debug/pprof/allocs` | 内存分配 profile | | ||
| | `/debug/pprof/block` | 阻塞 profile | | ||
| | `/debug/pprof/mutex` | 锁竞争 profile | | ||
|
Comment on lines
+104
to
+112
|
||
|
|
||
| 使用示例: | ||
|
|
||
| ```bash | ||
| # 采集 CPU profile | ||
| curl -o cpu.pprof http://localhost:6060/debug/pprof/profile?seconds=30 | ||
| go tool pprof cpu.pprof | ||
|
|
||
| # 查看堆内存 profile | ||
| go tool pprof http://localhost:6060/debug/pprof/heap | ||
|
|
||
| # 查看 goroutine 堆栈 | ||
| curl http://localhost:6060/debug/pprof/goroutine?debug=1 | ||
| ``` | ||
|
|
||
| > [!TIP] | ||
| > | ||
| > pprof 端点对于诊断 Kyanos 自身的性能问题、内存泄漏或 goroutine 泄漏非常有用。 | ||
|
|
||
| ## 源码结构 | ||
|
|
||
| ``` | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetPprofAddr()falls back to"localhost:6060", while the CLI flag default is127.0.0.1:6060and docs mentionlocalhost:6060. Usinglocalhostcan also resolve to IPv6-only on some systems. Consider using a single constant/default (preferably127.0.0.1:6060) across flags, docs, and this fallback to avoid surprising bind behavior.