Skip to content

Commit 64cc7d7

Browse files
committed
MINOR: runtime: update whole backend at once
this will reduce number of socket calls to HAProxy to library
1 parent 5ef7e18 commit 64cc7d7

File tree

2 files changed

+105
-20
lines changed

2 files changed

+105
-20
lines changed

pkg/haproxy/api/api.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ type HAProxyClient interface { //nolint:interfacebloat
6565
PeerEntryEdit(peerSection string, peer models.PeerEntry) error
6666
RefreshBackends() (deleted []string, err error)
6767
SetMapContent(mapFile string, payload []string) error
68-
SetServerAddr(backendName string, serverName string, ip string, port int) error
69-
SetServerState(backendName string, serverName string, state string) error
68+
SetServerAddrAndState([]RuntimeServerData) error
7069
ServerGet(serverName, backendNa string) (models.Server, error)
7170
SetAuxCfgFile(auxCfgFile string)
7271
SyncBackendSrvs(backend *store.RuntimeBackend, portUpdated bool) error

pkg/haproxy/api/runtime.go

Lines changed: 104 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
11
package api
22

33
import (
4+
"errors"
45
"fmt"
6+
"strconv"
57
"strings"
68

79
"github.com/haproxytech/client-native/v5/models"
10+
"github.com/haproxytech/client-native/v5/runtime"
811

912
"github.com/haproxytech/kubernetes-ingress/pkg/store"
1013
"github.com/haproxytech/kubernetes-ingress/pkg/utils"
1114
)
1215

1316
var ErrMapNotFound = fmt.Errorf("map not found")
1417

18+
// bufsize is the default value of HAproxy tune.bufsize. Not recommended to change it
19+
// Map payload cannot be bigger than tune.bufsize
20+
const bufSize = 16000
21+
22+
type RuntimeServerData struct {
23+
BackendName string
24+
ServerName string
25+
IP string
26+
Port int
27+
State string
28+
}
29+
1530
func (c *clientNative) ExecuteRaw(command string) (result []string, err error) {
1631
runtime, err := c.nativeAPI.Runtime()
1732
if err != nil {
@@ -20,20 +35,83 @@ func (c *clientNative) ExecuteRaw(command string) (result []string, err error) {
2035
return runtime.ExecuteRaw(command)
2136
}
2237

23-
func (c *clientNative) SetServerAddr(backendName string, serverName string, ip string, port int) error {
38+
func (c *clientNative) SetServerAddrAndState(servers []RuntimeServerData) error {
2439
runtime, err := c.nativeAPI.Runtime()
2540
if err != nil {
2641
return err
2742
}
28-
return runtime.SetServerAddr(backendName, serverName, ip, port)
43+
if len(servers) == 0 {
44+
return nil
45+
}
46+
backendNameSize := len(servers[0].BackendName)
47+
oneServerCommandSize := 65 + 2*backendNameSize
48+
size := oneServerCommandSize * len(servers)
49+
if size > bufSize {
50+
size = bufSize
51+
}
52+
53+
var sb strings.Builder
54+
sb.Grow(size)
55+
var cmdBuilder strings.Builder
56+
cmdBuilder.Grow(oneServerCommandSize)
57+
for _, server := range servers {
58+
// if new commands are added recalculate oneServerCommandSize
59+
cmdBuilder.WriteString("set server ")
60+
cmdBuilder.WriteString(server.BackendName)
61+
cmdBuilder.WriteString("/")
62+
cmdBuilder.WriteString(server.ServerName)
63+
cmdBuilder.WriteString(" addr ")
64+
cmdBuilder.WriteString(server.IP)
65+
if server.Port > 0 {
66+
cmdBuilder.WriteString(" port ")
67+
cmdBuilder.WriteString(strconv.Itoa(server.Port))
68+
}
69+
cmdBuilder.WriteString(";set server ")
70+
cmdBuilder.WriteString(server.BackendName)
71+
cmdBuilder.WriteString("/")
72+
cmdBuilder.WriteString(server.ServerName)
73+
cmdBuilder.WriteString(" state ")
74+
cmdBuilder.WriteString(server.State)
75+
cmdBuilder.WriteString(";")
76+
// if new commands are added recalculate oneServerCommandSize
77+
78+
if sb.Len()+cmdBuilder.Len() >= size {
79+
err = c.runRaw(runtime, sb, server.BackendName)
80+
if err != nil {
81+
return err
82+
}
83+
sb.Reset()
84+
sb.Grow(size)
85+
}
86+
sb.WriteString(cmdBuilder.String())
87+
cmdBuilder.Reset()
88+
cmdBuilder.Grow(oneServerCommandSize)
89+
}
90+
if sb.Len() > 0 {
91+
err = c.runRaw(runtime, sb, servers[0].BackendName)
92+
if err != nil {
93+
return err
94+
}
95+
}
96+
return nil
2997
}
3098

31-
func (c *clientNative) SetServerState(backendName string, serverName string, state string) error {
32-
runtime, err := c.nativeAPI.Runtime()
99+
func (c *clientNative) runRaw(runtime runtime.Runtime, sb strings.Builder, backendName string) error {
100+
logger := utils.GetLogger()
101+
result, err := runtime.ExecuteRaw(sb.String())
33102
if err != nil {
34103
return err
35104
}
36-
return runtime.SetServerState(backendName, serverName, state)
105+
for i := 0; i < len(result); i++ {
106+
if len(result[i]) > 5 {
107+
switch result[i][1:5] {
108+
case "[3]:", "[2]:", "[1]:", "[0]:":
109+
logger.Errorf("[RUNTIME] [BACKEND] [SOCKET] backend %s: Error: '%s', server slots adjustment ?", backendName, result[i])
110+
return errors.New("runtime update failed for " + backendName)
111+
}
112+
}
113+
}
114+
return nil
37115
}
38116

39117
func (c *clientNative) SetMapContent(mapFile string, payload []string) error {
@@ -91,7 +169,6 @@ func (c *clientNative) SyncBackendSrvs(backend *store.RuntimeBackend, portUpdate
91169
// Disable stale entries from HAProxySrvs
92170
// and provide list of Disabled Srvs
93171
var disabled []*store.HAProxySrv
94-
var errors utils.Errors
95172
for i, srv := range haproxySrvs {
96173
srv.Modified = srv.Modified || portUpdated
97174
if _, ok := addresses[srv.Address]; ok {
@@ -118,26 +195,35 @@ func (c *clientNative) SyncBackendSrvs(backend *store.RuntimeBackend, portUpdate
118195
logger.Tracef("[RUNTIME] [BACKEND] [SERVER] backend %s: list of endpoints addresses after treatment %+v", backend.Name, addresses)
119196

120197
// Dynamically updates HAProxy backend servers with HAProxySrvs content
121-
var addrErr, stateErr error
198+
runtimeServerData := make([]RuntimeServerData, 0, len(haproxySrvs))
122199
for _, srv := range haproxySrvs {
123200
if !srv.Modified {
124201
continue
125202
}
126203
if srv.Address == "" {
127204
logger.Tracef("[RUNTIME] [BACKEND] [SERVER] [SOCKET] backend %s: server '%s' changed status to %v", backend.Name, srv.Name, "maint")
128-
addrErr = c.SetServerAddr(backend.Name, srv.Name, "127.0.0.1", 0)
129-
stateErr = c.SetServerState(backend.Name, srv.Name, "maint")
205+
runtimeServerData = append(runtimeServerData, RuntimeServerData{
206+
BackendName: backend.Name,
207+
ServerName: srv.Name,
208+
IP: "127.0.0.1",
209+
Port: 0,
210+
State: "maint",
211+
})
130212
} else {
131213
logger.Tracef("[RUNTIME] [BACKEND] [SERVER] [SOCKET] backend %s: server '%s': addr '%s' changed status to %v", backend.Name, srv.Name, srv.Address, "ready")
132-
addrErr = c.SetServerAddr(backend.Name, srv.Name, srv.Address, int(backend.Endpoints.Port))
133-
stateErr = c.SetServerState(backend.Name, srv.Name, "ready")
134-
}
135-
if addrErr != nil || stateErr != nil {
136-
backend.DynUpdateFailed = true
137-
errors.Add(addrErr)
138-
errors.Add(stateErr)
139-
logger.Errorf("[RUNTIME] [BACKEND] [SERVER] [SOCKET] backend %s: server '%s': addr '%s': addrError '%v': stateError: '%v'", backend.Name, srv.Name, srv.Address, addrErr, stateErr)
214+
runtimeServerData = append(runtimeServerData, RuntimeServerData{
215+
BackendName: backend.Name,
216+
ServerName: srv.Name,
217+
IP: srv.Address,
218+
Port: int(backend.Endpoints.Port),
219+
State: "ready",
220+
})
140221
}
141222
}
142-
return errors.Result()
223+
err := c.SetServerAddrAndState(runtimeServerData)
224+
if err != nil {
225+
backend.DynUpdateFailed = true
226+
return err
227+
}
228+
return nil
143229
}

0 commit comments

Comments
 (0)