github.com/matrixorigin/matrixone@v1.2.0/cmd/mo-service/launch.go (about)

     1  // Copyright 2022 Matrix Origin
     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 main
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  	"time"
    22  
    23  	"github.com/fagongzi/goetty/v2"
    24  	"github.com/matrixorigin/matrixone/pkg/backup"
    25  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    26  	"github.com/matrixorigin/matrixone/pkg/common/stopper"
    27  	"github.com/matrixorigin/matrixone/pkg/logservice"
    28  	"github.com/matrixorigin/matrixone/pkg/logutil"
    29  	logpb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    30  	"go.uber.org/zap"
    31  )
    32  
    33  var (
    34  	cnProxy goetty.Proxy
    35  )
    36  
    37  func startCluster(
    38  	ctx context.Context,
    39  	stopper *stopper.Stopper,
    40  	shutdownC chan struct{},
    41  ) error {
    42  	if *launchFile == "" {
    43  		panic("launch file not set")
    44  	}
    45  
    46  	cfg := &LaunchConfig{}
    47  	if err := parseConfigFromFile(*launchFile, cfg); err != nil {
    48  		return err
    49  	}
    50  
    51  	if cfg.Dynamic.Enable {
    52  		return startDynamicCluster(ctx, cfg, stopper, shutdownC)
    53  	}
    54  
    55  	/*
    56  		When the mo started in local cluster, we save all config files.
    57  		Because we can get all config files conveniently.
    58  	*/
    59  	backup.SaveLaunchConfigPath(backup.LaunchConfig, []string{*launchFile})
    60  	backup.SaveLaunchConfigPath(backup.LogConfig, cfg.LogServiceConfigFiles)
    61  	backup.SaveLaunchConfigPath(backup.DnConfig, cfg.TNServiceConfigsFiles)
    62  	backup.SaveLaunchConfigPath(backup.CnConfig, cfg.CNServiceConfigsFiles)
    63  	if err := startLogServiceCluster(ctx, cfg.LogServiceConfigFiles, stopper, shutdownC); err != nil {
    64  		return err
    65  	}
    66  	if err := startTNServiceCluster(ctx, cfg.TNServiceConfigsFiles, stopper, shutdownC); err != nil {
    67  		return err
    68  	}
    69  	if err := startCNServiceCluster(ctx, cfg.CNServiceConfigsFiles, stopper, shutdownC); err != nil {
    70  		return err
    71  	}
    72  	if *withProxy {
    73  		backup.SaveLaunchConfigPath(backup.ProxyConfig, cfg.ProxyServiceConfigsFiles)
    74  		if err := startProxyServiceCluster(ctx, cfg.ProxyServiceConfigsFiles, stopper, shutdownC); err != nil {
    75  			return err
    76  		}
    77  	}
    78  	if err := startPythonUdfServiceCluster(ctx, cfg.PythonUdfServiceConfigsFiles, stopper, shutdownC); err != nil {
    79  		return err
    80  	}
    81  	return nil
    82  }
    83  
    84  func startLogServiceCluster(
    85  	ctx context.Context,
    86  	files []string,
    87  	stopper *stopper.Stopper,
    88  	shutdownC chan struct{},
    89  ) error {
    90  	if len(files) == 0 {
    91  		return moerr.NewBadConfig(context.Background(), "Log service config not set")
    92  	}
    93  
    94  	var cfg *Config
    95  	for _, file := range files {
    96  		cfg = NewConfig()
    97  		if err := parseConfigFromFile(file, cfg); err != nil {
    98  			return err
    99  		}
   100  		if err := startService(ctx, cfg, stopper, shutdownC); err != nil {
   101  			return err
   102  		}
   103  	}
   104  	return nil
   105  }
   106  
   107  func startTNServiceCluster(
   108  	ctx context.Context,
   109  	files []string,
   110  	stopper *stopper.Stopper,
   111  	shutdownC chan struct{},
   112  ) error {
   113  	if len(files) == 0 {
   114  		return moerr.NewBadConfig(context.Background(), "DN service config not set")
   115  	}
   116  
   117  	for _, file := range files {
   118  		cfg := NewConfig()
   119  		// mo boosting in standalone mode
   120  		cfg.IsStandalone = true
   121  		if err := parseConfigFromFile(file, cfg); err != nil {
   122  			return err
   123  		}
   124  		if err := startService(ctx, cfg, stopper, shutdownC); err != nil {
   125  			return nil
   126  		}
   127  	}
   128  	return nil
   129  }
   130  
   131  func startCNServiceCluster(
   132  	ctx context.Context,
   133  	files []string,
   134  	stopper *stopper.Stopper,
   135  	shutdownC chan struct{},
   136  ) error {
   137  	if len(files) == 0 {
   138  		return moerr.NewBadConfig(context.Background(), "CN service config not set")
   139  	}
   140  
   141  	upstreams := []string{}
   142  
   143  	var cfg *Config
   144  	for _, file := range files {
   145  		cfg = NewConfig()
   146  		if err := parseConfigFromFile(file, cfg); err != nil {
   147  			return err
   148  		}
   149  		upstreams = append(upstreams, fmt.Sprintf("127.0.0.1:%d", cfg.getCNServiceConfig().Frontend.Port))
   150  		if err := startService(ctx, cfg, stopper, shutdownC); err != nil {
   151  			return err
   152  		}
   153  	}
   154  
   155  	if len(upstreams) > 1 {
   156  		// TODO: make configurable for 6001
   157  		cnProxy = goetty.NewProxy("0.0.0.0:6001", logutil.GetGlobalLogger().Named("mysql-proxy"))
   158  		for _, address := range upstreams {
   159  			cnProxy.AddUpStream(address, time.Second*10)
   160  		}
   161  		if err := cnProxy.Start(); err != nil {
   162  			return err
   163  		}
   164  	}
   165  	return nil
   166  }
   167  
   168  func startProxyServiceCluster(
   169  	ctx context.Context,
   170  	files []string,
   171  	stopper *stopper.Stopper,
   172  	shutdownC chan struct{},
   173  ) error {
   174  	if len(files) == 0 {
   175  		return moerr.NewBadConfig(context.Background(), "Proxy service config not set")
   176  	}
   177  
   178  	var cfg *Config
   179  	for _, file := range files {
   180  		cfg = NewConfig()
   181  		if err := parseConfigFromFile(file, cfg); err != nil {
   182  			return err
   183  		}
   184  		if err := startService(ctx, cfg, stopper, shutdownC); err != nil {
   185  			return err
   186  		}
   187  	}
   188  
   189  	return nil
   190  }
   191  
   192  func startPythonUdfServiceCluster(
   193  	ctx context.Context,
   194  	files []string,
   195  	stopper *stopper.Stopper,
   196  	shutdownC chan struct{},
   197  ) error {
   198  	if len(files) == 0 {
   199  		return nil
   200  	}
   201  
   202  	for _, file := range files {
   203  		cfg := NewConfig()
   204  		if err := parseConfigFromFile(file, cfg); err != nil {
   205  			return err
   206  		}
   207  		if err := startService(ctx, cfg, stopper, shutdownC); err != nil {
   208  			return err
   209  		}
   210  	}
   211  	return nil
   212  }
   213  
   214  func waitHAKeeperReady(cfg logservice.HAKeeperClientConfig) (logservice.CNHAKeeperClient, error) {
   215  	// wait hakeeper ready
   216  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*30)
   217  	defer cancel()
   218  	for {
   219  		var err error
   220  		client, err := logservice.NewCNHAKeeperClient(ctx, cfg)
   221  		if moerr.IsMoErrCode(err, moerr.ErrNoHAKeeper) {
   222  			// not ready
   223  			logutil.Info("hakeeper not ready, retry")
   224  			time.Sleep(time.Second)
   225  			continue
   226  		}
   227  		return client, err
   228  	}
   229  }
   230  
   231  func waitHAKeeperRunning(client logservice.CNHAKeeperClient) error {
   232  	ctx, cancel := context.WithTimeout(context.TODO(), time.Minute*2)
   233  	defer cancel()
   234  
   235  	// wait HAKeeper running
   236  	for {
   237  		state, err := client.GetClusterState(ctx)
   238  		if errors.Is(err, context.DeadlineExceeded) {
   239  			return err
   240  		}
   241  		if moerr.IsMoErrCode(err, moerr.ErrNoHAKeeper) ||
   242  			state.State != logpb.HAKeeperRunning {
   243  			// not ready
   244  			logutil.Info("hakeeper not ready, retry")
   245  			time.Sleep(time.Second)
   246  			continue
   247  		}
   248  		return err
   249  	}
   250  }
   251  
   252  func waitAnyShardReady(client logservice.CNHAKeeperClient) error {
   253  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*30)
   254  	defer cancel()
   255  
   256  	// wait shard ready
   257  	for {
   258  		if ok, err := func() (bool, error) {
   259  			details, err := client.GetClusterDetails(ctx)
   260  			if err != nil {
   261  				if errors.Is(err, context.DeadlineExceeded) {
   262  					logutil.Errorf("wait TN ready timeout: %s", err)
   263  					return false, err
   264  				}
   265  				logutil.Errorf("failed to get cluster details %s", err)
   266  				return false, nil
   267  			}
   268  			for _, store := range details.TNStores {
   269  				if len(store.Shards) > 0 {
   270  					return true, nil
   271  				}
   272  			}
   273  			logutil.Info("shard not ready")
   274  			return false, nil
   275  		}(); err != nil {
   276  			return err
   277  		} else if ok {
   278  			logutil.Info("shard ready")
   279  			return nil
   280  		}
   281  		time.Sleep(time.Second)
   282  	}
   283  }
   284  
   285  func waitClusterCondition(
   286  	cfg logservice.HAKeeperClientConfig,
   287  	waitFunc func(logservice.CNHAKeeperClient) error,
   288  ) error {
   289  	client, err := waitHAKeeperReady(cfg)
   290  	if err != nil {
   291  		return err
   292  	}
   293  	if err := waitFunc(client); err != nil {
   294  		return err
   295  	}
   296  	if err := client.Close(); err != nil {
   297  		logutil.Error("close hakeeper client failed", zap.Error(err))
   298  	}
   299  	return nil
   300  }