k8s.io/kubernetes@v1.29.3/pkg/proxy/ipvs/graceful_termination.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package ipvs 18 19 import ( 20 "fmt" 21 "sync" 22 "time" 23 24 "k8s.io/apimachinery/pkg/util/wait" 25 "k8s.io/klog/v2" 26 utilipvs "k8s.io/kubernetes/pkg/proxy/ipvs/util" 27 ) 28 29 const ( 30 rsCheckDeleteInterval = 1 * time.Minute 31 ) 32 33 // listItem stores real server information and the process time. 34 // If nothing special happened, real server will be delete after process time. 35 type listItem struct { 36 VirtualServer *utilipvs.VirtualServer 37 RealServer *utilipvs.RealServer 38 } 39 40 // String return the unique real server name(with virtual server information) 41 func (g *listItem) String() string { 42 return GetUniqueRSName(g.VirtualServer, g.RealServer) 43 } 44 45 // GetUniqueRSName return a string type unique rs name with vs information 46 func GetUniqueRSName(vs *utilipvs.VirtualServer, rs *utilipvs.RealServer) string { 47 return vs.String() + "/" + rs.String() 48 } 49 50 type graceTerminateRSList struct { 51 lock sync.Mutex 52 list map[string]*listItem 53 } 54 55 // add push an new element to the rsList 56 func (q *graceTerminateRSList) add(rs *listItem) bool { 57 q.lock.Lock() 58 defer q.lock.Unlock() 59 60 uniqueRS := rs.String() 61 if _, ok := q.list[uniqueRS]; ok { 62 return false 63 } 64 65 klog.V(5).InfoS("Adding real server to graceful delete real server list", "realServer", rs) 66 q.list[uniqueRS] = rs 67 return true 68 } 69 70 // remove remove an element from the rsList 71 func (q *graceTerminateRSList) remove(rs *listItem) bool { 72 q.lock.Lock() 73 defer q.lock.Unlock() 74 75 uniqueRS := rs.String() 76 if _, ok := q.list[uniqueRS]; ok { 77 delete(q.list, uniqueRS) 78 return true 79 } 80 return false 81 } 82 83 // return the size of the list 84 func (q *graceTerminateRSList) len() int { 85 q.lock.Lock() 86 defer q.lock.Unlock() 87 88 return len(q.list) 89 } 90 91 func (q *graceTerminateRSList) flushList(handler func(rsToDelete *listItem) (bool, error)) bool { 92 q.lock.Lock() 93 defer q.lock.Unlock() 94 success := true 95 for name, rs := range q.list { 96 deleted, err := handler(rs) 97 if err != nil { 98 klog.ErrorS(err, "Error in deleting real server", "realServer", name) 99 success = false 100 } 101 if deleted { 102 klog.InfoS("Removed real server from graceful delete real server list", "realServer", name) 103 delete(q.list, rs.String()) 104 } 105 } 106 return success 107 } 108 109 // exist check whether the specified unique RS is in the rsList 110 func (q *graceTerminateRSList) exist(uniqueRS string) (*listItem, bool) { 111 q.lock.Lock() 112 defer q.lock.Unlock() 113 114 if rs, ok := q.list[uniqueRS]; ok { 115 return rs, true 116 } 117 return nil, false 118 } 119 120 // GracefulTerminationManager manage rs graceful termination information and do graceful termination work 121 // rsList is the rs list to graceful termination, ipvs is the ipvsinterface to do ipvs delete/update work 122 type GracefulTerminationManager struct { 123 rsList graceTerminateRSList 124 ipvs utilipvs.Interface 125 } 126 127 // NewGracefulTerminationManager create a gracefulTerminationManager to manage ipvs rs graceful termination work 128 func NewGracefulTerminationManager(ipvs utilipvs.Interface) *GracefulTerminationManager { 129 l := make(map[string]*listItem) 130 return &GracefulTerminationManager{ 131 rsList: graceTerminateRSList{ 132 list: l, 133 }, 134 ipvs: ipvs, 135 } 136 } 137 138 // InTerminationList to check whether specified unique rs name is in graceful termination list 139 func (m *GracefulTerminationManager) InTerminationList(uniqueRS string) bool { 140 _, exist := m.rsList.exist(uniqueRS) 141 return exist 142 } 143 144 // GracefulDeleteRS to update rs weight to 0, and add rs to graceful terminate list 145 func (m *GracefulTerminationManager) GracefulDeleteRS(vs *utilipvs.VirtualServer, rs *utilipvs.RealServer) error { 146 // Try to delete rs before add it to graceful delete list 147 ele := &listItem{ 148 VirtualServer: vs, 149 RealServer: rs, 150 } 151 deleted, err := m.deleteRsFunc(ele) 152 if err != nil { 153 klog.ErrorS(err, "Error in deleting real server", "realServer", ele) 154 } 155 if deleted { 156 return nil 157 } 158 rs.Weight = 0 159 err = m.ipvs.UpdateRealServer(vs, rs) 160 if err != nil { 161 return err 162 } 163 klog.V(5).InfoS("Adding real server to graceful delete real server list", "realServer", ele) 164 m.rsList.add(ele) 165 return nil 166 } 167 168 func (m *GracefulTerminationManager) deleteRsFunc(rsToDelete *listItem) (bool, error) { 169 klog.V(5).InfoS("Trying to delete real server", "realServer", rsToDelete) 170 rss, err := m.ipvs.GetRealServers(rsToDelete.VirtualServer) 171 if err != nil { 172 return false, err 173 } 174 for _, rs := range rss { 175 if rsToDelete.RealServer.Equal(rs) { 176 // For UDP and SCTP traffic, no graceful termination, we immediately delete the RS 177 // (existing connections will be deleted on the next packet because sysctlExpireNoDestConn=1) 178 // For other protocols, don't delete until all connections have expired) 179 if utilipvs.IsRsGracefulTerminationNeeded(rsToDelete.VirtualServer.Protocol) && rs.ActiveConn+rs.InactiveConn != 0 { 180 klog.V(5).InfoS("Skip deleting real server till all connection have expired", "realServer", rsToDelete, "activeConnection", rs.ActiveConn, "inactiveConnection", rs.InactiveConn) 181 return false, nil 182 } 183 klog.V(5).InfoS("Deleting real server", "realServer", rsToDelete) 184 err := m.ipvs.DeleteRealServer(rsToDelete.VirtualServer, rs) 185 if err != nil { 186 return false, fmt.Errorf("delete destination %q err: %w", rs.String(), err) 187 } 188 return true, nil 189 } 190 } 191 return true, fmt.Errorf("failed to delete rs %q, can't find the real server", rsToDelete.String()) 192 } 193 194 func (m *GracefulTerminationManager) tryDeleteRs() { 195 if !m.rsList.flushList(m.deleteRsFunc) { 196 klog.ErrorS(nil, "Try flush graceful termination list error") 197 } 198 } 199 200 // MoveRSOutofGracefulDeleteList to delete an rs and remove it from the rsList immediately 201 func (m *GracefulTerminationManager) MoveRSOutofGracefulDeleteList(uniqueRS string) error { 202 rsToDelete, find := m.rsList.exist(uniqueRS) 203 if !find || rsToDelete == nil { 204 return fmt.Errorf("failed to find rs: %q", uniqueRS) 205 } 206 err := m.ipvs.DeleteRealServer(rsToDelete.VirtualServer, rsToDelete.RealServer) 207 if err != nil { 208 return err 209 } 210 m.rsList.remove(rsToDelete) 211 return nil 212 } 213 214 // Run start a goroutine to try to delete rs in the graceful delete rsList with an interval 1 minute 215 func (m *GracefulTerminationManager) Run() { 216 go wait.Until(m.tryDeleteRs, rsCheckDeleteInterval, wait.NeverStop) 217 }