使用kratos框架从0搭建微服务

使用Kratos从0搭建微服务

1、初始化项目

环境准备

安装相关环境以及工具:
kratos项目初始化

初始化项目

//创建项目
kratos new <Your project name>
//拉取项目依赖
go mod download
//运行项目
kratos run

//输出
INFO msg=config loaded: config.yaml format: yaml # 默认载入 configs/config.yaml 配置文件
INFO msg=[gRPC] server listening on: [::]:9000 # gRPC服务监听 9000 端口
INFO msg=[HTTP] server listening on: [::]:8000 # HTTP服务监听 8000 端口

//测试
curl 'http://127.0.0.1:8000/helloworld/kratos'
//输出
{
  "message": "Hello kratos"
}

2、常用组件与中间件接入

日志(zap)

Installation

go get -u go.uber.org/zap

在kratos中引入zap日志库

// internal/pkg/zap
package zap

import (
	"fmt"
	"os"

	"go.uber.org/zap/zapcore"

	"github.com/go-kratos/kratos/v2/log"
	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
)

var _ log.Logger = (*ZapLogger)(nil)

type ZapLogger struct {
	log  *zap.Logger
	Sync func() error
}

// Log 日志记录器接口实现
func (z *ZapLogger) Log(level log.Level, keyvals ...interface{}) error {
	if len(keyvals) == 0 || len(keyvals)%2 != 0 {
		z.log.Warn(fmt.Sprint("Key Values must appear in pairs: ", keyvals))
		return nil
	}

	var data []zap.Field
	for i := 0; i < len(keyvals); i += 2 {
		data = append(data, zap.Any(fmt.Sprint(keyvals[i]), keyvals[i+1]))
	}
	switch level {
	case log.LevelDebug:
		z.log.Debug("", data...)
	case log.LevelInfo:
		z.log.Info("", data...)
	case log.LevelWarn:
		z.log.Warn("", data...)
	case log.LevelError:
		z.log.Error("", data...)
	case log.LevelFatal:
		z.log.Fatal("", data...)
	}
	return nil
}

// Logger 配置zap日志,将zap日志库引入
func Logger() log.Logger {
	encoder := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "zap",
		CallerKey:      "caller",
		MessageKey:     "msg",
		StacktraceKey:  "stack",
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalLevelEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.FullCallerEncoder,
	}
	return NewZapLogger(
		encoder,
		zap.NewAtomicLevelAt(zapcore.DebugLevel),
		zap.AddStacktrace(
			zap.NewAtomicLevelAt(zapcore.ErrorLevel)),
		zap.AddCaller(),
		zap.AddCallerSkip(2),
		zap.Development(),
	)
}

// NewZapLogger return a zap zap.
func NewZapLogger(encoder zapcore.EncoderConfig, level zap.AtomicLevel, opts ...zap.Option) *ZapLogger {
	//设置日志级别
	level.SetLevel(zap.InfoLevel)

	var core zapcore.Core

	core = zapcore.NewCore(
		zapcore.NewConsoleEncoder(encoder),                      // 编码器配置
		zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout)), // 打印到控制台
		level, // 日志级别
	)
		//可选打印到控制台并输出到文件
	/*	core = zapcore.NewCore(
		zapcore.NewJSONEncoder(encoder), // 编码器配置
		zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(getLogWriter())), // 打印到控制台和文件
		level, // 日志级别
	)*/

	zapLogger := zap.New(core, opts...)
	return &ZapLogger{log: zapLogger, Sync: zapLogger.Sync}
}

// 日志自动切割,采用 lumberjack 实现的
func getLogWriter() zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "tmp/test.log",
		MaxSize:    10,
		MaxBackups: 5,
		MaxAge:     30,
		Compress:   false,
	}
	return zapcore.AddSync(lumberJackLogger)
}

修改main.go

	//日志初始化
	loggers := log.With(zap.Logger(),
		"caller", log.DefaultCaller,
		"service.id", id,
		"service.name", Name,
		"service.version", Version,
		"trace_id", tracing.TraceID(),
		"span_id", tracing.SpanID(),
	)

使用方式

//在internal/server/grpc.go&http.go中引入日志中间件
	logging.Server(logger), //日志中间件

配置(apollo)

获取apollo配置模块,将其下载到本地internal/pkg/apollo
https://github.com/go-kratos/kratos/tree/main/contrib/config/apollo
修改main.go

	//远程配置中心初始化
	c := config.New(
		config.WithSource(
			apollo.NewSource(
				apollo.WithAppID(appId),         //APPID
				apollo.WithCluster(cluster),     //集群环境
				apollo.WithEndpoint(endpoint),   //获取配置地址
				apollo.WithNamespace(namespace), //命名空间,除却properties其他结构配置都需加后缀
				apollo.WithEnableBackup(),
				apollo.WithSecret(secret)), //密钥
		),
	)

链路追踪(jaeger)

在main.go中引入链路追踪

//设置全局链路追踪程序
func setTracerProvider(url string) error {
	// Create the Jaeger exporter
	exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
	if err != nil {
		return err
	}
	//配置链路追踪
	tp := trace.NewTracerProvider(
		// 采样率设置(100%)
		trace.WithSampler(trace.ParentBased(trace.TraceIDRatioBased(1.0))),
		// 采样地址
		trace.WithBatcher(exp),
		// 程序信息设置
		trace.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.DBSystemMySQL,
			semconv.ServiceNameKey.String(bc.Dbs.ProjectName),

			attribute.String("ID", id),
			attribute.String("Env", bc.Dbs.Env),
			attribute.String("Version", bc.Dbs.Version),
		)),
	)
	//注册全局链路追踪
	otel.SetTracerProvider(tp)
	return nil
}

main方法中调用此方法

//链路追踪初始化
	err := setTracerProvider("http//jaeger采集地址")
	if err != nil {
		panic(err)
	}

server中http与grpc引入链路追踪中间件

	tracing.Server(),       //链路追踪中间件

服务注册发现(nacos)

在internal/data初始化nacos客户端

// NewNacosConf 初始化nacos客户端服务
func NewNacosConf(conf *conf.Dbs, logger log.Logger) vo.NacosClientParam {
	sc := []constant.ServerConfig{
		*constant.NewServerConfig(conf.Nacos.Ip, conf.Nacos.Port),
	}
	cc := &constant.ClientConfig{
		NamespaceId:         conf.Nacos.NamespaceId,
		TimeoutMs:           conf.Nacos.TimeoutMs,
		NotLoadCacheAtStart: conf.Nacos.NotLoadCacheAtStart,
		LogDir:              conf.Nacos.LogDir,
		CacheDir:            conf.Nacos.CacheDir,
		LogLevel:            conf.Nacos.LogLevel,
	}

	return vo.NacosClientParam{
		ClientConfig:  cc,
		ServerConfigs: sc,
	}
}

编写发现与注册服务

// NewDiscovery nacos服务发现注入
func NewDiscovery(param vo.NacosClientParam) registry.Discovery {
	client, err := clients.NewNamingClient(param)
	if err != nil {
		panic(err)
	}
	return nacos.New(client)
}

// NewRegistrar 服务注册业务注入
func NewRegistrar(param vo.NacosClientParam) registry.Registrar {
	client, err := clients.NewNamingClient(param)
	if err != nil {
		panic(err)
	}
	return nacos.New(client)
}

记得在wire.NewSet中引入三个方法
修改main.go newApp

//方法引入registry.Registrar参数
//在方法内调用registry.Registrar参数
	kratos.Registrar(r),

orm框架(ent)

参考https://github.com/go-kratos/examples/blob/main/blog/internal/data/data.go

监控(prometheus)

参考https://go-kratos.dev/docs/component/middleware/metrics

3、编写proto文件

参考https://go-kratos.dev/docs/guide/api-protobuf

posted @ 2022-05-23 11:18  悠悠听风  阅读(1202)  评论(0编辑  收藏  举报