Documentation
¶
Overview ¶
Package apply turns health-check verdicts into IPVS table changes.
It is the seam between framework, which decides whether a backend is usable, and ipvs, which can write the kernel's table. Neither knows about the other, and this is the only place that knows both.
Removing a server and draining a server are different operations ¶
A failed real server can be handled two ways, and the difference decides whether existing connections survive:
- **Remove** it from the table. Established connections to it are dropped immediately, because the kernel no longer has an entry to route them by.
- **Set its weight to zero** (`inhibit_on_failure`). No *new* connections are scheduled to it, and existing ones continue until they close.
Draining is almost always what an operator wants for a server that failed a health check but is still answering — an application that is slow is not an application that should have every in-flight request killed. Removal is what they want for one that is genuinely gone.
Index ¶
- Variables
- type Applier
- func (a *Applier) Init(vs *framework.VirtualServer) error
- func (a *Applier) Present(vsName, rsName string) bool
- func (a *Applier) Quorum(vsName string, ev framework.QuorumEvent) error
- func (a *Applier) Replace(vs map[string]*VirtualServer)
- func (a *Applier) SetAlive(vsName, rsName string, alive bool) error
- func (a *Applier) SetWeight(vsName, rsName string, weight int) error
- func (a *Applier) SorryInstalled(vsName string) bool
- type IPVS
- type RealServer
- type TrackedFile
- type VirtualServer
Constants ¶
This section is empty.
Variables ¶
var ErrUnknown = errors.New("apply: unknown virtual or real server")
ErrUnknown is returned for a server or service this applier was not configured with.
Functions ¶
This section is empty.
Types ¶
type Applier ¶
type Applier struct {
// contains filtered or unexported fields
}
Applier writes verdicts into the kernel.
func (*Applier) Init ¶
func (a *Applier) Init(vs *framework.VirtualServer) error
Init installs every service and every real server that starts up.
A server that starts *down* — alpha mode — is not installed at all. Adding it and immediately removing it would put it in the table for however long the two syscalls take, and traffic scheduled in that window goes to a backend nobody has checked.
A virtual server that starts *below quorum* gets its sorry server here. C arranges the same thing by calling update_quorum_state with init true at the end of init_service_vs (ipwrapper.c:659), whose losing branch has a second disjunct for exactly this state (ipwrapper.c:552-553). Without it the sorry server appears only after a backend has come up and gone down again — so a cold start against a dead pool, the case it most exists for, serves connection-refused.
func (*Applier) Present ¶
Present reports whether a destination is currently in the table, for tests and for an operational dump.
func (*Applier) Quorum ¶
func (a *Applier) Quorum(vsName string, ev framework.QuorumEvent) error
Quorum applies a quorum transition.
The sorry server goes in *before* the real servers come out and comes out *after* they go back in. Ordering it the other way leaves a window with no destination at all, and a virtual server with no destinations refuses connections — which is precisely the failure the sorry server exists to replace with something controlled.
func (*Applier) Replace ¶
func (a *Applier) Replace(vs map[string]*VirtualServer)
Replace swaps in a new configuration after a reload.
The presence tracking is *kept*, not reset. It records what is actually in the kernel's table, and a reload does not empty the table — that is the whole point of diffing rather than rebuilding. Resetting it would make the next verdict on a surviving backend use AddDest where the destination already exists, which gives EEXIST.
Entries for virtual servers that no longer exist are dropped, so the map does not grow across reloads on a daemon that is up for months.
func (*Applier) SetAlive ¶
SetAlive applies one real server's verdict.
While the sorry server is serving the table is not touched at all. C guards the same way — "Change only if we have quorum or no sorry server" (ipwrapper.c:612-616) — and without it a backend recovering during a quorum outage would be added back alongside the sorry server, undoing the pool withdrawal one server at a time. The verdict is still recorded, so the pool restored when quorum returns is the one that is healthy then, not the one that was healthy when it was withdrawn.
func (*Applier) SetWeight ¶
SetWeight changes a live real server's weight, for a weighted tracker that moved without the server going down.
func (*Applier) SorryInstalled ¶
SorryInstalled reports whether a sorry server is currently installed.
type IPVS ¶
type IPVS interface {
AddService(ipvs.Service) error
SetService(ipvs.Service) error
DelService(ipvs.Service) error
AddDest(ipvs.Service, ipvs.Dest) error
SetDest(ipvs.Service, ipvs.Dest) error
DelDest(ipvs.Service, ipvs.Dest) error
}
IPVS is the subset of ipvs.Conn this package uses, so the sequencing can be tested without root.
type RealServer ¶
type RealServer struct {
Name string
Dest ipvs.Dest
// Inhibit drains instead of removing; see the package comment.
Inhibit bool
// Weight is the configured weight, restored when the server comes back.
Weight int
}
RealServer binds a framework real server to its IPVS destination.
type TrackedFile ¶
type TrackedFile struct {
// RealServer is the backend the weight applies to.
RealServer string
// File is the track_file name, resolved to a path elsewhere.
File string
// Weight is the contribution, following the same rules as a VRRP
// instance's track_file.
Weight int
}
VirtualServer binds a framework virtual server to its IPVS service. TrackedFile is one real_server track_file entry.
The weight comes from a file rather than a probe, which is how an operator drains a backend for maintenance: write to the file and the weight drops, without editing the configuration or stopping the process the checkers probe.
type VirtualServer ¶
type VirtualServer struct {
// TrackedFiles are the real_server track_file entries, so the file
// watcher can find which backend each belongs to.
TrackedFiles []TrackedFile
Name string
Service ipvs.Service
Servers map[string]*RealServer
// SorryServer is installed while quorum is lost, so clients get a
// controlled response instead of a connection refused.
SorryServer *ipvs.Dest
// SorryServerInhibit drains the sorry server instead of removing it,
// the same distinction the package comment draws for a real server. It
// changes when the destination exists as well as how it leaves: an
// inhibit sorry server sits in the table from startup at weight zero,
// so that losing quorum raises a weight rather than inserting an entry
// (ipwrapper.c:661-673).
SorryServerInhibit bool
}