Skip to content

Commit

Permalink
Poll conns on agents to prevent high cpu usage
Browse files Browse the repository at this point in the history
  • Loading branch information
muraty committed Oct 13, 2020
1 parent c1e727e commit 03f4074
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 18 deletions.
60 changes: 44 additions & 16 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"os"
"strconv"
"time"

"github.com/cenkalti/log"
gopsutilNet "github.com/shirou/gopsutil/net"
Expand All @@ -17,12 +18,24 @@ import (
func NewAgent(cfg *config.Config) *Agent {
d := new(Agent)
d.Config = &cfg.Agent
d.Hostname = getHostname()
return d
}

func getHostname() string {
hostname, err := os.Hostname()
if err != nil {
log.Errorf("Hostname could not found")
hostname = "UNKNOWN"
}
return hostname
}

// Agent is type for handling agent operations
type Agent struct {
Config *config.Agent
Config *config.Agent
Conns []gopsutilNet.ConnectionStat
Hostname string
}

func parsePortParam(w http.ResponseWriter, req *http.Request) (uint32, error) {
Expand Down Expand Up @@ -50,20 +63,7 @@ func (a *Agent) Process(w http.ResponseWriter, req *http.Request) {
http.Error(w, "port param is required", http.StatusBadRequest)
return
}
connections, err := gopsutilNet.Connections("all")
if err != nil {
log.Errorf("Error while getting connections: %s\n", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

hostname, err := os.Hostname()
if err != nil {
log.Errorf("Hostname could not found")
hostname = "UNKNOWN"
}

for _, conn := range connections {
for _, conn := range a.Conns {
if conn.Laddr.Port != port {
continue
}
Expand Down Expand Up @@ -98,16 +98,44 @@ func (a *Agent) Process(w http.ResponseWriter, req *http.Request) {
Pid: conn.Pid,
Name: name,
CmdLine: cls,
Hostname: hostname,
Hostname: a.Hostname,
})
return
}
http.Error(w, "process not found!", http.StatusNotFound)
return
}

func (a *Agent) pollConns() {
// todo: run with context
log.Debugln("Polling...")
ticker := time.NewTicker(a.Config.PollDuration * time.Second)

for {
a.getConns() // poll immediately at the initialization
select {
// todo: add return case
case <-ticker.C:
a.getConns()
}
}

}
func (a *Agent) getConns() {
// This is an expensive operation.
// So, we need to call infrequent to prevent high load on servers those run kimo agents.
conns, err := gopsutilNet.Connections("all")
if err != nil {
log.Errorln(err.Error())
return
}
a.Conns = conns
}

// Run is main function to run http server
func (a *Agent) Run() error {
go a.pollConns()

http.HandleFunc("/proc", a.Process)
err := http.ListenAndServe(a.Config.ListenAddress, nil)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions config.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
debug = true
[agent]
listen_address = "0.0.0.0:3333"
poll_duration = 30
[server]
dsn = "kimo:123@(mysql:3306)/information_schema"
listen_address = "0.0.0.0:3322"
Expand Down
6 changes: 4 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ type Server struct {

// Agent is used as anget config on agent machines
type Agent struct {
ListenAddress string `toml:"listen_address"`
ListenAddress string `toml:"listen_address"`
PollDuration time.Duration `toml:"poll_duration"`
}

// NewConfig is constructor function for Config type
Expand All @@ -48,7 +49,7 @@ var defaultConfig = Config{
Server: Server{
DSN: "",
AgentPort: 3333,
PollDuration: 30,
PollDuration: 10,
TCPProxyMgmtAddress: "tcpproxy:3307",
ListenAddress: "0.0.0.0:3322",
AgentConnectTimeout: 2,
Expand All @@ -58,6 +59,7 @@ var defaultConfig = Config{
},
Agent: Agent{
ListenAddress: "0.0.0.0:3333",
PollDuration: 30,
},
Debug: true,
}

0 comments on commit 03f4074

Please sign in to comment.