github.com/XiaoMi/Gaea@v1.2.5/proxy/server/manager.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 server
    16  
    17  import (
    18  	"bytes"
    19  	"crypto/md5"
    20  	"fmt"
    21  	"net/http"
    22  	"sort"
    23  	"strconv"
    24  	"strings"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/XiaoMi/Gaea/core/errors"
    29  	"github.com/XiaoMi/Gaea/log"
    30  	"github.com/XiaoMi/Gaea/log/xlog"
    31  	"github.com/XiaoMi/Gaea/models"
    32  	"github.com/XiaoMi/Gaea/mysql"
    33  	"github.com/XiaoMi/Gaea/parser"
    34  	"github.com/XiaoMi/Gaea/stats"
    35  	"github.com/XiaoMi/Gaea/stats/prometheus"
    36  	"github.com/XiaoMi/Gaea/util"
    37  	"github.com/XiaoMi/Gaea/util/sync2"
    38  )
    39  
    40  // LoadAndCreateManager load namespace config, and create manager
    41  func LoadAndCreateManager(cfg *models.Proxy) (*Manager, error) {
    42  	namespaceConfigs, err := loadAllNamespace(cfg)
    43  	if err != nil {
    44  		log.Warn("init namespace manager failed, %v", err)
    45  		return nil, err
    46  
    47  	}
    48  
    49  	mgr, err := CreateManager(cfg, namespaceConfigs)
    50  	if err != nil {
    51  		log.Warn("create manager error: %v", err)
    52  		return nil, err
    53  	}
    54  	//globalManager = mgr
    55  	return mgr, nil
    56  }
    57  
    58  func loadAllNamespace(cfg *models.Proxy) (map[string]*models.Namespace, error) {
    59  	// get names of all namespace
    60  	root := cfg.CoordinatorRoot
    61  	if cfg.ConfigType == models.ConfigFile {
    62  		root = cfg.FileConfigPath
    63  	}
    64  
    65  	client := models.NewClient(cfg.ConfigType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, root)
    66  	store := models.NewStore(client)
    67  	defer store.Close()
    68  	var err error
    69  	var names []string
    70  	names, err = store.ListNamespace()
    71  	if err != nil {
    72  		log.Warn("list namespace failed, err: %v", err)
    73  		return nil, err
    74  	}
    75  
    76  	// query remote namespace models in worker goroutines
    77  	nameC := make(chan string)
    78  	namespaceC := make(chan *models.Namespace)
    79  	var wg sync.WaitGroup
    80  	for i := 0; i < 10; i++ {
    81  		wg.Add(1)
    82  		go func() {
    83  			client := models.NewClient(cfg.ConfigType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, root)
    84  			store := models.NewStore(client)
    85  			defer store.Close()
    86  			defer wg.Done()
    87  			for name := range nameC {
    88  				namespace, e := store.LoadNamespace(cfg.EncryptKey, name)
    89  				if e != nil {
    90  					log.Warn("load namespace %s failed, err: %v", name, err)
    91  					// assign extent err out of this scope
    92  					err = e
    93  					return
    94  				}
    95  				// verify namespace config
    96  				e = namespace.Verify()
    97  				if e != nil {
    98  					log.Warn("verify namespace %s failed, err: %v", name, e)
    99  					err = e
   100  					return
   101  				}
   102  				namespaceC <- namespace
   103  			}
   104  		}()
   105  	}
   106  
   107  	// dispatch goroutine
   108  	go func() {
   109  		for _, name := range names {
   110  			nameC <- name
   111  		}
   112  		close(nameC)
   113  		wg.Wait()
   114  		close(namespaceC)
   115  	}()
   116  
   117  	// collect all namespaces
   118  	namespaceModels := make(map[string]*models.Namespace, 64)
   119  	for namespace := range namespaceC {
   120  		namespaceModels[namespace.Name] = namespace
   121  	}
   122  	if err != nil {
   123  		log.Warn("get namespace failed, err:%v", err)
   124  		return nil, err
   125  	}
   126  
   127  	return namespaceModels, nil
   128  }
   129  
   130  // Manager contains namespace manager and user manager
   131  type Manager struct {
   132  	reloadPrepared sync2.AtomicBool
   133  	switchIndex    util.BoolIndex
   134  	namespaces     [2]*NamespaceManager
   135  	users          [2]*UserManager
   136  	statistics     *StatisticManager
   137  }
   138  
   139  // NewManager return empty Manager
   140  func NewManager() *Manager {
   141  	return &Manager{}
   142  }
   143  
   144  // CreateManager create manager
   145  func CreateManager(cfg *models.Proxy, namespaceConfigs map[string]*models.Namespace) (*Manager, error) {
   146  	m := NewManager()
   147  
   148  	// init statistics
   149  	statisticManager, err := CreateStatisticManager(cfg, m)
   150  	if err != nil {
   151  		log.Warn("init stats manager failed, %v", err)
   152  		return nil, err
   153  	}
   154  	m.statistics = statisticManager
   155  
   156  	current, _, _ := m.switchIndex.Get()
   157  
   158  	// init namespace
   159  	m.namespaces[current] = CreateNamespaceManager(namespaceConfigs)
   160  
   161  	// init user
   162  	user, err := CreateUserManager(namespaceConfigs)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	m.users[current] = user
   167  
   168  	m.startConnectPoolMetricsTask(cfg.StatsInterval)
   169  	return m, nil
   170  }
   171  
   172  // Close close manager
   173  func (m *Manager) Close() {
   174  	current, _, _ := m.switchIndex.Get()
   175  
   176  	namespaces := m.namespaces[current].namespaces
   177  	for _, ns := range namespaces {
   178  		ns.Close(false)
   179  	}
   180  
   181  	m.statistics.Close()
   182  }
   183  
   184  // ReloadNamespacePrepare prepare commit
   185  func (m *Manager) ReloadNamespacePrepare(namespaceConfig *models.Namespace) error {
   186  	name := namespaceConfig.Name
   187  	current, other, _ := m.switchIndex.Get()
   188  
   189  	// reload namespace prepare
   190  	currentNamespaceManager := m.namespaces[current]
   191  	newNamespaceManager := ShallowCopyNamespaceManager(currentNamespaceManager)
   192  	if err := newNamespaceManager.RebuildNamespace(namespaceConfig); err != nil {
   193  		log.Warn("prepare config of namespace: %s failed, err: %v", name, err)
   194  		return err
   195  	}
   196  	m.namespaces[other] = newNamespaceManager
   197  
   198  	// reload user prepare
   199  	currentUserManager := m.users[current]
   200  	newUserManager := CloneUserManager(currentUserManager)
   201  	newUserManager.RebuildNamespaceUsers(namespaceConfig)
   202  	m.users[other] = newUserManager
   203  	m.reloadPrepared.Set(true)
   204  
   205  	return nil
   206  }
   207  
   208  // ReloadNamespaceCommit commit config
   209  func (m *Manager) ReloadNamespaceCommit(name string) error {
   210  	if !m.reloadPrepared.CompareAndSwap(true, false) {
   211  		err := errors.ErrNamespaceNotPrepared
   212  		log.Warn("commit namespace error, namespace: %s, err: %v", name, err)
   213  		return err
   214  	}
   215  
   216  	current, _, index := m.switchIndex.Get()
   217  
   218  	currentNamespace := m.namespaces[current].GetNamespace(name)
   219  	if currentNamespace != nil {
   220  		go currentNamespace.Close(true)
   221  	}
   222  
   223  	m.switchIndex.Set(!index)
   224  
   225  	return nil
   226  }
   227  
   228  // DeleteNamespace delete namespace
   229  func (m *Manager) DeleteNamespace(name string) error {
   230  	current, other, index := m.switchIndex.Get()
   231  
   232  	// idempotent delete
   233  	currentNamespace := m.namespaces[current].GetNamespace(name)
   234  	if currentNamespace == nil {
   235  		return nil
   236  	}
   237  
   238  	// delete namespace of other
   239  	currentNamespaceManager := m.namespaces[current]
   240  	newNamespaceManager := ShallowCopyNamespaceManager(currentNamespaceManager)
   241  	newNamespaceManager.DeleteNamespace(name)
   242  	m.namespaces[other] = newNamespaceManager
   243  
   244  	// delete users of other
   245  	currentUserManager := m.users[current]
   246  	newUserManager := CloneUserManager(currentUserManager)
   247  	newUserManager.ClearNamespaceUsers(name)
   248  	m.users[other] = newUserManager
   249  
   250  	// switch namespace manager
   251  	m.switchIndex.Set(!index)
   252  
   253  	// delay recycle resources of current
   254  	go currentNamespace.Close(true)
   255  
   256  	return nil
   257  }
   258  
   259  // GetNamespace return specific namespace
   260  func (m *Manager) GetNamespace(name string) *Namespace {
   261  	current, _, _ := m.switchIndex.Get()
   262  	return m.namespaces[current].GetNamespace(name)
   263  }
   264  
   265  // CheckUser check if user in users
   266  func (m *Manager) CheckUser(user string) bool {
   267  	current, _, _ := m.switchIndex.Get()
   268  	return m.users[current].CheckUser(user)
   269  }
   270  
   271  // CheckPassword check if right password with specific user
   272  func (m *Manager) CheckPassword(user string, salt, auth []byte) (bool, string) {
   273  	current, _, _ := m.switchIndex.Get()
   274  	return m.users[current].CheckPassword(user, salt, auth)
   275  }
   276  
   277  // CheckPassword check if right password with specific user
   278  func (m *Manager) CheckSha2Password(user string, salt, auth []byte) (bool, string) {
   279  	current, _, _ := m.switchIndex.Get()
   280  	return m.users[current].CheckSha2Password(user, salt, auth)
   281  }
   282  
   283  // GetStatisticManager return proxy status to record status
   284  func (m *Manager) GetStatisticManager() *StatisticManager {
   285  	return m.statistics
   286  }
   287  
   288  // GetNamespaceByUser return namespace by user
   289  func (m *Manager) GetNamespaceByUser(userName, password string) string {
   290  	current, _, _ := m.switchIndex.Get()
   291  	return m.users[current].GetNamespaceByUser(userName, password)
   292  }
   293  
   294  // ConfigFingerprint return config fingerprint
   295  func (m *Manager) ConfigFingerprint() string {
   296  	current, _, _ := m.switchIndex.Get()
   297  	return m.namespaces[current].ConfigFingerprint()
   298  }
   299  
   300  // RecordSessionSQLMetrics record session SQL metrics, like response time, error
   301  func (m *Manager) RecordSessionSQLMetrics(reqCtx *util.RequestContext, se *SessionExecutor, sql string, startTime time.Time, err error) {
   302  	trimmedSql := strings.ReplaceAll(sql, "\n", " ")
   303  	namespace := se.namespace
   304  	ns := m.GetNamespace(namespace)
   305  	if ns == nil {
   306  		log.Warn("record session SQL metrics error, namespace: %s, sql: %s, err: %s", namespace, trimmedSql, "namespace not found")
   307  		return
   308  	}
   309  
   310  	var operation string
   311  	if stmtType, ok := reqCtx.Get(util.StmtType).(int); ok {
   312  		operation = parser.StmtType(stmtType)
   313  	} else {
   314  		fingerprint := mysql.GetFingerprint(sql)
   315  		operation = mysql.GetFingerprintOperation(fingerprint)
   316  	}
   317  
   318  	// record sql timing
   319  	m.statistics.recordSessionSQLTiming(namespace, operation, startTime)
   320  
   321  	// record slow sql
   322  	duration := time.Since(startTime).Nanoseconds() / int64(time.Millisecond)
   323  	if duration > ns.getSessionSlowSQLTime() || ns.getSessionSlowSQLTime() == 0 {
   324  		log.Warn("session slow SQL, namespace: %s, sql: %s, cost: %d ms", namespace, trimmedSql, duration)
   325  		fingerprint := mysql.GetFingerprint(sql)
   326  		md5 := mysql.GetMd5(fingerprint)
   327  		ns.SetSlowSQLFingerprint(md5, fingerprint)
   328  		m.statistics.recordSessionSlowSQLFingerprint(namespace, md5)
   329  	}
   330  
   331  	// record error sql
   332  	if err != nil {
   333  		log.Warn("session error SQL, namespace: %s, sql: %s, cost: %d ms, err: %v", namespace, trimmedSql, duration, err)
   334  		fingerprint := mysql.GetFingerprint(sql)
   335  		md5 := mysql.GetMd5(fingerprint)
   336  		ns.SetErrorSQLFingerprint(md5, fingerprint)
   337  		m.statistics.recordSessionErrorSQLFingerprint(namespace, operation, md5)
   338  	}
   339  
   340  	if OpenProcessGeneralQueryLog() && ns.openGeneralLog {
   341  		m.statistics.generalLogger.Notice("client: %s, namespace: %s, db: %s, user: %s, cmd: %s, sql: %s, cost: %d ms, succ: %t",
   342  			se.clientAddr, namespace, se.db, se.user, operation, trimmedSql, duration, err == nil)
   343  	}
   344  }
   345  
   346  // RecordBackendSQLMetrics record backend SQL metrics, like response time, error
   347  func (m *Manager) RecordBackendSQLMetrics(reqCtx *util.RequestContext, namespace string, sql, backendAddr string, startTime time.Time, err error) {
   348  	trimmedSql := strings.ReplaceAll(sql, "\n", " ")
   349  	ns := m.GetNamespace(namespace)
   350  	if ns == nil {
   351  		log.Warn("record backend SQL metrics error, namespace: %s, backend addr: %s, sql: %s, err: %s", namespace, backendAddr, trimmedSql, "namespace not found")
   352  		return
   353  	}
   354  
   355  	var operation string
   356  	if stmtType, ok := reqCtx.Get(util.StmtType).(int); ok {
   357  		operation = parser.StmtType(stmtType)
   358  	} else {
   359  		fingerprint := mysql.GetFingerprint(sql)
   360  		operation = mysql.GetFingerprintOperation(fingerprint)
   361  	}
   362  
   363  	// record sql timing
   364  	m.statistics.recordBackendSQLTiming(namespace, operation, startTime)
   365  
   366  	// record slow sql
   367  	duration := time.Since(startTime).Nanoseconds() / int64(time.Millisecond)
   368  	if m.statistics.isBackendSlowSQL(startTime) {
   369  		log.Warn("backend slow SQL, namespace: %s, addr: %s, sql: %s, cost: %d ms", namespace, backendAddr, trimmedSql, duration)
   370  		fingerprint := mysql.GetFingerprint(sql)
   371  		md5 := mysql.GetMd5(fingerprint)
   372  		ns.SetBackendSlowSQLFingerprint(md5, fingerprint)
   373  		m.statistics.recordBackendSlowSQLFingerprint(namespace, md5)
   374  	}
   375  
   376  	// record error sql
   377  	if err != nil {
   378  		log.Warn("backend error SQL, namespace: %s, addr: %s, sql: %s, cost %d ms, err: %v", namespace, backendAddr, trimmedSql, duration, err)
   379  		fingerprint := mysql.GetFingerprint(sql)
   380  		md5 := mysql.GetMd5(fingerprint)
   381  		ns.SetBackendErrorSQLFingerprint(md5, fingerprint)
   382  		m.statistics.recordBackendErrorSQLFingerprint(namespace, operation, md5)
   383  	}
   384  }
   385  
   386  func (m *Manager) startConnectPoolMetricsTask(interval int) {
   387  	if interval <= 0 {
   388  		interval = 10
   389  	}
   390  
   391  	go func() {
   392  		t := time.NewTicker(time.Duration(interval) * time.Second)
   393  		for {
   394  			select {
   395  			case <-m.GetStatisticManager().closeChan:
   396  				return
   397  			case <-t.C:
   398  				current, _, _ := m.switchIndex.Get()
   399  				for nameSpaceName, _ := range m.namespaces[current].namespaces {
   400  					m.recordBackendConnectPoolMetrics(nameSpaceName)
   401  				}
   402  			}
   403  		}
   404  	}()
   405  }
   406  
   407  func (m *Manager) recordBackendConnectPoolMetrics(namespace string) {
   408  	ns := m.GetNamespace(namespace)
   409  	if ns == nil {
   410  		log.Warn("record backend connect pool metrics err, namespace: %s", namespace)
   411  		return
   412  	}
   413  
   414  	for sliceName, slice := range ns.slices {
   415  		m.statistics.recordConnectPoolInuseCount(namespace, sliceName, slice.Master.Addr(), slice.Master.InUse())
   416  		m.statistics.recordConnectPoolIdleCount(namespace, sliceName, slice.Master.Addr(), slice.Master.Available())
   417  		m.statistics.recordConnectPoolWaitCount(namespace, sliceName, slice.Master.Addr(), slice.Master.WaitCount())
   418  		for _, slave := range slice.Slave {
   419  			m.statistics.recordConnectPoolInuseCount(namespace, sliceName, slave.Addr(), slave.InUse())
   420  			m.statistics.recordConnectPoolIdleCount(namespace, sliceName, slave.Addr(), slave.Available())
   421  			m.statistics.recordConnectPoolWaitCount(namespace, sliceName, slave.Addr(), slave.WaitCount())
   422  		}
   423  		for _, statisticSlave := range slice.StatisticSlave {
   424  			m.statistics.recordConnectPoolInuseCount(namespace, sliceName, statisticSlave.Addr(), statisticSlave.InUse())
   425  			m.statistics.recordConnectPoolIdleCount(namespace, sliceName, statisticSlave.Addr(), statisticSlave.Available())
   426  			m.statistics.recordConnectPoolWaitCount(namespace, sliceName, statisticSlave.Addr(), statisticSlave.WaitCount())
   427  		}
   428  	}
   429  }
   430  
   431  // NamespaceManager is the manager that holds all namespaces
   432  type NamespaceManager struct {
   433  	namespaces map[string]*Namespace
   434  }
   435  
   436  // NewNamespaceManager constructor of NamespaceManager
   437  func NewNamespaceManager() *NamespaceManager {
   438  	return &NamespaceManager{
   439  		namespaces: make(map[string]*Namespace, 64),
   440  	}
   441  }
   442  
   443  // CreateNamespaceManager create NamespaceManager
   444  func CreateNamespaceManager(namespaceConfigs map[string]*models.Namespace) *NamespaceManager {
   445  	nsMgr := NewNamespaceManager()
   446  	for _, config := range namespaceConfigs {
   447  		namespace, err := NewNamespace(config)
   448  		if err != nil {
   449  			log.Warn("create namespace %s failed, err: %v", config.Name, err)
   450  			continue
   451  		}
   452  		nsMgr.namespaces[namespace.name] = namespace
   453  	}
   454  	return nsMgr
   455  }
   456  
   457  // ShallowCopyNamespaceManager copy NamespaceManager
   458  func ShallowCopyNamespaceManager(nsMgr *NamespaceManager) *NamespaceManager {
   459  	newNsMgr := NewNamespaceManager()
   460  	for k, v := range nsMgr.namespaces {
   461  		newNsMgr.namespaces[k] = v
   462  	}
   463  	return newNsMgr
   464  }
   465  
   466  // RebuildNamespace rebuild namespace
   467  func (n *NamespaceManager) RebuildNamespace(config *models.Namespace) error {
   468  	namespace, err := NewNamespace(config)
   469  	if err != nil {
   470  		log.Warn("create namespace %s failed, err: %v", config.Name, err)
   471  		return err
   472  	}
   473  	n.namespaces[config.Name] = namespace
   474  	return nil
   475  }
   476  
   477  // DeleteNamespace delete namespace
   478  func (n *NamespaceManager) DeleteNamespace(ns string) {
   479  	delete(n.namespaces, ns)
   480  }
   481  
   482  // GetNamespace get namespace in NamespaceManager
   483  func (n *NamespaceManager) GetNamespace(namespace string) *Namespace {
   484  	return n.namespaces[namespace]
   485  }
   486  
   487  // GetNamespaces return all namespaces in NamespaceManager
   488  func (n *NamespaceManager) GetNamespaces() map[string]*Namespace {
   489  	return n.namespaces
   490  }
   491  
   492  // ConfigFingerprint return config fingerprint
   493  func (n *NamespaceManager) ConfigFingerprint() string {
   494  	sortedKeys := make([]string, 0)
   495  	for k := range n.GetNamespaces() {
   496  		sortedKeys = append(sortedKeys, k)
   497  	}
   498  
   499  	sort.Strings(sortedKeys)
   500  
   501  	h := md5.New()
   502  	for _, k := range sortedKeys {
   503  		h.Write(n.GetNamespace(k).DumpToJSON())
   504  	}
   505  	return fmt.Sprintf("%x", h.Sum(nil))
   506  }
   507  
   508  // UserManager means user for auth
   509  // username+password是全局唯一的, 而username可以对应多个namespace
   510  type UserManager struct {
   511  	users          map[string][]string // key: user name, value: user password, same user may have different password, so array of passwords is needed
   512  	userNamespaces map[string]string   // key: UserName+Password, value: name of namespace
   513  }
   514  
   515  // NewUserManager constructor of UserManager
   516  func NewUserManager() *UserManager {
   517  	return &UserManager{
   518  		users:          make(map[string][]string, 64),
   519  		userNamespaces: make(map[string]string, 64),
   520  	}
   521  }
   522  
   523  // CreateUserManager create UserManager
   524  func CreateUserManager(namespaceConfigs map[string]*models.Namespace) (*UserManager, error) {
   525  	user := NewUserManager()
   526  	for _, ns := range namespaceConfigs {
   527  		user.addNamespaceUsers(ns)
   528  	}
   529  	return user, nil
   530  }
   531  
   532  // CloneUserManager close UserManager
   533  func CloneUserManager(user *UserManager) *UserManager {
   534  	ret := NewUserManager()
   535  	// copy
   536  	for k, v := range user.userNamespaces {
   537  		ret.userNamespaces[k] = v
   538  	}
   539  	for k, v := range user.users {
   540  		users := make([]string, len(v))
   541  		copy(users, v)
   542  		ret.users[k] = users
   543  	}
   544  
   545  	return ret
   546  }
   547  
   548  // RebuildNamespaceUsers rebuild users in namespace
   549  func (u *UserManager) RebuildNamespaceUsers(namespace *models.Namespace) {
   550  	u.ClearNamespaceUsers(namespace.Name)
   551  	u.addNamespaceUsers(namespace)
   552  }
   553  
   554  // ClearNamespaceUsers clear users in namespace
   555  func (u *UserManager) ClearNamespaceUsers(namespace string) {
   556  	for key, ns := range u.userNamespaces {
   557  		if ns == namespace {
   558  			delete(u.userNamespaces, key)
   559  
   560  			// delete user password in users
   561  			username, password := getUserAndPasswordFromKey(key)
   562  			var s []string
   563  			for i := range u.users[username] {
   564  				if u.users[username][i] == password {
   565  					s = append(u.users[username][:i], u.users[username][i+1:]...)
   566  				}
   567  			}
   568  			u.users[username] = s
   569  		}
   570  	}
   571  }
   572  
   573  func (u *UserManager) addNamespaceUsers(namespace *models.Namespace) {
   574  	for _, user := range namespace.Users {
   575  		key := getUserKey(user.UserName, user.Password)
   576  		u.userNamespaces[key] = namespace.Name
   577  		u.users[user.UserName] = append(u.users[user.UserName], user.Password)
   578  	}
   579  }
   580  
   581  // CheckUser check if user in users
   582  func (u *UserManager) CheckUser(user string) bool {
   583  	if _, ok := u.users[user]; ok {
   584  		return true
   585  	}
   586  	return false
   587  }
   588  
   589  // CheckPassword check if right password with specific user
   590  func (u *UserManager) CheckPassword(user string, salt, auth []byte) (bool, string) {
   591  	for _, password := range u.users[user] {
   592  		checkAuth := mysql.CalcPassword(salt, []byte(password))
   593  		if bytes.Equal(auth, checkAuth) {
   594  			return true, password
   595  		}
   596  	}
   597  	return false, ""
   598  }
   599  
   600  // CheckPassword check if right password with specific user
   601  func (u *UserManager) CheckSha2Password(user string, salt, auth []byte) (bool, string) {
   602  	for _, password := range u.users[user] {
   603  		checkAuth := mysql.CalcCachingSha2Password(salt, password)
   604  		if bytes.Equal(auth, checkAuth) {
   605  			return true, password
   606  		}
   607  	}
   608  	return false, ""
   609  }
   610  
   611  // GetNamespaceByUser return namespace by user
   612  func (u *UserManager) GetNamespaceByUser(userName, password string) string {
   613  	key := getUserKey(userName, password)
   614  	if name, ok := u.userNamespaces[key]; ok {
   615  		return name
   616  	}
   617  	return ""
   618  }
   619  
   620  func getUserKey(username, password string) string {
   621  	return username + ":" + password
   622  }
   623  
   624  func getUserAndPasswordFromKey(key string) (username string, password string) {
   625  	strs := strings.Split(key, ":")
   626  	return strs[0], strs[1]
   627  }
   628  
   629  const (
   630  	statsLabelCluster       = "Cluster"
   631  	statsLabelOperation     = "Operation"
   632  	statsLabelNamespace     = "Namespace"
   633  	statsLabelFingerprint   = "Fingerprint"
   634  	statsLabelFlowDirection = "Flowdirection"
   635  	statsLabelSlice         = "Slice"
   636  	statsLabelIPAddr        = "IPAddr"
   637  )
   638  
   639  // StatisticManager statistics manager
   640  type StatisticManager struct {
   641  	manager     *Manager
   642  	clusterName string
   643  
   644  	statsType     string // 监控后端类型
   645  	handlers      map[string]http.Handler
   646  	generalLogger log.Logger
   647  
   648  	sqlTimings                *stats.MultiTimings            // SQL耗时统计
   649  	sqlFingerprintSlowCounts  *stats.CountersWithMultiLabels // 慢SQL指纹数量统计
   650  	sqlErrorCounts            *stats.CountersWithMultiLabels // SQL错误数统计
   651  	sqlFingerprintErrorCounts *stats.CountersWithMultiLabels // SQL指纹错误数统计
   652  	sqlForbidenCounts         *stats.CountersWithMultiLabels // SQL黑名单请求统计
   653  	flowCounts                *stats.CountersWithMultiLabels // 业务流量统计
   654  	sessionCounts             *stats.GaugesWithMultiLabels   // 前端会话数统计
   655  
   656  	backendSQLTimings                *stats.MultiTimings            // 后端SQL耗时统计
   657  	backendSQLFingerprintSlowCounts  *stats.CountersWithMultiLabels // 后端慢SQL指纹数量统计
   658  	backendSQLErrorCounts            *stats.CountersWithMultiLabels // 后端SQL错误数统计
   659  	backendSQLFingerprintErrorCounts *stats.CountersWithMultiLabels // 后端SQL指纹错误数统计
   660  	backendConnectPoolIdleCounts     *stats.GaugesWithMultiLabels   //后端空闲连接数统计
   661  	backendConnectPoolInUseCounts    *stats.GaugesWithMultiLabels   //后端正在使用连接数统计
   662  	backendConnectPoolWaitCounts     *stats.GaugesWithMultiLabels   //后端等待队列统计
   663  
   664  	slowSQLTime int64
   665  	closeChan   chan bool
   666  }
   667  
   668  // NewStatisticManager return empty StatisticManager
   669  func NewStatisticManager() *StatisticManager {
   670  	return &StatisticManager{}
   671  }
   672  
   673  // CreateStatisticManager create StatisticManager
   674  func CreateStatisticManager(cfg *models.Proxy, manager *Manager) (*StatisticManager, error) {
   675  	mgr := NewStatisticManager()
   676  	mgr.manager = manager
   677  	mgr.clusterName = cfg.Cluster
   678  
   679  	var err error
   680  	if err = mgr.Init(cfg); err != nil {
   681  		return nil, err
   682  	}
   683  	if mgr.generalLogger, err = initGeneralLogger(cfg); err != nil {
   684  		return nil, err
   685  	}
   686  	return mgr, nil
   687  }
   688  
   689  type proxyStatsConfig struct {
   690  	Service      string
   691  	StatsEnabled bool
   692  }
   693  
   694  func initGeneralLogger(cfg *models.Proxy) (log.Logger, error) {
   695  	c := make(map[string]string, 5)
   696  	c["path"] = cfg.LogPath
   697  	c["filename"] = cfg.LogFileName + "_sql"
   698  	c["level"] = cfg.LogLevel
   699  	c["service"] = cfg.Service
   700  	c["runtime"] = "false"
   701  	return xlog.CreateLogManager(cfg.LogOutput, c)
   702  }
   703  
   704  func parseProxyStatsConfig(cfg *models.Proxy) (*proxyStatsConfig, error) {
   705  	enabled, err := strconv.ParseBool(cfg.StatsEnabled)
   706  	if err != nil {
   707  		return nil, err
   708  	}
   709  
   710  	statsConfig := &proxyStatsConfig{
   711  		Service:      cfg.Service,
   712  		StatsEnabled: enabled,
   713  	}
   714  	return statsConfig, nil
   715  }
   716  
   717  // Init init StatisticManager
   718  func (s *StatisticManager) Init(cfg *models.Proxy) error {
   719  	s.closeChan = make(chan bool, 0)
   720  	s.handlers = make(map[string]http.Handler)
   721  	s.slowSQLTime = cfg.SlowSQLTime
   722  	statsCfg, err := parseProxyStatsConfig(cfg)
   723  	if err != nil {
   724  		return err
   725  	}
   726  
   727  	if err := s.initBackend(statsCfg); err != nil {
   728  		return err
   729  	}
   730  
   731  	s.sqlTimings = stats.NewMultiTimings("SqlTimings",
   732  		"gaea proxy sql sqlTimings", []string{statsLabelCluster, statsLabelNamespace, statsLabelOperation})
   733  	s.sqlFingerprintSlowCounts = stats.NewCountersWithMultiLabels("SqlFingerprintSlowCounts",
   734  		"gaea proxy sql fingerprint slow counts", []string{statsLabelCluster, statsLabelNamespace, statsLabelFingerprint})
   735  	s.sqlErrorCounts = stats.NewCountersWithMultiLabels("SqlErrorCounts",
   736  		"gaea proxy sql error counts per error type", []string{statsLabelCluster, statsLabelNamespace, statsLabelOperation})
   737  	s.sqlFingerprintErrorCounts = stats.NewCountersWithMultiLabels("SqlFingerprintErrorCounts",
   738  		"gaea proxy sql fingerprint error counts", []string{statsLabelCluster, statsLabelNamespace, statsLabelFingerprint})
   739  	s.sqlForbidenCounts = stats.NewCountersWithMultiLabels("SqlForbiddenCounts",
   740  		"gaea proxy sql error counts per error type", []string{statsLabelCluster, statsLabelNamespace, statsLabelFingerprint})
   741  	s.flowCounts = stats.NewCountersWithMultiLabels("FlowCounts",
   742  		"gaea proxy flow counts", []string{statsLabelCluster, statsLabelNamespace, statsLabelFlowDirection})
   743  	s.sessionCounts = stats.NewGaugesWithMultiLabels("SessionCounts",
   744  		"gaea proxy session counts", []string{statsLabelCluster, statsLabelNamespace})
   745  
   746  	s.backendSQLTimings = stats.NewMultiTimings("BackendSqlTimings",
   747  		"gaea proxy backend sql sqlTimings", []string{statsLabelCluster, statsLabelNamespace, statsLabelOperation})
   748  	s.backendSQLFingerprintSlowCounts = stats.NewCountersWithMultiLabels("BackendSqlFingerprintSlowCounts",
   749  		"gaea proxy backend sql fingerprint slow counts", []string{statsLabelCluster, statsLabelNamespace, statsLabelFingerprint})
   750  	s.backendSQLErrorCounts = stats.NewCountersWithMultiLabels("BackendSqlErrorCounts",
   751  		"gaea proxy backend sql error counts per error type", []string{statsLabelCluster, statsLabelNamespace, statsLabelOperation})
   752  	s.backendSQLFingerprintErrorCounts = stats.NewCountersWithMultiLabels("BackendSqlFingerprintErrorCounts",
   753  		"gaea proxy backend sql fingerprint error counts", []string{statsLabelCluster, statsLabelNamespace, statsLabelFingerprint})
   754  	s.backendConnectPoolIdleCounts = stats.NewGaugesWithMultiLabels("backendConnectPoolIdleCounts",
   755  		"gaea proxy backend idle connect counts", []string{statsLabelCluster, statsLabelNamespace, statsLabelSlice, statsLabelIPAddr})
   756  	s.backendConnectPoolInUseCounts = stats.NewGaugesWithMultiLabels("backendConnectPoolInUseCounts",
   757  		"gaea proxy backend in-use connect counts", []string{statsLabelCluster, statsLabelNamespace, statsLabelSlice, statsLabelIPAddr})
   758  	s.backendConnectPoolWaitCounts = stats.NewGaugesWithMultiLabels("backendConnectPoolWaitCounts",
   759  		"gaea proxy backend wait connect counts", []string{statsLabelCluster, statsLabelNamespace, statsLabelSlice, statsLabelIPAddr})
   760  
   761  	s.startClearTask()
   762  	return nil
   763  }
   764  
   765  // Close close proxy stats
   766  func (s *StatisticManager) Close() {
   767  	close(s.closeChan)
   768  }
   769  
   770  // GetHandlers return specific handler of stats
   771  func (s *StatisticManager) GetHandlers() map[string]http.Handler {
   772  	return s.handlers
   773  }
   774  
   775  func (s *StatisticManager) initBackend(cfg *proxyStatsConfig) error {
   776  	prometheus.Init(cfg.Service)
   777  	s.handlers = prometheus.GetHandlers()
   778  	return nil
   779  }
   780  
   781  // clear data to prevent
   782  func (s *StatisticManager) startClearTask() {
   783  	go func() {
   784  		t := time.NewTicker(time.Hour)
   785  		for {
   786  			select {
   787  			case <-s.closeChan:
   788  				return
   789  			case <-t.C:
   790  				s.clearLargeCounters()
   791  			}
   792  		}
   793  	}()
   794  }
   795  
   796  func (s *StatisticManager) clearLargeCounters() {
   797  	s.sqlErrorCounts.ResetAll()
   798  	s.sqlFingerprintSlowCounts.ResetAll()
   799  	s.sqlFingerprintErrorCounts.ResetAll()
   800  
   801  	s.backendSQLErrorCounts.ResetAll()
   802  	s.backendSQLFingerprintSlowCounts.ResetAll()
   803  	s.backendSQLFingerprintErrorCounts.ResetAll()
   804  }
   805  
   806  func (s *StatisticManager) recordSessionSlowSQLFingerprint(namespace string, md5 string) {
   807  	fingerprintStatsKey := []string{s.clusterName, namespace, md5}
   808  	s.sqlFingerprintSlowCounts.Add(fingerprintStatsKey, 1)
   809  }
   810  
   811  func (s *StatisticManager) recordSessionErrorSQLFingerprint(namespace string, operation string, md5 string) {
   812  	fingerprintStatsKey := []string{s.clusterName, namespace, md5}
   813  	operationStatsKey := []string{s.clusterName, namespace, operation}
   814  	s.sqlErrorCounts.Add(operationStatsKey, 1)
   815  	s.sqlFingerprintErrorCounts.Add(fingerprintStatsKey, 1)
   816  }
   817  
   818  func (s *StatisticManager) recordSessionSQLTiming(namespace string, operation string, startTime time.Time) {
   819  	operationStatsKey := []string{s.clusterName, namespace, operation}
   820  	s.sqlTimings.Record(operationStatsKey, startTime)
   821  }
   822  
   823  // millisecond duration
   824  func (s *StatisticManager) isBackendSlowSQL(startTime time.Time) bool {
   825  	duration := time.Since(startTime).Nanoseconds() / int64(time.Millisecond)
   826  	return duration > s.slowSQLTime || s.slowSQLTime == 0
   827  }
   828  
   829  func (s *StatisticManager) recordBackendSlowSQLFingerprint(namespace string, md5 string) {
   830  	fingerprintStatsKey := []string{s.clusterName, namespace, md5}
   831  	s.backendSQLFingerprintSlowCounts.Add(fingerprintStatsKey, 1)
   832  }
   833  
   834  func (s *StatisticManager) recordBackendErrorSQLFingerprint(namespace string, operation string, md5 string) {
   835  	fingerprintStatsKey := []string{s.clusterName, namespace, md5}
   836  	operationStatsKey := []string{s.clusterName, namespace, operation}
   837  	s.backendSQLErrorCounts.Add(operationStatsKey, 1)
   838  	s.backendSQLFingerprintErrorCounts.Add(fingerprintStatsKey, 1)
   839  }
   840  
   841  func (s *StatisticManager) recordBackendSQLTiming(namespace string, operation string, startTime time.Time) {
   842  	operationStatsKey := []string{s.clusterName, namespace, operation}
   843  	s.backendSQLTimings.Record(operationStatsKey, startTime)
   844  }
   845  
   846  // RecordSQLForbidden record forbidden sql
   847  func (s *StatisticManager) RecordSQLForbidden(fingerprint, namespace string) {
   848  	md5 := mysql.GetMd5(fingerprint)
   849  	s.sqlForbidenCounts.Add([]string{s.clusterName, namespace, md5}, 1)
   850  }
   851  
   852  // IncrSessionCount incr session count
   853  func (s *StatisticManager) IncrSessionCount(namespace string) {
   854  	statsKey := []string{s.clusterName, namespace}
   855  	s.sessionCounts.Add(statsKey, 1)
   856  }
   857  
   858  // DescSessionCount decr session count
   859  func (s *StatisticManager) DescSessionCount(namespace string) {
   860  	statsKey := []string{s.clusterName, namespace}
   861  	s.sessionCounts.Add(statsKey, -1)
   862  }
   863  
   864  // AddReadFlowCount add read flow count
   865  func (s *StatisticManager) AddReadFlowCount(namespace string, byteCount int) {
   866  	statsKey := []string{s.clusterName, namespace, "read"}
   867  	s.flowCounts.Add(statsKey, int64(byteCount))
   868  }
   869  
   870  // AddWriteFlowCount add write flow count
   871  func (s *StatisticManager) AddWriteFlowCount(namespace string, byteCount int) {
   872  	statsKey := []string{s.clusterName, namespace, "write"}
   873  	s.flowCounts.Add(statsKey, int64(byteCount))
   874  }
   875  
   876  //record idle connect count
   877  func (s *StatisticManager) recordConnectPoolIdleCount(namespace string, slice string, addr string, count int64) {
   878  	statsKey := []string{s.clusterName, namespace, slice, addr}
   879  	s.backendConnectPoolIdleCounts.Set(statsKey, count)
   880  }
   881  
   882  //record in-use connect count
   883  func (s *StatisticManager) recordConnectPoolInuseCount(namespace string, slice string, addr string, count int64) {
   884  	statsKey := []string{s.clusterName, namespace, slice, addr}
   885  	s.backendConnectPoolInUseCounts.Set(statsKey, count)
   886  }
   887  
   888  //record wait queue length
   889  func (s *StatisticManager) recordConnectPoolWaitCount(namespace string, slice string, addr string, count int64) {
   890  	statsKey := []string{s.clusterName, namespace, slice, addr}
   891  	s.backendConnectPoolWaitCounts.Set(statsKey, count)
   892  }