GoLang 微服务学习笔记

https://www.bilibili.com/video/BV1Gg4y1u77D/?spm_id_from=333.337.search-card.all.click\&vd_source=707ec8983cc32e6e065d5496a7f79ee6

目录








第1讲:为什么说云原生重构了互联网产品开发模式?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=2





第2讲:云原生基础架构的组成以及云原生应用的特征

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=3











第3讲:微服务架构是如何演进的?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=4

  • 通过垂直分层结构,可以让逻辑请求,也可以为不同层提供不同性能的硬件支持,比如用户界面层需要分发带宽,而业务逻辑层需要算力
  • SOA有服务提供者与服务使用者




第4讲:DDD 领域场景分析的战略模式

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=5









第5讲:为什么说 Service Meh 是下一代微服务架构?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.player.switch\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=6

  • 微服务拆分是复杂的,如下图拆分的微服务











第6讲: Go 语言开发快速回顾:语法、数据结构和流程控制

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=7


  • go 命令


  • go的指针应用

  • go的struct类型,也是go的类写法
  • 在struct定义的变量,大写是包外可以访问,小写是包外部能访问
  • go数组使用,声明时,需要固定数组大小
  • go的切片slice,即动态数组


  • appand切片
  • 也可以通过不指定数组大小,来声明切片
  • go的map类型


  • map的获取
  • 判断某键是否存在map中
  • go 的for循环语句


  • go 中的switch不需要写case
  • go defer延迟执行函数,defer是先进后出(解析是历届解析)



第7讲: 如何使用 Go 更好地开发并发程序?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=8









  • 以上总共生成了5个一组,共3组,15个(0-14)的生产;再收到queue的消息后,消费也会是15个,顺序是不确定的
go 复制代码
package main

import (
	"fmt"
	"time"
)

func send(ch chan int, begin int) {
	for i := begin; i < begin+10; i++ {
		ch <- i
	}
}

func receive(ch <-chan int) {
	val := <-ch
	fmt.Println("receive:", val)
}

func main() {
	ch1 := make(chan int)
	ch2 := make(chan int)

	go send(ch1, 0)
	go receive(ch2)

	time.Sleep(time.Second)

	for {
		select {
		case val := <-ch1:
			fmt.Println("get value from ch1:", val)
		case ch2 <- 2:
			fmt.Println("send value by ch2")
		case <-time.After(time.Second):
			fmt.Println("timeout")
			return
		}
	}
}


go 复制代码
package main

import (
	"context"
	"fmt"
	"time"
)

const DB_ADDRESS = "db_address"
const CALCULATE_VALUE = "calculate_value"

func readDB(ctx context.Context, cost time.Duration) {
	fmt.Println("db address is", ctx.Value(DB_ADDRESS))
	select {
	case <-time.After(cost):
		fmt.Println("read data from db")
	case <-ctx.Done():
		fmt.Println(ctx.Err())
	}
}

func calculate(ctx context.Context, cost time.Duration) {
	fmt.Println("calculate value is", ctx.Value(CALCULATE_VALUE))
	select {
	case <-time.After(cost):
		fmt.Println("calculate finish")
	case <-ctx.Done():
		fmt.Println(ctx.Err())
	}
}

func main() {
	ctx := context.Background()

	ctx = context.WithValue(ctx, DB_ADDRESS, "localhost:10086")
	ctx = context.WithValue(ctx, CALCULATE_VALUE, 1234)

	ctx, cancel := context.WithTimeout(ctx, time.Second*2) //6秒则输出finish
	defer cancel()

	go readDB(ctx, time.Second*4)
	go calculate(ctx, time.Second*4)

	time.Sleep(time.Second * 5)
}

第8讲: 如何基于 Go-kit 开发 Web 应用:从接口层到业务层再到数据层

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=8

  • 配置代理

  • 安装插件






  • 项目需要引入的包

redis的安装:

https://github.com/microsoftarchive/redis/releases (微软的Redis版)

https://gitee.com/qishibo/AnotherRedisDesktopManager/releases/tag/v1.7.1(Redis工具)

cmd输入,redis-server.exe --service-install redis.windows-service.conf 完成服务添加

cmd输入,redis-cli.exe ,输入keys * 查看缓存情况,也可以用redis工具查看



go 复制代码
package main

import (
	"context"
	"flag"
	"fmt"
	"github.com/longjoy/micro-go-course/section08/user/dao"
	"github.com/longjoy/micro-go-course/section08/user/endpoint"
	"github.com/longjoy/micro-go-course/section08/user/redis"
	"github.com/longjoy/micro-go-course/section08/user/service"
	"github.com/longjoy/micro-go-course/section08/user/transport"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"syscall"
)

func main() {

	//* 使用了flag定义了带有更多信息的变量
	var (
		// 服务地址和服务名
		servicePort = flag.Int("service.port", 10086, "service port")
	)

	flag.Parse()

	//* 空的 Context,用作 Context 树的根节点,是其他 Context 的父级,一般用于初始化 Context 链
	ctx := context.Background()
	errChan := make(chan error)

	//* 使用dao包,用于数据库操作,打开数据库,初始化db (Gorm)
	err := dao.InitMysql("127.0.0.1", "3306", "root", "***", "user")
	if err != nil {
		log.Fatal(err)
	}
	
	//* 打开redis
	err = redis.InitRedis("127.0.0.1", "6379", "")
	if err != nil {
		log.Fatal(err)
	}

	//* 把UserDAOImpl对象(包含SelectByEmail与Save)给到service,初始化userService,见代码1
	userService := service.MakeUserServiceImpl(&dao.UserDAOImpl{})

	//* UserEndpoints是2个endpoint.Endpoint类型的函数,如下
	//* type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
	//* 并make初始化,见代码2
	userEndpoints := &endpoint.UserEndpoints{
		endpoint.MakeRegisterEndpoint(userService),
		endpoint.MakeLoginEndpoint(userService),
	}

	//* 把路由封装起来,之后启动服务器,见代码3
	r := transport.MakeHttpHandler(ctx, userEndpoints)

	//* 首先,定义了一个 servicePort 并创建了一个错误通道 errChan。
	//* 然后,使用 http.NewServeMux() 创建一个路由处理程序 r,并为根路由添加了一个简单的处理函数。
	//* 启动了两个 goroutine:一个用于启动 HTTP 服务器,另一个用于监听系统信号。
	//* 最后,从 errChan 接收错误信息,当按下 Ctrl+C 时,会接收到 SIGINT 信号,程序打印错误信息并退出。
	go func() {
		errChan <- http.ListenAndServe(":"+strconv.Itoa(*servicePort), r)
	}()

	go func() {
		// 监控系统信号,等待 ctrl + c 系统信号通知服务关闭
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		errChan <- fmt.Errorf("%s", <-c)
	}()

	error := <-errChan
	log.Println(error)

}
  • 代码1:MakeUserServiceImpl操作
go 复制代码
//* 定义了UserService接口
type UserService interface {
	// 登录接口
	Login(ctx context.Context, email, password string) (*UserInfoDTO, error)
	// 注册接口
	Register(ctx context.Context, vo *RegisterUserVO) (*UserInfoDTO, error)
}

//* UserServiceImpl为接口的一个实现,并有一个userDAO的对象值
type UserServiceImpl struct {
	userDAO dao.UserDAO
}

func MakeUserServiceImpl(userDAO dao.UserDAO) UserService {
	return &UserServiceImpl{
		userDAO: userDAO,
	}
}

//* 以下函数实现了userService接口的一个具体实现UserServiceImpl
//* 通过userService取到userDAO,符合依赖倒置原则
func (userService *UserServiceImpl) Login(ctx context.Context, email, password string) (*UserInfoDTO, error){
	user, err := userService.userDAO.SelectByEmail(email)
	......
}

func (userService UserServiceImpl) Register(ctx context.Context, vo *RegisterUserVO) (*UserInfoDTO, error){
	......
}
  • 代码2:MakeLoginEndpoint:Endpoint的初始化
go 复制代码
type UserEndpoints struct {
	RegisterEndpoint  endpoint.Endpoint
	LoginEndpoint endpoint.Endpoint
}

//* 发送数据格式
type LoginRequest struct {
	Email string
	Password string
}

//* 接受数据格式
type LoginResponse struct {
	//* 转换json时,这个字段名为user_info
	UserInfo *service.UserInfoDTO `json:"user_info"`
}

//* 返回endpoint.Endpoint函数,接受LoginRequest格式,返回LoginResponse格式
func MakeLoginEndpoint(userService service.UserService) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
		//* 通过指针,断言了request的类型,后面的req.Email, req.Password就可以成立
		req := request.(*LoginRequest)
		userInfo, err := userService.Login(ctx, req.Email, req.Password)
		//* 通过userService返回需要的userInfo查询数据,并返回
		return &LoginResponse{UserInfo:userInfo}, err

	}
}
  • 代码3
go 复制代码
package transport

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/transport"
	kithttp "github.com/go-kit/kit/transport/http"
	"github.com/gorilla/mux"
	"github.com/longjoy/micro-go-course/section08/user/endpoint"
	"net/http"
	"os"
)

var (
	ErrorBadRequest = errors.New("invalid request parameter")
)

// MakeHttpHandler make http handler use mux
func MakeHttpHandler(ctx context.Context, endpoints *endpoint.UserEndpoints) http.Handler {
	//* mux 是一个强大的 HTTP 路由和分发库
	r := mux.NewRouter()

	//* 日志打印
	kitLog := log.NewLogfmtLogger(os.Stderr)

	kitLog = log.With(kitLog, "ts", log.DefaultTimestampUTC)
	kitLog = log.With(kitLog, "caller", log.DefaultCaller)

	//* 配置服务器的错误处理和错误编码
	options := []kithttp.ServerOption{
		kithttp.ServerErrorHandler(transport.NewLogErrorHandler(kitLog)),
		kithttp.ServerErrorEncoder(encodeError),
	}

	//* 建立一个路由
	r.Methods("POST").Path("/register").Handler(kithttp.NewServer(
		endpoints.RegisterEndpoint, //绑定处理的endpoint
		decodeRegisterRequest, //数据获取解析,并交给endpoint处理
		encodeJSONResponse, //把结果转成Json,发送给客户端,是发送前的处理
		options...,
	))


	r.Methods("POST").Path("/login").Handler(kithttp.NewServer(
		endpoints.LoginEndpoint,
		decodeLoginRequest,
		encodeJSONResponse,
		options...,
	))

	return r
}
func decodeRegisterRequest(_ context.Context, r *http.Request) (interface{}, error) {
	username := r.FormValue("username")
	password := r.FormValue("password")
	email := r.FormValue("email")

	if username == "" || password == "" || email == ""{
		return nil, ErrorBadRequest
	}
	return &endpoint.RegisterRequest{
		Username:username,
		Password:password,
		Email:email,
	},nil
}


func decodeLoginRequest(_ context.Context, r *http.Request) (interface{}, error) {
	email := r.FormValue("email")
	password := r.FormValue("password")

	if email == "" || password == "" {
		return nil, ErrorBadRequest
	}
	return &endpoint.LoginRequest{
		Email:email,
		Password:password,
	},nil
}

func encodeJSONResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
	w.Header().Set("Content-Type", "application/json;charset=utf-8")
	return json.NewEncoder(w).Encode(response)
}



func encodeError(_ context.Context, err error, w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	switch err {
	default:
		w.WriteHeader(http.StatusInternalServerError)
	}
	json.NewEncoder(w).Encode(map[string]interface{}{
		"error": err.Error(),
	})
}

第9讲: 货运平台应用的微服务划分

https://https://www.bilibili.com/video/BV1Gg4y1u77D/?spm_id_from=333.788.videopod.episodes&vd_source=707ec8983cc32e6e065d5496a7f79ee6&p=10
















在这里插入图片描述


第10讲: 微服务 Docker 容器化部署和 Kubernete 容器编排

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.player.switch\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=11




















第11讲: 如何结合 Jenkin 完成持续化集成和自动化测试?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=12










第12讲: 服务注册与发现如何满足服务治理?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=13


















第13讲: 如何基于 Conul 给微服务添加服务注册与发现?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=14







第14讲: 如何在 Go-kit 和 Service Meh 中进行服务注册与发现?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=15














第15讲: 微服务间如何进行远程方法调用?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.player.switch\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=16

















第16讲: Go RPC 如何实现服务间通信?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=17








第17讲: Go-kit 如何集成 gRPC?

https://www.bilibili.com/video/BV1Gg4y1u77D?spm_id_from=333.788.videopod.episodes\&vd_source=707ec8983cc32e6e065d5496a7f79ee6\&p=19








结束:

作为想了解下golang的微服务部分,就先看到这里,此教程给到众多惊喜;

云原生与微服务是当下开发大系统有力的解决方案,这篇教程更像是一场淋漓尽致的讲座,介绍了当下的云原生的各个构成,非常值得一学。

相关推荐
江木1231 小时前
Python Numba多流和共享内存CUDA优化技术学习记录
开发语言·python·学习
虾球xz2 小时前
游戏引擎学习第80天
学习·游戏引擎
Rousson2 小时前
硬件学习笔记--34 GB/T17215.321相关内容介绍
网络·笔记·学习
技术的探险家2 小时前
R语言的文件操作
开发语言·后端·golang
rgrgrwfe3 小时前
【golang学习之旅】使用VScode安装配置Go开发环境
vscode·学习·golang
m0_748251723 小时前
腾讯云AI代码助手评测:如何智能高效完成Go语言Web项目开发
前端·golang·腾讯云ai代码助手
BinaryBardC3 小时前
Go语言的文件操作
开发语言·后端·golang
alden_ygq3 小时前
Go os/exec 使用实践
开发语言·数据库·golang
m0_748251353 小时前
爬虫学习记录
爬虫·学习