Add profiling tools (#1087)

* Add gin-contrib/pprof dependency

* Run pprof server on agent with --profiler flag

* Add --profiler flag to cli

* Fix error message

* Print cpu usage percentage

* measure cpu of current pid instead of globaly on the system

* Add scripts to plot performance

* Plot packetsCount in analysis

* Concat to DataFrame

* Plot in turbo colorscheme

* Make COLORMAP const

* Fix rss units

* Reduce code repetition by adding function for plotting

* Allow grouping based on filenames

* Temporary: Marked with comments where to disable code for experiments

* Add newline at end of file

* Add tap.cpuprofile flag. Change memprofile flag to tap.memprofile

* create tapper modes for debugging using env vars

* Fix rss plot units (MB instead of bytes)

* Remove comment

* Add info to plot script

* Remove tap.cpumemprofile. Rename tap.memprofile to memprofile

* Remove unused import

* Remove whitespaces

Co-authored-by: M. Mert Yıldıran <mehmet@up9.com>

* Remove whitespaces

Co-authored-by: M. Mert Yıldıran <mehmet@up9.com>

* Remove whitespaces

Co-authored-by: M. Mert Yıldıran <mehmet@up9.com>

* Remove whitespaces

Co-authored-by: M. Mert Yıldıran <mehmet@up9.com>

* Remove whitespaces

Co-authored-by: M. Mert Yıldıran <mehmet@up9.com>

* Remove whitespaces

Co-authored-by: M. Mert Yıldıran <mehmet@up9.com>

* Rename debug env vars

* Create package for debug env vars, read each env var once

* Run go mod tidy

* Increment MatchedPairs before emitting

* Only count cores once

* Count virtual and physical cores

* Add dbgctl replace in cli

* Fix lint: Check return values

* Add tap/dbgctl to test-lint make rule

* Replace tap/dbgctl in all modules

* #run_acceptance_tests

* Copy dbgctl module to docker image

* Debug/profile tapper benchmark (#1093)

* add mizu debug env to avoid all extensions

* add readme + run_tapper_benchmark.sh

* temporary change branch name

* fix readme

* fix MIZU_BENCHMARK_CLIENTS_COUNT env

* change tap target to tcp stream

* track live tcp streams

* pr fixes

* rename tapperPacketsCount to ignored_packets_count

* change mizu tapper to mizu debugg

Co-authored-by: David Levanon <dvdlevanon@gmail.com>
Co-authored-by: M. Mert Yıldıran <mehmet@up9.com>
This commit is contained in:
Nimrod Gilboa Markevich 2022-05-18 15:42:13 +03:00 committed by GitHub
parent a9de4f0bba
commit ab38f4c011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 604 additions and 34 deletions

View File

@ -68,6 +68,7 @@ COPY shared/go.mod shared/go.mod ../shared/
COPY logger/go.mod logger/go.mod ../logger/
COPY tap/go.mod tap/go.mod ../tap/
COPY tap/api/go.mod ../tap/api/
COPY tap/dbgctl/go.mod ../tap/dbgctl/
COPY tap/extensions/amqp/go.mod ../tap/extensions/amqp/
COPY tap/extensions/http/go.mod ../tap/extensions/http/
COPY tap/extensions/kafka/go.mod ../tap/extensions/kafka/

View File

@ -83,6 +83,7 @@ test-lint: ## Run lint on all modules
cd cli && golangci-lint run
cd acceptanceTests && golangci-lint run
cd tap/api && golangci-lint run
cd tap/dbgctl && golangci-lint run
cd tap/extensions/ && for D in */; do cd $$D && golangci-lint run && cd ..; done
test-cli: ## Run cli tests

View File

@ -54,3 +54,5 @@ replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../tap/dbgctl

View File

@ -7,6 +7,7 @@ require (
github.com/chanced/openapi v0.0.8
github.com/djherbis/atime v1.1.0
github.com/getkin/kin-openapi v0.89.0
github.com/gin-contrib/pprof v1.3.0
github.com/gin-contrib/static v0.0.1
github.com/gin-gonic/gin v1.7.7
github.com/go-playground/locales v0.14.0
@ -24,6 +25,7 @@ require (
github.com/up9inc/mizu/shared v0.0.0
github.com/up9inc/mizu/tap v0.0.0
github.com/up9inc/mizu/tap/api v0.0.0
github.com/up9inc/mizu/tap/dbgctl v0.0.0
github.com/up9inc/mizu/tap/extensions/amqp v0.0.0
github.com/up9inc/mizu/tap/extensions/http v0.0.0
github.com/up9inc/mizu/tap/extensions/kafka v0.0.0
@ -60,6 +62,7 @@ require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
@ -101,15 +104,20 @@ require (
github.com/russross/blackfriday v1.6.0 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect
github.com/segmentio/kafka-go v0.4.27 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/spf13/cobra v1.3.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/struCoder/pidusage v0.2.1 // indirect
github.com/tidwall/gjson v1.14.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/sjson v1.2.4 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/ugorji/go/codec v1.2.6 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
github.com/xlab/treeprint v1.1.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
@ -151,3 +159,5 @@ replace github.com/up9inc/mizu/tap/extensions/http v0.0.0 => ../tap/extensions/h
replace github.com/up9inc/mizu/tap/extensions/kafka v0.0.0 => ../tap/extensions/kafka
replace github.com/up9inc/mizu/tap/extensions/redis v0.0.0 => ../tap/extensions/redis
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../tap/dbgctl

View File

@ -213,10 +213,13 @@ github.com/getkin/kin-openapi v0.89.0 h1:p4nagHchUKGn85z/f+pse4aSh50nIBOYjOhMIku
github.com/getkin/kin-openapi v0.89.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0=
github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Swm1U=
github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs=
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
@ -238,6 +241,8 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@ -618,6 +623,8 @@ github.com/segmentio/kafka-go v0.4.27 h1:sIhEozeL/TLN2mZ5dkG462vcGEWYKS+u31sXPjK
github.com/segmentio/kafka-go v0.4.27/go.mod h1:XzMcoMjSzDGHcIwpWUI7GB43iKZ2fTVmryPSGLf/MPg=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -659,6 +666,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/struCoder/pidusage v0.2.1 h1:dFiEgUDkubeIj0XA1NpQ6+8LQmKrLi7NiIQl86E6BoY=
github.com/struCoder/pidusage v0.2.1/go.mod h1:bewtP2KUA1TBUyza5+/PCpSQ6sc/H6jJbIKAzqW86BA=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.12.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@ -672,6 +681,10 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
@ -702,6 +715,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
@ -894,6 +909,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -962,6 +978,7 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc=
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@ -14,6 +14,7 @@ import (
"syscall"
"time"
"github.com/gin-contrib/pprof"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"github.com/up9inc/mizu/agent/pkg/dependency"
@ -36,6 +37,7 @@ import (
"github.com/up9inc/mizu/shared"
"github.com/up9inc/mizu/tap"
tapApi "github.com/up9inc/mizu/tap/api"
"github.com/up9inc/mizu/tap/dbgctl"
)
var tapperMode = flag.Bool("tap", false, "Run in tapper mode without API")
@ -45,6 +47,7 @@ var apiServerAddress = flag.String("api-server-address", "", "Address of mizu AP
var namespace = flag.String("namespace", "", "Resolve IPs if they belong to resources in this namespace (default is all)")
var harsReaderMode = flag.Bool("hars-read", false, "Run in hars-read mode")
var harsDir = flag.String("hars-dir", "", "Directory to read hars from")
var profiler = flag.Bool("profiler", false, "Run pprof server")
const (
socketConnectionRetries = 30
@ -61,7 +64,7 @@ func main() {
app.LoadExtensions()
if !*tapperMode && !*apiServerMode && !*standaloneMode && !*harsReaderMode {
panic("One of the flags --tap, --api or --standalone or --hars-read must be provided")
panic("One of the flags --tap, --api-server, --standalone or --hars-read must be provided")
}
if *standaloneMode {
@ -69,7 +72,14 @@ func main() {
} else if *tapperMode {
runInTapperMode()
} else if *apiServerMode {
utils.StartServer(runInApiServerMode(*namespace))
app := runInApiServerMode(*namespace)
if *profiler {
pprof.Register(app)
}
utils.StartServer(app)
} else if *harsReaderMode {
runInHarReaderMode()
}
@ -283,6 +293,10 @@ func pipeTapChannelToSocket(connection *websocket.Conn, messageDataChannel <-cha
continue
}
if dbgctl.MizuTapperDisableSending {
continue
}
// NOTE: This is where the `*tapApi.OutputChannelItem` leaves the code
// and goes into the intermediate WebSocket.
err = connection.WriteMessage(websocket.TextMessage, marshaledData)

View File

@ -11,6 +11,7 @@ import (
"github.com/up9inc/mizu/agent/pkg/api"
"github.com/up9inc/mizu/agent/pkg/utils"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/tap/dbgctl"
tapApi "github.com/up9inc/mizu/tap/api"
amqpExt "github.com/up9inc/mizu/tap/extensions/amqp"
httpExt "github.com/up9inc/mizu/tap/extensions/http"
@ -24,36 +25,38 @@ var (
)
func LoadExtensions() {
Extensions = make([]*tapApi.Extension, 4)
Extensions = make([]*tapApi.Extension, 0)
ExtensionsMap = make(map[string]*tapApi.Extension)
extensionAmqp := &tapApi.Extension{}
dissectorAmqp := amqpExt.NewDissector()
dissectorAmqp.Register(extensionAmqp)
extensionAmqp.Dissector = dissectorAmqp
Extensions[0] = extensionAmqp
ExtensionsMap[extensionAmqp.Protocol.Name] = extensionAmqp
extensionHttp := &tapApi.Extension{}
dissectorHttp := httpExt.NewDissector()
dissectorHttp.Register(extensionHttp)
extensionHttp.Dissector = dissectorHttp
Extensions[1] = extensionHttp
Extensions = append(Extensions, extensionHttp)
ExtensionsMap[extensionHttp.Protocol.Name] = extensionHttp
extensionKafka := &tapApi.Extension{}
dissectorKafka := kafkaExt.NewDissector()
dissectorKafka.Register(extensionKafka)
extensionKafka.Dissector = dissectorKafka
Extensions[2] = extensionKafka
ExtensionsMap[extensionKafka.Protocol.Name] = extensionKafka
if !dbgctl.MizuTapperDisableNonHttpExtensions {
extensionAmqp := &tapApi.Extension{}
dissectorAmqp := amqpExt.NewDissector()
dissectorAmqp.Register(extensionAmqp)
extensionAmqp.Dissector = dissectorAmqp
Extensions = append(Extensions, extensionAmqp)
ExtensionsMap[extensionAmqp.Protocol.Name] = extensionAmqp
extensionRedis := &tapApi.Extension{}
dissectorRedis := redisExt.NewDissector()
dissectorRedis.Register(extensionRedis)
extensionRedis.Dissector = dissectorRedis
Extensions[3] = extensionRedis
ExtensionsMap[extensionRedis.Protocol.Name] = extensionRedis
extensionKafka := &tapApi.Extension{}
dissectorKafka := kafkaExt.NewDissector()
dissectorKafka.Register(extensionKafka)
extensionKafka.Dissector = dissectorKafka
Extensions = append(Extensions, extensionKafka)
ExtensionsMap[extensionKafka.Protocol.Name] = extensionKafka
extensionRedis := &tapApi.Extension{}
dissectorRedis := redisExt.NewDissector()
dissectorRedis.Register(extensionRedis)
extensionRedis.Dissector = dissectorRedis
Extensions = append(Extensions, extensionRedis)
ExtensionsMap[extensionRedis.Protocol.Name] = extensionRedis
}
sort.Slice(Extensions, func(i, j int) bool {
return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority

View File

@ -123,4 +123,5 @@ func init() {
tapCmd.Flags().String(configStructs.ContractFile, defaultTapConfig.ContractFile, "OAS/Swagger file to validate to monitor the contracts")
tapCmd.Flags().Bool(configStructs.ServiceMeshName, defaultTapConfig.ServiceMesh, "Record decrypted traffic if the cluster is configured with a service mesh and with mtls")
tapCmd.Flags().Bool(configStructs.TlsName, defaultTapConfig.Tls, "Record tls traffic")
tapCmd.Flags().Bool(configStructs.ProfilerName, defaultTapConfig.Profiler, "Run pprof server")
}

View File

@ -124,7 +124,7 @@ func RunMizuTap() {
}
logger.Log.Infof("Waiting for Mizu Agent to start...")
if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, getSyncEntriesConfig(), config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel()); err != nil {
if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, getSyncEntriesConfig(), config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel(), config.Config.Tap.Profiler); err != nil {
var statusError *k8serrors.StatusError
if errors.As(err, &statusError) && (statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists) {
logger.Log.Info("Mizu is already running in this namespace, change the `mizu-resources-namespace` configuration or run `mizu clean` to remove the currently running Mizu instance")

View File

@ -30,6 +30,7 @@ const (
ContractFile = "contract"
ServiceMeshName = "service-mesh"
TlsName = "tls"
ProfilerName = "profiler"
)
type TapConfig struct {
@ -54,6 +55,7 @@ type TapConfig struct {
TapperResources shared.Resources `yaml:"tapper-resources"`
ServiceMesh bool `yaml:"service-mesh" default:"false"`
Tls bool `yaml:"tls" default:"false"`
Profiler bool `yaml:"profiler" default:"false"`
}
func (config *TapConfig) PodRegex() *regexp.Regexp {

View File

@ -74,6 +74,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday v1.6.0 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
github.com/xlab/treeprint v1.1.0 // indirect
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab // indirect
@ -104,3 +105,5 @@ replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../tap/dbgctl

View File

@ -14,7 +14,7 @@ import (
core "k8s.io/api/core/v1"
)
func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, syncEntriesConfig *shared.SyncEntriesConfig, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level) (bool, error) {
func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, syncEntriesConfig *shared.SyncEntriesConfig, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level, profiler bool) (bool, error) {
if !isNsRestrictedMode {
if err := createMizuNamespace(ctx, kubernetesProvider, mizuResourcesNamespace); err != nil {
return false, err
@ -50,6 +50,7 @@ func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.
Resources: apiServerResources,
ImagePullPolicy: imagePullPolicy,
LogLevel: logLevel,
Profiler: profiler,
}
if err := createMizuApiServerPod(ctx, kubernetesProvider, opts); err != nil {

View File

@ -0,0 +1,107 @@
# Performance analysis
This directory contains tools for analyzing tapper performance.
# Periodic tapper logs
In tapper logs there are some periodic lines that shows its internal state and consumed resources.
Internal state example (formatted and commented):
```
stats - {
"processedBytes":468940592, // how many bytes we read from pcap
"packetsCount":174883, // how many packets we read from pcap
"tcpPacketsCount":174883, // how many tcp packets we read from pcap
"reassembledTcpPayloadsCount":66893, // how many chunks sent to tcp stream
"matchedPairs":24821, // how many request response pairs found
"droppedTcpStreams":2 // how many tcp streams remained stale and dropped
}
```
Consumed resources example (formatted and commented):
```
mem: 24441240, // golang heap size
goroutines: 29, // how many goroutines
cpu: 91.208791, // how much cpu the tapper process consume (in percentage per core)
cores: 16, // how many cores there are on the machine
rss: 87052288 // how many bytes held by the tapper process
```
# Plot tapper logs
In order to plot a tapper log or many logs into a graph, use the `plot_from_tapper_logs.py` util.
It gets a list of tapper logs as a parameter, and output an image with a nice graph.
The log file names should be named in this format `XX_DESCRIPTION.log` when XX is the number between determining the color of the output graph and description is the name of the series. It allows for easy comparison between various modes.
Example run:
```
cd $MIZU_HOME/performance_analysis
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt
python plot_from_tapper_logs.py 00_tapper.log
```
# Tapper Modes
Every packet seen by the tapper is processed in a pipeline that contains various stages.
* Pcap - Read the packet from libpcap
* Assembler - Assemble the packet into a TcpStream
* TcpStream - Hold stream information and TcpReaders
* Dissectors - Read from TcpReader and recognize the packet content and protocol.
* Emit - Marshal the request response pair into a Json
* Send - Send the Json to Api Server
Tapper can be run with various debug modes:
* No Pcap - Start the tapper process, but don't read from any packets from pcap
* No Assembler - Read packets from pcap, but don't assemble them
* No TcpStream - Assemble the packets, but don't create TcpStream for them
* No Dissectors - Create a TcpStream for the packets, but don't dissect their content
* No Emit - Dissect the TcpStream, but don't emit the matched request response pair
* No Send - Emit the request response pair, but don't send them to the Api Server.
* Regular mode
![Tapper Modes](https://github.com/up9inc/mizu/blob/debug/profile-tapper-benchmark/performance_analysis/tapper-modes.png)
# Run benchmark with various tapper modes
## Prerequisite
In order to run the benchmark you probably want:
1. An up and running Api Server
2. An up and running Basenine
3. An up and running UI (optional)
4. An up and running test server, like nginx, that can return a known payload at a known endpoint.
5. Set MIZU_HOME environment variable to points to mizu directory
6. Install the `hey` tool
## Running the benchmark
In order to run a benchmark use the `run_tapper_benchmark.sh` script.
Example run:
```
cd $MIZU_HOME/performance_analysis
source venv/bin/activate # Assuming you already run plot_from_tapper_logs.py
./run_tapper_benchmark.sh
```
Running it without params use the default values, use the following environment variables for customization:
```
export=MIZU_BENCHMARK_OUTPUT_DIR=/path/to/dir # Set the output directory for tapper logs and graph
export=MIZU_BENCHMARK_CLIENT_PERIOD=1m # How long each test run
export=MIZU_BENCHMARK_URL=http://server:port/path # The URL to use for the benchmarking process (the test server endpoint)
export=MIZU_BENCHMARK_RUN_COUNT=3 # How many times each tapper mode should run
export=MIZU_BENCHMARK_QPS=250 # How many queries per second the each client should send to the test server
export=MIZU_BENCHMARK_CLIENTS_COUNT=5 # How many clients should run in parallel during the benchmark
```
# Example output graph
An example output graph from a 15 min run with 15K payload and 1000 QPS looks like
![Example Graph](https://github.com/up9inc/mizu/blob/debug/profile-tapper-benchmark/performance_analysis/example-graph.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

View File

@ -0,0 +1,183 @@
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import pathlib
import re
import sys
import typing
COLORMAP = plt.get_cmap('turbo')
# Extract cpu and rss samples from log files and plot them
# Input: List of log files
#
# example:
# python plot_from_tapper_logs.py 01_no_pcap_01.log 99_normal_00.log
#
# The script assumes that the log file names start with a number (pattern '\d+')
# and groups based on this number. Files that start will the same number will be plotted with the same color.
# Change group_pattern to an empty string to disable this, or change to a regex of your liking.
def get_sample(name: str, line: str, default_value: float):
pattern = name + r': ?(\d+(\.\d+)?)'
maybe_sample = re.findall(pattern, line)
if len(maybe_sample) == 0:
return default_value
sample = float(maybe_sample[0][0])
return sample
def append_sample(name: str, line: str, samples: typing.List[float]):
sample = get_sample(name, line, -1)
if sample == -1:
return
samples.append(sample)
def extract_samples(f: typing.IO) -> typing.Tuple[pd.Series, pd.Series, pd.Series, pd.Series, pd.Series, pd.Series, pd.Series, pd.Series]:
cpu_samples = []
rss_samples = []
count_samples = []
matched_samples = []
live_samples = []
processed_samples = []
heap_samples = []
goroutines_samples = []
for line in f:
append_sample('cpu', line, cpu_samples)
append_sample('rss', line, rss_samples)
ignored_packets_count = get_sample('"ignoredPacketsCount"', line, -1)
packets_count = get_sample('"packetsCount"', line, -1)
if ignored_packets_count != -1 and packets_count != -1:
count_samples.append(packets_count - ignored_packets_count)
append_sample('"matchedPairs"', line, matched_samples)
append_sample('"liveTcpStreams"', line, live_samples)
append_sample('"processedBytes"', line, processed_samples)
append_sample('mem', line, heap_samples)
append_sample('goroutines', line, goroutines_samples)
cpu_samples = pd.Series(cpu_samples)
rss_samples = pd.Series(rss_samples)
count_samples = pd.Series(count_samples)
matched_samples = pd.Series(matched_samples)
live_samples = pd.Series(live_samples)
processed_samples = pd.Series(processed_samples)
heap_samples = pd.Series(heap_samples)
goroutines_samples = pd.Series(goroutines_samples)
return cpu_samples, rss_samples, count_samples, matched_samples, live_samples, processed_samples, heap_samples, goroutines_samples
def plot(ax, df: pd.DataFrame, title: str, xlabel: str, ylabel: str, group_pattern: typing.Optional[str]):
if group_pattern:
color = get_group_color(df.columns, group_pattern)
df.plot(color=color, ax=ax)
else:
df.plot(cmap=COLORMAP, ax=ax)
ax.ticklabel_format(style='plain')
plt.title(title)
plt.legend()
plt.xlabel(xlabel)
plt.ylabel(ylabel)
def get_group_color(names, pattern):
props = [int(re.findall(pattern, pathlib.Path(name).name)[0]) for name in names]
key = dict(zip(sorted(list(set(props))), range(len(set(props)))))
n_colors = len(key)
color_options = plt.get_cmap('jet')(np.linspace(0, 1, n_colors))
groups = [key[prop] for prop in props]
color = color_options[groups] # type: ignore
return color
if __name__ == '__main__':
filenames = sys.argv[1:]
cpu_samples_all_files = []
rss_samples_all_files = []
count_samples_all_files = []
matched_samples_all_files = []
live_samples_all_files = []
processed_samples_all_files = []
heap_samples_all_files = []
goroutines_samples_all_files = []
for ii, filename in enumerate(filenames):
print("Analyzing {}".format(filename))
with open(filename, 'r') as f:
cpu_samples, rss_samples, count_samples, matched_samples, live_samples, processed_samples, heap_samples, goroutines_samples = extract_samples(f)
cpu_samples.name = pathlib.Path(filename).name
rss_samples.name = pathlib.Path(filename).name
count_samples.name = pathlib.Path(filename).name
matched_samples.name = pathlib.Path(filename).name
live_samples.name = pathlib.Path(filename).name
processed_samples.name = pathlib.Path(filename).name
heap_samples.name = pathlib.Path(filename).name
goroutines_samples.name = pathlib.Path(filename).name
cpu_samples_all_files.append(cpu_samples)
rss_samples_all_files.append(rss_samples)
count_samples_all_files.append(count_samples)
matched_samples_all_files.append(matched_samples)
live_samples_all_files.append(live_samples)
processed_samples_all_files.append(processed_samples)
heap_samples_all_files.append(processed_samples)
goroutines_samples_all_files.append(processed_samples)
cpu_samples_df = pd.concat(cpu_samples_all_files, axis=1)
rss_samples_df = pd.concat(rss_samples_all_files, axis=1)
count_samples_df = pd.concat(count_samples_all_files, axis=1)
matched_samples_df = pd.concat(matched_samples_all_files, axis=1)
live_samples_df = pd.concat(live_samples_all_files, axis=1)
processed_samples_df = pd.concat(processed_samples_all_files, axis=1)
heap_samples_df = pd.concat(heap_samples_all_files, axis=1)
goroutines_samples_df = pd.concat(goroutines_samples_all_files, axis=1)
group_pattern = r'^\d+'
cpu_plot = plt.subplot(8, 2, 1)
plot(cpu_plot, cpu_samples_df, 'cpu', '', 'cpu (%)', group_pattern)
cpu_plot.legend().remove()
mem_plot = plt.subplot(8, 2, 2)
plot(mem_plot, (rss_samples_df / 1024 / 1024), 'rss', '', 'mem (mega)', group_pattern)
mem_plot.legend(loc='center left', bbox_to_anchor=(1, 0.5))
packets_plot = plt.subplot(8, 2, 3)
plot(packets_plot, count_samples_df, 'packetsCount', '', 'packetsCount', group_pattern)
packets_plot.legend().remove()
matched_plot = plt.subplot(8, 2, 4)
plot(matched_plot, matched_samples_df, 'matchedCount', '', 'matchedCount', group_pattern)
matched_plot.legend().remove()
live_plot = plt.subplot(8, 2, 5)
plot(live_plot, live_samples_df, 'liveStreamsCount', '', 'liveStreamsCount', group_pattern)
live_plot.legend().remove()
processed_plot = plt.subplot(8, 2, 6)
plot(processed_plot, (processed_samples_df / 1024 / 1024), 'processedBytes', '', 'bytes (mega)', group_pattern)
processed_plot.legend().remove()
heap_plot = plt.subplot(8, 2, 7)
plot(heap_plot, (heap_samples_df / 1024 / 1024), 'heap', '', 'heap (mega)', group_pattern)
heap_plot.legend().remove()
goroutines_plot = plt.subplot(8, 2, 8)
plot(goroutines_plot, (goroutines_samples_df / 1024 / 1024), 'goroutines', '', 'goroutines', group_pattern)
goroutines_plot.legend().remove()
fig = plt.gcf()
fig.set_size_inches(20, 18)
print('Saving graph to graph.png')
plt.savefig('graph.png', bbox_inches='tight')

View File

@ -0,0 +1,2 @@
matplotlib
pandas

View File

@ -0,0 +1,92 @@
#!/bin/bash
[ -z "$MIZU_HOME" ] && { echo "MIZU_HOME is missing"; exit 1; }
[ -z "$MIZU_BENCHMARK_OUTPUT_DIR" ] && export MIZU_BENCHMARK_OUTPUT_DIR="/tmp/mizu-benchmark-results-$(date +%d-%m-%H-%M)"
[ -z "$MIZU_BENCHMARK_CLIENT_PERIOD" ] && export MIZU_BENCHMARK_CLIENT_PERIOD="1m"
[ -z "$MIZU_BENCHMARK_URL" ] && export MIZU_BENCHMARK_URL="http://localhost:8081/data/b.1000.json"
[ -z "$MIZU_BENCHMARK_RUN_COUNT" ] && export MIZU_BENCHMARK_RUN_COUNT="3"
[ -z "$MIZU_BENCHMARK_QPS" ] && export MIZU_BENCHMARK_QPS="500"
[ -z "$MIZU_BENCHMARK_CLIENTS_COUNT" ] && export MIZU_BENCHMARK_CLIENTS_COUNT="5"
function log() {
local message=$@
printf "[%s] %s\n" "$(date "+%d-%m %H:%M:%S")" "$message"
}
function run_single_bench() {
local mode_num=$1
local mode_str=$2
log "Starting ${mode_num}_${mode_str} (runs: $MIZU_BENCHMARK_RUN_COUNT) (period: $MIZU_BENCHMARK_CLIENT_PERIOD)"
for ((i=0;i<"$MIZU_BENCHMARK_RUN_COUNT";i++)); do
log " $i: Running tapper"
rm -f tapper.log
nohup ./agent/build/mizuagent --tap --api-server-address ws://localhost:8899/wsTapper -i lo -stats 10 > tapper.log 2>&1 &
log " $i: Running client (hey)"
hey -z $MIZU_BENCHMARK_CLIENT_PERIOD -c $MIZU_BENCHMARK_CLIENTS_COUNT -q $MIZU_BENCHMARK_QPS $MIZU_BENCHMARK_URL > /dev/null || return 1
log " $i: Killing tapper"
kill -9 $(ps -ef | grep agent/build/mizuagent | grep tap | grep -v grep | awk '{ print $2 }') > /dev/null 2>&1
local output_file=$MIZU_BENCHMARK_OUTPUT_DIR/${mode_num}_${mode_str}_${i}.log
log " $i: Moving output to $output_file"
mv tapper.log $output_file || return 1
done
}
function generate_bench_graph() {
cd performance_analysis/ || return 1
source venv/bin/activate
python plot_from_tapper_logs.py $MIZU_BENCHMARK_OUTPUT_DIR/*.log || return 1
mv graph.png $MIZU_BENCHMARK_OUTPUT_DIR || return 1
}
mkdir -p $MIZU_BENCHMARK_OUTPUT_DIR
rm -f $MIZU_BENCHMARK_OUTPUT_DIR/*
log "Writing output to $MIZU_BENCHMARK_OUTPUT_DIR"
cd $MIZU_HOME || exit 1
export HOST_MODE=0
export MIZU_DEBUG_DISABLE_PCAP=false
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=false
export MIZU_DEBUG_DISABLE_TCP_STREAM=false
export MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION=false
export MIZU_DEBUG_DISABLE_DISSECTORS=false
export MIZU_DEBUG_DISABLE_EMITTING=false
export MIZU_DEBUG_DISABLE_SENDING=false
export MIZU_DEBUG_DISABLE_PCAP=true
run_single_bench "01" "no_pcap" || exit 1
export MIZU_DEBUG_DISABLE_PCAP=false
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=true
run_single_bench "02" "no_assembler" || exit 1
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=false
export MIZU_DEBUG_DISABLE_TCP_STREAM=true
run_single_bench "03" "no_tcp_stream" || exit 1
export MIZU_DEBUG_DISABLE_TCP_STREAM=false
export MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION=true
run_single_bench "04" "only_http" || exit 1
export MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION=false
export MIZU_DEBUG_DISABLE_DISSECTORS=true
run_single_bench "05" "no_dissectors" || exit 1
export MIZU_DEBUG_DISABLE_DISSECTORS=false
export MIZU_DEBUG_DISABLE_EMITTING=true
run_single_bench "06" "no_emit" || exit 1
export MIZU_DEBUG_DISABLE_EMITTING=false
export MIZU_DEBUG_DISABLE_SENDING=true
run_single_bench "07" "no_send" || exit 1
export MIZU_DEBUG_DISABLE_SENDING=false
run_single_bench "08" "normal" || exit 1
generate_bench_graph || exit 1
log "Output written to to $MIZU_BENCHMARK_OUTPUT_DIR"

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

View File

@ -67,6 +67,7 @@ require (
github.com/spf13/cobra v1.3.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
github.com/xlab/treeprint v1.1.0 // indirect
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab // indirect
@ -95,3 +96,5 @@ require (
replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../tap/dbgctl

View File

@ -181,6 +181,7 @@ type ApiServerOptions struct {
Resources shared.Resources
ImagePullPolicy core.PullPolicy
LogLevel logging.Level
Profiler bool
}
func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, mountVolumeClaim bool, volumeClaimName string, createAuthContainer bool) (*core.Pod, error) {
@ -212,7 +213,15 @@ func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, moun
return nil, fmt.Errorf("invalid memory request for %s container", opts.PodName)
}
command := []string{"./mizuagent", "--api-server"}
command := []string{
"./mizuagent",
"--api-server",
}
if opts.Profiler {
command = append(command, "--profiler")
}
if opts.IsNamespaceRestricted {
command = append(command, "--namespace", opts.Namespace)
}

View File

@ -15,6 +15,8 @@ import (
"time"
"github.com/google/martian/har"
"github.com/up9inc/mizu/tap/dbgctl"
)
const mizuTestEnvVar = "MIZU_TEST"
@ -149,8 +151,13 @@ type Emitter interface {
}
func (e *Emitting) Emit(item *OutputChannelItem) {
e.OutputChannel <- item
e.AppStats.IncMatchedPairs()
if dbgctl.MizuTapperDisableEmitting {
return
}
e.OutputChannel <- item
}
type Entry struct {

View File

@ -2,4 +2,9 @@ module github.com/up9inc/mizu/tap/api
go 1.17
require github.com/google/martian v2.1.0+incompatible
require (
github.com/google/martian v2.1.0+incompatible
github.com/up9inc/mizu/tap/dbgctl v0.0.0
)
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../dbgctl

View File

@ -15,6 +15,7 @@ type AppStats struct {
TlsConnectionsCount uint64 `json:"tlsConnectionsCount"`
MatchedPairs uint64 `json:"matchedPairs"`
DroppedTcpStreams uint64 `json:"droppedTcpStreams"`
LiveTcpStreams uint64 `json:"liveTcpStreams"`
}
func (as *AppStats) IncMatchedPairs() {
@ -46,6 +47,14 @@ func (as *AppStats) IncTlsConnectionsCount() {
atomic.AddUint64(&as.TlsConnectionsCount, 1)
}
func (as *AppStats) IncLiveTcpStreams() {
atomic.AddUint64(&as.LiveTcpStreams, 1)
}
func (as *AppStats) DecLiveTcpStreams() {
atomic.AddUint64(&as.LiveTcpStreams, ^uint64(0))
}
func (as *AppStats) UpdateProcessedBytes(size uint64) {
atomic.AddUint64(&as.ProcessedBytes, size)
}
@ -65,6 +74,7 @@ func (as *AppStats) DumpStats() *AppStats {
currentAppStats.TlsConnectionsCount = resetUint64(&as.TlsConnectionsCount)
currentAppStats.MatchedPairs = resetUint64(&as.MatchedPairs)
currentAppStats.DroppedTcpStreams = resetUint64(&as.DroppedTcpStreams)
currentAppStats.LiveTcpStreams = as.LiveTcpStreams
return currentAppStats
}

View File

@ -0,0 +1,15 @@
package dbgctl
import (
"os"
)
var (
MizuTapperDisablePcap bool = os.Getenv("MIZU_DEBUG_DISABLE_PCAP") == "true"
MizuTapperDisableTcpReassembly bool = os.Getenv("MIZU_DEBUG_DISABLE_TCP_REASSEMBLY") == "true"
MizuTapperDisableTcpStream bool = os.Getenv("MIZU_DEBUG_DISABLE_TCP_STREAM") == "true"
MizuTapperDisableDissectors bool = os.Getenv("MIZU_DEBUG_DISABLE_DISSECTORS") == "true"
MizuTapperDisableEmitting bool = os.Getenv("MIZU_DEBUG_DISABLE_EMITTING") == "true"
MizuTapperDisableSending bool = os.Getenv("MIZU_DEBUG_DISABLE_SENDING") == "true"
MizuTapperDisableNonHttpExtensions bool = os.Getenv("MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION") == "true"
)

3
tap/dbgctl/go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/up9inc/mizu/tap/dbgctl
go 1.18

View File

@ -11,7 +11,10 @@ require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/google/martian v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../../api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../../dbgctl

View File

@ -14,8 +14,11 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/martian v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../../api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../../dbgctl

View File

@ -18,7 +18,10 @@ require (
github.com/klauspost/compress v1.14.2 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../../api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../../dbgctl

View File

@ -11,7 +11,10 @@ require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/google/martian v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../../api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../../dbgctl

View File

@ -7,14 +7,18 @@ require (
github.com/go-errors/errors v1.4.2
github.com/google/gopacket v1.1.19
github.com/hashicorp/golang-lru v0.5.4
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/struCoder/pidusage v0.2.1
github.com/up9inc/mizu/logger v0.0.0
github.com/up9inc/mizu/tap/api v0.0.0
github.com/up9inc/mizu/tap/dbgctl v0.0.0
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74
k8s.io/api v0.23.3
)
require (
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.2.0 // indirect
@ -23,6 +27,9 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect
golang.org/x/text v0.3.7 // indirect
@ -33,8 +40,11 @@ require (
k8s.io/utils v0.0.0-20220127004650-9b3446523e65 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
replace github.com/up9inc/mizu/tap/api v0.0.0 => ./api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ./dbgctl

View File

@ -31,6 +31,8 @@ github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
@ -117,6 +119,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@ -126,11 +130,19 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/struCoder/pidusage v0.2.1 h1:dFiEgUDkubeIj0XA1NpQ6+8LQmKrLi7NiIQl86E6BoY=
github.com/struCoder/pidusage v0.2.1/go.mod h1:bewtP2KUA1TBUyza5+/PCpSQ6sc/H6jJbIKAzqW86BA=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -170,6 +182,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -184,6 +197,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc=
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@ -18,6 +18,8 @@ import (
"time"
"strconv"
"github.com/shirou/gopsutil/cpu"
"github.com/struCoder/pidusage"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/tap/api"
"github.com/up9inc/mizu/tap/diagnose"
@ -126,6 +128,16 @@ func printPeriodicStats(cleaner *Cleaner) {
statsPeriod := time.Second * time.Duration(*statsevery)
ticker := time.NewTicker(statsPeriod)
logicalCoreCount, err := cpu.Counts(true)
if err != nil {
logicalCoreCount = -1
}
physicalCoreCount, err := cpu.Counts(false)
if err != nil {
physicalCoreCount = -1
}
for {
<-ticker.C
@ -142,11 +154,21 @@ func printPeriodicStats(cleaner *Cleaner) {
// At this moment
memStats := runtime.MemStats{}
runtime.ReadMemStats(&memStats)
sysInfo, err := pidusage.GetStat(os.Getpid())
if err != nil {
sysInfo = &pidusage.SysInfo{
CPU: -1,
Memory: -1,
}
}
logger.Log.Infof(
"mem: %d, goroutines: %d",
"mem: %d, goroutines: %d, cpu: %f, cores: %d/%d, rss: %f",
memStats.HeapAlloc,
runtime.NumGoroutine(),
)
sysInfo.CPU,
logicalCoreCount,
physicalCoreCount,
sysInfo.Memory)
// Since the last print
cleanStats := cleaner.dumpStats()

View File

@ -11,6 +11,7 @@ import (
"github.com/google/gopacket/pcap"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/tap/api"
"github.com/up9inc/mizu/tap/dbgctl"
"github.com/up9inc/mizu/tap/diagnose"
)
@ -116,6 +117,9 @@ func (source *tcpPacketSource) close() {
}
func (source *tcpPacketSource) readPackets(ipdefrag bool, packets chan<- TcpPacketInfo) {
if dbgctl.MizuTapperDisablePcap {
return
}
logger.Log.Infof("Start reading packets from %v", source.name)
for {

View File

@ -12,6 +12,7 @@ import (
"github.com/google/gopacket/reassembly"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/tap/api"
"github.com/up9inc/mizu/tap/dbgctl"
"github.com/up9inc/mizu/tap/diagnose"
"github.com/up9inc/mizu/tap/source"
)
@ -93,9 +94,11 @@ func (a *tcpAssembler) processPackets(dumpPacket bool, packets <-chan source.Tcp
Origin: packetInfo.Source.Origin,
}
diagnose.InternalStats.Totalsz += len(tcp.Payload)
a.assemblerMutex.Lock()
a.AssembleWithContext(packet.NetworkLayer().NetworkFlow(), tcp, &c)
a.assemblerMutex.Unlock()
if !dbgctl.MizuTapperDisableTcpReassembly {
a.assemblerMutex.Lock()
a.AssembleWithContext(packet.NetworkLayer().NetworkFlow(), tcp, &c)
a.assemblerMutex.Unlock()
}
}
}

View File

@ -7,6 +7,7 @@ import (
"time"
"github.com/up9inc/mizu/tap/api"
"github.com/up9inc/mizu/tap/dbgctl"
)
/* TcpReader gets reads from a channel of bytes of tcp payload, and parses it into requests and responses.
@ -48,6 +49,13 @@ func NewTcpReader(ident string, tcpId *api.TcpID, parent *tcpStream, isClient bo
func (reader *tcpReader) run(options *api.TrafficFilteringOptions, wg *sync.WaitGroup) {
defer wg.Done()
if dbgctl.MizuTapperDisableDissectors {
b := bufio.NewReader(reader)
_, _ = io.ReadAll(b)
return
}
for i, extension := range extensions {
reader.reqResMatcher = reader.parent.reqResMatchers[i]
reader.counterPair = reader.parent.counterPairs[i]

View File

@ -5,6 +5,7 @@ import (
"time"
"github.com/up9inc/mizu/tap/api"
"github.com/up9inc/mizu/tap/dbgctl"
)
/* It's a connection (bidirectional)
@ -91,6 +92,9 @@ func (t *tcpStream) GetReqResMatchers() []api.RequestResponseMatcher {
}
func (t *tcpStream) GetIsTapTarget() bool {
if dbgctl.MizuTapperDisableTcpStream {
return false
}
return t.isTapTarget
}

View File

@ -28,10 +28,12 @@ func (streamMap *tcpStreamMap) Range(f func(key, value interface{}) bool) {
func (streamMap *tcpStreamMap) Store(key, value interface{}) {
streamMap.streams.Store(key, value)
diagnose.AppStats.IncLiveTcpStreams()
}
func (streamMap *tcpStreamMap) Delete(key interface{}) {
streamMap.streams.Delete(key)
diagnose.AppStats.DecLiveTcpStreams()
}
func (streamMap *tcpStreamMap) NextId() int64 {