metrics.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package node
  14. import (
  15. "sync"
  16. "time"
  17. "k8s.io/kubernetes/pkg/api/unversioned"
  18. "github.com/golang/glog"
  19. "github.com/prometheus/client_golang/prometheus"
  20. )
  21. const (
  22. NodeControllerSubsystem = "node_collector"
  23. ZoneHealthStatisticKey = "zone_health"
  24. ZoneSizeKey = "zone_size"
  25. ZoneNoUnhealthyNodesKey = "unhealty_nodes_in_zone"
  26. EvictionsIn10MinutesKey = "10_minute_evictions"
  27. EvictionsIn1HourKey = "1_hour_evictions"
  28. )
  29. var (
  30. ZoneHealth = prometheus.NewGaugeVec(
  31. prometheus.GaugeOpts{
  32. Subsystem: NodeControllerSubsystem,
  33. Name: ZoneHealthStatisticKey,
  34. Help: "Gauge measuring percentage of healty nodes per zone.",
  35. },
  36. []string{"zone"},
  37. )
  38. ZoneSize = prometheus.NewGaugeVec(
  39. prometheus.GaugeOpts{
  40. Subsystem: NodeControllerSubsystem,
  41. Name: ZoneSizeKey,
  42. Help: "Gauge measuring number of registered Nodes per zones.",
  43. },
  44. []string{"zone"},
  45. )
  46. UnhealthyNodes = prometheus.NewGaugeVec(
  47. prometheus.GaugeOpts{
  48. Subsystem: NodeControllerSubsystem,
  49. Name: ZoneNoUnhealthyNodesKey,
  50. Help: "Gauge measuring number of not Ready Nodes per zones.",
  51. },
  52. []string{"zone"},
  53. )
  54. Evictions10Minutes = prometheus.NewGaugeVec(
  55. prometheus.GaugeOpts{
  56. Subsystem: NodeControllerSubsystem,
  57. Name: EvictionsIn10MinutesKey,
  58. Help: "Gauge measuring number of Node evictions that happened in previous 10 minutes per zone.",
  59. },
  60. []string{"zone"},
  61. )
  62. Evictions1Hour = prometheus.NewGaugeVec(
  63. prometheus.GaugeOpts{
  64. Subsystem: NodeControllerSubsystem,
  65. Name: EvictionsIn1HourKey,
  66. Help: "Gauge measuring number of Node evictions that happened in previous hour per zone.",
  67. },
  68. []string{"zone"},
  69. )
  70. )
  71. var registerMetrics sync.Once
  72. func Register() {
  73. registerMetrics.Do(func() {
  74. prometheus.MustRegister(ZoneHealth)
  75. prometheus.MustRegister(ZoneSize)
  76. prometheus.MustRegister(UnhealthyNodes)
  77. prometheus.MustRegister(Evictions10Minutes)
  78. prometheus.MustRegister(Evictions1Hour)
  79. })
  80. }
  81. type eviction struct {
  82. node string
  83. time unversioned.Time
  84. }
  85. type evictionData struct {
  86. sync.Mutex
  87. nodeEvictionCount map[string]map[string]int
  88. nodeEvictionList []eviction
  89. now func() unversioned.Time
  90. windowSize time.Duration
  91. }
  92. func newEvictionData(windowSize time.Duration) *evictionData {
  93. return &evictionData{
  94. nodeEvictionCount: make(map[string]map[string]int),
  95. nodeEvictionList: make([]eviction, 0),
  96. now: unversioned.Now,
  97. windowSize: windowSize,
  98. }
  99. }
  100. func (e *evictionData) slideWindow() {
  101. e.Lock()
  102. defer e.Unlock()
  103. now := e.now()
  104. firstInside := 0
  105. for _, v := range e.nodeEvictionList {
  106. if v.time.Add(e.windowSize).Before(now.Time) {
  107. firstInside++
  108. zone := ""
  109. for z := range e.nodeEvictionCount {
  110. if _, ok := e.nodeEvictionCount[z][v.node]; ok {
  111. zone = z
  112. break
  113. }
  114. }
  115. if zone == "" {
  116. glog.Warningf("EvictionData corruption - unknown zone for node %v", v.node)
  117. continue
  118. }
  119. if e.nodeEvictionCount[zone][v.node] > 1 {
  120. e.nodeEvictionCount[zone][v.node] = e.nodeEvictionCount[zone][v.node] - 1
  121. } else {
  122. delete(e.nodeEvictionCount[zone], v.node)
  123. }
  124. } else {
  125. break
  126. }
  127. }
  128. e.nodeEvictionList = e.nodeEvictionList[firstInside:]
  129. }
  130. func (e *evictionData) registerEviction(node, zone string) {
  131. e.Lock()
  132. defer e.Unlock()
  133. e.nodeEvictionList = append(e.nodeEvictionList, eviction{node: node, time: e.now()})
  134. if _, ok := e.nodeEvictionCount[zone]; !ok {
  135. e.nodeEvictionCount[zone] = make(map[string]int)
  136. }
  137. if _, ok := e.nodeEvictionCount[zone][node]; !ok {
  138. e.nodeEvictionCount[zone][node] = 1
  139. } else {
  140. e.nodeEvictionCount[zone][node] = e.nodeEvictionCount[zone][node] + 1
  141. }
  142. }
  143. func (e *evictionData) removeEviction(node, zone string) {
  144. e.Lock()
  145. defer e.Unlock()
  146. // TODO: This may be inefficient, but hopefully will be rarely called. Verify that this is true.
  147. for i := len(e.nodeEvictionList) - 1; i >= 0; i-- {
  148. if e.nodeEvictionList[i].node == node {
  149. e.nodeEvictionList = append(e.nodeEvictionList[:i], e.nodeEvictionList[i+1:]...)
  150. break
  151. }
  152. }
  153. if e.nodeEvictionCount[zone][node] > 1 {
  154. e.nodeEvictionCount[zone][node] = e.nodeEvictionCount[zone][node] - 1
  155. } else {
  156. delete(e.nodeEvictionCount[zone], node)
  157. }
  158. }
  159. func (e *evictionData) countEvictions(zone string) int {
  160. e.Lock()
  161. defer e.Unlock()
  162. return len(e.nodeEvictionCount[zone])
  163. }
  164. func (e *evictionData) getZones() []string {
  165. e.Lock()
  166. defer e.Unlock()
  167. zones := make([]string, 0, len(e.nodeEvictionCount))
  168. for k := range e.nodeEvictionCount {
  169. zones = append(zones, k)
  170. }
  171. return zones
  172. }
  173. func (e *evictionData) initZone(zone string) {
  174. e.Lock()
  175. defer e.Unlock()
  176. e.nodeEvictionCount[zone] = make(map[string]int)
  177. }