github.com/XiaoMi/Gaea@v1.2.5/cc/service/service.go (about) 1 // Copyright 2019 The Gaea Authors. All Rights Reserved. 2 // 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package service 16 17 import ( 18 "fmt" 19 "sync" 20 21 "github.com/XiaoMi/Gaea/cc/proxy" 22 "github.com/XiaoMi/Gaea/log" 23 "github.com/XiaoMi/Gaea/models" 24 ) 25 26 const ( 27 PREPARE_RETRY_TIMES = 3 28 COMMIT_RETRY_TIMES = 1 29 ) 30 31 func getCoordinatorRoot(cluster string) string { 32 if cluster != "" { 33 return "/" + cluster 34 } 35 return cluster 36 } 37 38 // ListNamespace return names of all namespace 39 func ListNamespace(cfg *models.CCConfig, cluster string) ([]string, error) { 40 client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster)) 41 mConn := models.NewStore(client) 42 defer mConn.Close() 43 return mConn.ListNamespace() 44 } 45 46 // QueryNamespace return information of namespace specified by names 47 func QueryNamespace(names []string, cfg *models.CCConfig, cluster string) (data []*models.Namespace, err error) { 48 client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster)) 49 mConn := models.NewStore(client) 50 defer mConn.Close() 51 for _, v := range names { 52 namespace, err := mConn.LoadNamespace(cfg.EncryptKey, v) 53 if err != nil { 54 log.Warn("load namespace %s failed, %v", v, err.Error()) 55 return nil, err 56 } 57 if namespace == nil { 58 log.Warn("namespace %s not found", v) 59 return data, nil 60 } 61 data = append(data, namespace) 62 } 63 64 return data, nil 65 } 66 67 // ModifyNamespace create or modify namespace 68 func ModifyNamespace(namespace *models.Namespace, cfg *models.CCConfig, cluster string) (err error) { 69 if err = namespace.Verify(); err != nil { 70 return fmt.Errorf("verify namespace error: %v", err) 71 } 72 73 // create/modify will save encrypted data default 74 if err = namespace.Encrypt(cfg.EncryptKey); err != nil { 75 return fmt.Errorf("encrypt namespace error: %v", err) 76 } 77 78 // sink namespace 79 client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster)) 80 storeConn := models.NewStore(client) 81 defer storeConn.Close() 82 83 if err := storeConn.UpdateNamespace(namespace); err != nil { 84 log.Warn("update namespace failed, %s", string(namespace.Encode())) 85 return err 86 } 87 88 // proxies ready to reload config 89 proxies, err := storeConn.ListProxyMonitorMetrics() 90 if err != nil { 91 log.Warn("list proxies failed, %v", err) 92 return err 93 } 94 95 wg := sync.WaitGroup{} 96 // prepare phase 97 for _, v := range proxies { 98 wg.Add(1) 99 go func(v *models.ProxyMonitorMetric) { 100 for i := 0; i < PREPARE_RETRY_TIMES; i++ { 101 if err = proxy.PrepareConfig(v.IP+":"+v.AdminPort, namespace.Name, cfg); err == nil { 102 break 103 } 104 log.Warn("namespace %s, proxy prepare retry %d", namespace.Name, i) 105 } 106 if err != nil { 107 return 108 } 109 wg.Done() 110 }(v) 111 } 112 wg.Wait() 113 114 // commit phase 115 for _, v := range proxies { 116 wg.Add(1) 117 go func(v *models.ProxyMonitorMetric) { 118 for i := 0; i < COMMIT_RETRY_TIMES; i++ { 119 if err := proxy.CommitConfig(v.IP+":"+v.AdminPort, namespace.Name, cfg); err == nil { 120 break 121 } 122 log.Warn("namespace %s, proxy prepare retry %d", namespace.Name, i) 123 } 124 if err != nil { 125 return 126 } 127 wg.Done() 128 }(v) 129 } 130 131 return nil 132 } 133 134 // DelNamespace delete namespace 135 func DelNamespace(name string, cfg *models.CCConfig, cluster string) error { 136 client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster)) 137 mConn := models.NewStore(client) 138 defer mConn.Close() 139 140 if err := mConn.DelNamespace(name); err != nil { 141 log.Warn("delete namespace %s failed, %s", name, err.Error()) 142 return err 143 } 144 145 proxies, err := mConn.ListProxyMonitorMetrics() 146 if err != nil { 147 log.Warn("list proxy failed, %s", err.Error()) 148 return err 149 } 150 151 for _, v := range proxies { 152 err := proxy.DelNamespace(v.IP+":"+v.AdminPort, name, cfg) 153 if err != nil { 154 log.Warn("delete namespace %s in proxy %s failed, err: %s", name, v.IP, err.Error()) 155 return err 156 } 157 } 158 159 return nil 160 } 161 162 // SQLFingerprint return sql fingerprints of all proxy 163 func SQLFingerprint(name string, cfg *models.CCConfig, cluster string) (slowSQLs, errSQLs map[string]string, err error) { 164 slowSQLs = make(map[string]string, 16) 165 errSQLs = make(map[string]string, 16) 166 // list proxy 167 client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster)) 168 mConn := models.NewStore(client) 169 defer mConn.Close() 170 proxies, err := mConn.ListProxyMonitorMetrics() 171 if err != nil { 172 log.Warn("list proxy failed, %v", err) 173 return nil, nil, err 174 } 175 wg := new(sync.WaitGroup) 176 respC := make(chan *proxy.SQLFingerprint, len(proxies)) 177 // query sql fingerprints concurrently 178 for _, p := range proxies { 179 wg.Add(1) 180 host := p.IP + ":" + p.AdminPort 181 go func(host, name string) { 182 defer wg.Done() 183 r, err := proxy.QueryNamespaceSQLFingerprint(host, name, cfg) 184 if err != nil { 185 log.Warn("query namespace sql fingerprint failed ,%v", err) 186 } 187 respC <- r 188 }(host, name) 189 } 190 wg.Wait() 191 close(respC) 192 193 for r := range respC { 194 if r == nil { 195 continue 196 } 197 for k, v := range r.SlowSQL { 198 slowSQLs[k] = v 199 } 200 for k, v := range r.ErrorSQL { 201 errSQLs[k] = v 202 } 203 } 204 205 return 206 } 207 208 // ProxyConfigFingerprint return fingerprints of all proxy 209 func ProxyConfigFingerprint(cfg *models.CCConfig, cluster string) (r map[string]string, err error) { 210 // list proxy 211 client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster)) 212 mConn := models.NewStore(client) 213 defer mConn.Close() 214 proxies, err := mConn.ListProxyMonitorMetrics() 215 if err != nil { 216 log.Warn("list proxy failed, %v", err) 217 return nil, err 218 } 219 wg := new(sync.WaitGroup) 220 r = make(map[string]string, len(proxies)) 221 respC := make(chan map[string]string, len(proxies)) 222 for _, p := range proxies { 223 host := p.IP + ":" + p.AdminPort 224 wg.Add(1) 225 go func(host string) { 226 defer wg.Done() 227 md5, err := proxy.QueryProxyConfigFingerprint(host, cfg) 228 if err != nil { 229 log.Warn("query config fingerprint of proxy failed, %s %v", host, err) 230 } 231 m := make(map[string]string, 1) 232 m[host] = md5 233 respC <- m 234 }(host) 235 } 236 wg.Wait() 237 close(respC) 238 for resp := range respC { 239 if resp == nil { 240 continue 241 } 242 for k, v := range resp { 243 r[k] = v 244 } 245 } 246 return 247 }