序言

我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下:

  1. 环境搭建
  2. 服务拆分
  3. 用户服务
  4. 产品服务
  5. 订单服务
  6. 支付服务(本文)
  7. RPC 服务 Auth 验证
  8. 服务监控
  9. 链路追踪
  10. 分布式事务

期望通过本系列带你在本机利用 Docker 环境利用 go-zero 快速开发一个商城系统,让你快速上手微服务。

完整示例代码:https://github.com/nivin-studio/go-zero-mall

首先,我们来看一下整体的服务拆分图:

6 支付服务(pay)

  • 进入服务工作区
  1. $ cd mall/service/pay

6.1 生成 pay model 模型

  • 创建 sql 文件
  1. $ vim model/pay.sql
  • 编写 sql 文件
  1. CREATE TABLE `pay` (
  2. `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  3. `uid` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
  4. `oid` bigint unsigned NOT NULL DEFAULT '0' COMMENT '订单ID',
  5. `amount` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '产品金额',
  6. `source` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '支付方式',
  7. `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '支付状态',
  8. `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  9. `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  10. PRIMARY KEY (`id`),
  11. KEY `idx_uid` (`uid`),
  12. KEY `idx_oid` (`oid`)
  13. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  • 运行模板生成命令
  1. $ goctl model mysql ddl -src ./model/pay.sql -dir ./model -c

6.2 生成 pay api 服务

  • 创建 api 文件
  1. $ vim api/pay.api
  • 编写 api 文件
  1. type (
  2. // 支付创建
  3. CreateRequest {
  4. Uid int64 `json:"uid"`
  5. Oid int64 `json:"oid"`
  6. Amount int64 `json:"amount"`
  7. }
  8. CreateResponse {
  9. Id int64 `json:"id"`
  10. }
  11. // 支付创建
  12. // 支付详情
  13. DetailRequest {
  14. Id int64 `json:"id"`
  15. }
  16. DetailResponse {
  17. Id int64 `json:"id"`
  18. Uid int64 `json:"uid"`
  19. Oid int64 `json:"oid"`
  20. Amount int64 `json:"amount"`
  21. Source int64 `json:"source"`
  22. Status int64 `json:"status"`
  23. }
  24. // 支付详情
  25. // 支付回调
  26. CallbackRequest {
  27. Id int64 `json:"id"`
  28. Uid int64 `json:"uid"`
  29. Oid int64 `json:"oid"`
  30. Amount int64 `json:"amount"`
  31. Source int64 `json:"source"`
  32. Status int64 `json:"status"`
  33. }
  34. CallbackResponse {
  35. }
  36. // 支付回调
  37. )
  38. @server(
  39. jwt: Auth
  40. )
  41. service Pay {
  42. @handler Create
  43. post /api/pay/create(CreateRequest) returns (CreateResponse)
  44. @handler Detail
  45. post /api/pay/detail(DetailRequest) returns (DetailResponse)
  46. @handler Callback
  47. post /api/pay/callback(CallbackRequest) returns (CallbackResponse)
  48. }
  • 运行模板生成命令
  1. $ goctl api go -api ./api/pay.api -dir ./api

6.3 生成 pay rpc 服务

  • 创建 proto 文件
  1. $ vim rpc/pay.proto
  • 编写 proto 文件
  1. syntax = "proto3";
  2. package payclient;
  3. option go_package = "pay";
  4. // 支付创建
  5. message CreateRequest {
  6. int64 Uid = 1;
  7. int64 Oid = 2;
  8. int64 Amount = 3;
  9. }
  10. message CreateResponse {
  11. int64 id = 1;
  12. }
  13. // 支付创建
  14. // 支付详情
  15. message DetailRequest {
  16. int64 id = 1;
  17. }
  18. message DetailResponse {
  19. int64 id = 1;
  20. int64 Uid = 2;
  21. int64 Oid = 3;
  22. int64 Amount = 4;
  23. int64 Source = 5;
  24. int64 Status = 6;
  25. }
  26. // 支付详情
  27. // 支付详情
  28. message CallbackRequest {
  29. int64 id = 1;
  30. int64 Uid = 2;
  31. int64 Oid = 3;
  32. int64 Amount = 4;
  33. int64 Source = 5;
  34. int64 Status = 6;
  35. }
  36. message CallbackResponse {
  37. }
  38. // 支付详情
  39. service Pay {
  40. rpc Create(CreateRequest) returns(CreateResponse);
  41. rpc Detail(DetailRequest) returns(DetailResponse);
  42. rpc Callback(CallbackRequest) returns(CallbackResponse);
  43. }
  • 运行模板生成命令
  1. $ goctl rpc proto -src ./rpc/pay.proto -dir ./rpc

6.4 编写 pay rpc 服务

6.4.1 修改配置文件

  • 修改 pay.yaml 配置文件
  1. $ vim rpc/etc/pay.yaml
  • 修改服务监听地址,端口号为0.0.0.0:9003,Etcd 服务配置,Mysql 服务配置,CacheRedis 服务配置
  1. Name: pay.rpc
  2. ListenOn: 0.0.0.0:9003
  3. Etcd:
  4. Hosts:
  5. - etcd:2379
  6. Key: pay.rpc
  7. Mysql:
  8. DataSource: root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
  9. CacheRedis:
  10. - Host: redis:6379
  11. Type: node
  12. Pass:

6.4.2 添加 pay model 依赖

  • 添加 Mysql 服务配置,CacheRedis 服务配置的实例化
  1. $ vim rpc/internal/config/config.go
  1. package config
  2. import (
  3. "github.com/tal-tech/go-zero/core/stores/cache"
  4. "github.com/tal-tech/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. zrpc.RpcServerConf
  8. Mysql struct {
  9. DataSource string
  10. }
  11. CacheRedis cache.CacheConf
  12. }
  • 注册服务上下文 pay model 的依赖
  1. $ vim rpc/internal/svc/servicecontext.go
  1. package svc
  2. import (
  3. "mall/service/pay/model"
  4. "mall/service/pay/rpc/internal/config"
  5. "github.com/tal-tech/go-zero/core/stores/sqlx"
  6. )
  7. type ServiceContext struct {
  8. Config config.Config
  9. PayModel model.PayModel
  10. }
  11. func NewServiceContext(c config.Config) *ServiceContext {
  12. conn := sqlx.NewMysql(c.Mysql.DataSource)
  13. return &ServiceContext{
  14. Config: c,
  15. PayModel: model.NewPayModel(conn, c.CacheRedis),
  16. }
  17. }

6.4.3 添加 user rpc,order rpc 依赖

  • 添加 user rpc, order rpc 服务配置
  1. $ vim rpc/etc/pay.yaml
  1. Name: pay.rpc
  2. ListenOn: 0.0.0.0:9003
  3. Etcd:
  4. Hosts:
  5. - etcd:2379
  6. Key: pay.rpc
  7. ...
  8. UserRpc:
  9. Etcd:
  10. Hosts:
  11. - etcd:2379
  12. Key: user.rpc
  13. OrderRpc:
  14. Etcd:
  15. Hosts:
  16. - etcd:2379
  17. Key: order.rpc
  • 添加 user rpc, order rpc 服务配置的实例化
  1. $ vim rpc/internal/config/config.go
  1. package config
  2. import (
  3. "github.com/tal-tech/go-zero/core/stores/cache"
  4. "github.com/tal-tech/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. zrpc.RpcServerConf
  8. Mysql struct {
  9. DataSource string
  10. }
  11. CacheRedis cache.CacheConf
  12. UserRpc zrpc.RpcClientConf
  13. OrderRpc zrpc.RpcClientConf
  14. }
  • 注册服务上下文 user rpc, order rpc 的依赖
  1. $ vim rpc/internal/svc/servicecontext.go
  1. package svc
  2. import (
  3. "mall/service/order/rpc/orderclient"
  4. "mall/service/pay/model"
  5. "mall/service/pay/rpc/internal/config"
  6. "mall/service/user/rpc/userclient"
  7. "github.com/tal-tech/go-zero/core/stores/sqlx"
  8. "github.com/tal-tech/go-zero/zrpc"
  9. )
  10. type ServiceContext struct {
  11. Config config.Config
  12. PayModel model.PayModel
  13. UserRpc userclient.User
  14. OrderRpc orderclient.Order
  15. }
  16. func NewServiceContext(c config.Config) *ServiceContext {
  17. conn := sqlx.NewMysql(c.Mysql.DataSource)
  18. return &ServiceContext{
  19. Config: c,
  20. PayModel: model.NewPayModel(conn, c.CacheRedis),
  21. UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
  22. OrderRpc: orderclient.NewOrder(zrpc.MustNewClient(c.OrderRpc)),
  23. }
  24. }

6.4.4 添加支付创建逻辑 Create

  • 添加根据 oid 查询订单支付记录 PayModel 方法 FindOneByOid
  1. $ vim model/paymodel.go
  1. package model
  2. ...
  3. var (
  4. ...
  5. cachePayIdPrefix = "cache:pay:id:"
  6. cachePayOidPrefix = "cache:pay:oid:"
  7. )
  8. type (
  9. PayModel interface {
  10. Insert(data *Pay) (sql.Result, error)
  11. FindOne(id int64) (*Pay, error)
  12. FindOneByOid(oid int64) (*Pay, error)
  13. Update(data *Pay) error
  14. Delete(id int64) error
  15. }
  16. ...
  17. )
  18. ...
  19. func (m *defaultPayModel) FindOneByOid(oid int64) (*Pay, error) {
  20. payOidKey := fmt.Sprintf("%s%v", cachePayOidPrefix, oid)
  21. var resp Pay
  22. err := m.QueryRow(&resp, payOidKey, func(conn sqlx.SqlConn, v interface{}) error {
  23. query := fmt.Sprintf("select %s from %s where `oid` = ? limit 1", payRows, m.table)
  24. return conn.QueryRow(v, query, oid)
  25. })
  26. switch err {
  27. case nil:
  28. return &resp, nil
  29. case sqlc.ErrNotFound:
  30. return nil, ErrNotFound
  31. default:
  32. return nil, err
  33. }
  34. }
  35. ......
  • 添加支付创建逻辑

    支付流水创建流程,通过调用 user rpc 服务查询验证用户是否存在,再通过调用 order rpc 服务查询验证订单是否存在,然后通过查询库判断此订单是否已经创建过支付流水,最后创建落库。

  1. $ vim rpc/internal/logic/createlogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/service/order/rpc/order"
  5. "mall/service/pay/model"
  6. "mall/service/pay/rpc/internal/svc"
  7. "mall/service/pay/rpc/pay"
  8. "mall/service/user/rpc/user"
  9. "github.com/tal-tech/go-zero/core/logx"
  10. "google.golang.org/grpc/status"
  11. )
  12. type CreateLogic struct {
  13. ctx context.Context
  14. svcCtx *svc.ServiceContext
  15. logx.Logger
  16. }
  17. func NewCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateLogic {
  18. return &CreateLogic{
  19. ctx: ctx,
  20. svcCtx: svcCtx,
  21. Logger: logx.WithContext(ctx),
  22. }
  23. }
  24. func (l *CreateLogic) Create(in *pay.CreateRequest) (*pay.CreateResponse, error) {
  25. // 查询用户是否存在
  26. _, err := l.svcCtx.UserRpc.UserInfo(l.ctx, &user.UserInfoRequest{
  27. Id: in.Uid,
  28. })
  29. if err != nil {
  30. return nil, err
  31. }
  32. // 查询订单是否存在
  33. _, err = l.svcCtx.OrderRpc.Detail(l.ctx, &order.DetailRequest{
  34. Id: in.Oid,
  35. })
  36. if err != nil {
  37. return nil, err
  38. }
  39. // 查询订单是否已经创建支付
  40. _, err = l.svcCtx.PayModel.FindOneByOid(in.Oid)
  41. if err == nil {
  42. return nil, status.Error(100, "订单已创建支付")
  43. }
  44. newPay := model.Pay{
  45. Uid: in.Uid,
  46. Oid: in.Oid,
  47. Amount: in.Amount,
  48. Source: 0,
  49. Status: 0,
  50. }
  51. res, err := l.svcCtx.PayModel.Insert(&newPay)
  52. if err != nil {
  53. return nil, status.Error(500, err.Error())
  54. }
  55. newPay.Id, err = res.LastInsertId()
  56. if err != nil {
  57. return nil, status.Error(500, err.Error())
  58. }
  59. return &pay.CreateResponse{
  60. Id: newPay.Id,
  61. }, nil
  62. }

6.4.5 添加支付详情逻辑 Detail

  1. $ vim rpc/internal/logic/detaillogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/service/pay/model"
  5. "mall/service/pay/rpc/internal/svc"
  6. "mall/service/pay/rpc/pay"
  7. "github.com/tal-tech/go-zero/core/logx"
  8. "google.golang.org/grpc/status"
  9. )
  10. type DetailLogic struct {
  11. ctx context.Context
  12. svcCtx *svc.ServiceContext
  13. logx.Logger
  14. }
  15. func NewDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DetailLogic {
  16. return &DetailLogic{
  17. ctx: ctx,
  18. svcCtx: svcCtx,
  19. Logger: logx.WithContext(ctx),
  20. }
  21. }
  22. func (l *DetailLogic) Detail(in *pay.DetailRequest) (*pay.DetailResponse, error) {
  23. // 查询支付是否存在
  24. res, err := l.svcCtx.PayModel.FindOne(in.Id)
  25. if err != nil {
  26. if err == model.ErrNotFound {
  27. return nil, status.Error(100, "支付不存在")
  28. }
  29. return nil, status.Error(500, err.Error())
  30. }
  31. return &pay.DetailResponse{
  32. Id: res.Id,
  33. Uid: res.Uid,
  34. Oid: res.Oid,
  35. Amount: res.Amount,
  36. Source: res.Source,
  37. Status: res.Status,
  38. }, nil
  39. }

6.4.6 添加支付回调逻辑 Callback

支付流水回调流程,通过调用 user rpc 服务查询验证用户是否存在,再通过调用 order rpc 服务查询验证订单是否存在,然后通过查询库判断此订单支付流水是否存在,以及回调支付金额和库中流水支付金额是否一致,最后更新支付流水状态和通过调用 order rpc 服务更新订单状态。

  1. $ vim rpc/internal/logic/callbacklogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/service/order/rpc/order"
  5. "mall/service/pay/model"
  6. "mall/service/pay/rpc/internal/svc"
  7. "mall/service/pay/rpc/pay"
  8. "mall/service/user/rpc/user"
  9. "github.com/tal-tech/go-zero/core/logx"
  10. "google.golang.org/grpc/status"
  11. )
  12. type CallbackLogic struct {
  13. ctx context.Context
  14. svcCtx *svc.ServiceContext
  15. logx.Logger
  16. }
  17. func NewCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CallbackLogic {
  18. return &CallbackLogic{
  19. ctx: ctx,
  20. svcCtx: svcCtx,
  21. Logger: logx.WithContext(ctx),
  22. }
  23. }
  24. func (l *CallbackLogic) Callback(in *pay.CallbackRequest) (*pay.CallbackResponse, error) {
  25. // 查询用户是否存在
  26. _, err := l.svcCtx.UserRpc.UserInfo(l.ctx, &user.UserInfoRequest{
  27. Id: in.Uid,
  28. })
  29. if err != nil {
  30. return nil, err
  31. }
  32. // 查询订单是否存在
  33. _, err = l.svcCtx.OrderRpc.Detail(l.ctx, &order.DetailRequest{
  34. Id: in.Oid,
  35. })
  36. if err != nil {
  37. return nil, err
  38. }
  39. // 查询支付是否存在
  40. res, err := l.svcCtx.PayModel.FindOne(in.Id)
  41. if err != nil {
  42. if err == model.ErrNotFound {
  43. return nil, status.Error(100, "支付不存在")
  44. }
  45. return nil, status.Error(500, err.Error())
  46. }
  47. // 支付金额与订单金额不符
  48. if in.Amount != res.Amount {
  49. return nil, status.Error(100, "支付金额与订单金额不符")
  50. }
  51. res.Source = in.Source
  52. res.Status = in.Status
  53. err = l.svcCtx.PayModel.Update(res)
  54. if err != nil {
  55. return nil, status.Error(500, err.Error())
  56. }
  57. // 更新订单支付状态
  58. _, err = l.svcCtx.OrderRpc.Paid(l.ctx, &order.PaidRequest{
  59. Id: in.Oid,
  60. })
  61. if err != nil {
  62. return nil, status.Error(500, err.Error())
  63. }
  64. return &pay.CallbackResponse{}, nil
  65. }

6.5 编写 pay api 服务

6.5.1 修改配置文件

  • 修改 pay.yaml 配置文件
  1. $ vim api/etc/pay.yaml
  • 修改服务地址,端口号为0.0.0.0:8003,Mysql 服务配置,CacheRedis 服务配置,Auth 验证配置
  1. Name: Pay
  2. Host: 0.0.0.0
  3. Port: 8003
  4. Mysql:
  5. DataSource: root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
  6. CacheRedis:
  7. - Host: redis:6379
  8. Type: node
  9. Pass:
  10. Auth:
  11. AccessSecret: uOvKLmVfztaXGpNYd4Z0I1SiT7MweJhl
  12. AccessExpire: 86400

6.5.2 添加 pay rpc 依赖

  • 添加 pay rpc 服务配置
  1. $ vim api/etc/pay.yaml
  1. Name: Pay
  2. Host: 0.0.0.0
  3. Port: 8003
  4. ......
  5. PayRpc:
  6. Etcd:
  7. Hosts:
  8. - etcd:2379
  9. Key: pay.rpc
  • 添加 pay rpc 服务配置的实例化
  1. $ vim api/internal/config/config.go
  1. package config
  2. import (
  3. "github.com/tal-tech/go-zero/rest"
  4. "github.com/tal-tech/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. rest.RestConf
  8. Auth struct {
  9. AccessSecret string
  10. AccessExpire int64
  11. }
  12. PayRpc zrpc.RpcClientConf
  13. }
  • 注册服务上下文 pay rpc 的依赖
  1. $ vim api/internal/svc/servicecontext.go
  1. package svc
  2. import (
  3. "mall/service/pay/api/internal/config"
  4. "mall/service/pay/rpc/payclient"
  5. "github.com/tal-tech/go-zero/zrpc"
  6. )
  7. type ServiceContext struct {
  8. Config config.Config
  9. PayRpc payclient.Pay
  10. }
  11. func NewServiceContext(c config.Config) *ServiceContext {
  12. return &ServiceContext{
  13. Config: c,
  14. PayRpc: payclient.NewPay(zrpc.MustNewClient(c.PayRpc)),
  15. }
  16. }

6.5.3 添加支付创建逻辑 Create

  1. $ vim api/internal/logic/createlogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/service/pay/api/internal/svc"
  5. "mall/service/pay/api/internal/types"
  6. "mall/service/pay/rpc/pay"
  7. "github.com/tal-tech/go-zero/core/logx"
  8. )
  9. type CreateLogic struct {
  10. logx.Logger
  11. ctx context.Context
  12. svcCtx *svc.ServiceContext
  13. }
  14. func NewCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) CreateLogic {
  15. return CreateLogic{
  16. Logger: logx.WithContext(ctx),
  17. ctx: ctx,
  18. svcCtx: svcCtx,
  19. }
  20. }
  21. func (l *CreateLogic) Create(req types.CreateRequest) (resp *types.CreateResponse, err error) {
  22. res, err := l.svcCtx.PayRpc.Create(l.ctx, &pay.CreateRequest{
  23. Uid: req.Uid,
  24. Oid: req.Oid,
  25. Amount: req.Amount,
  26. })
  27. if err != nil {
  28. return nil, err
  29. }
  30. return &types.CreateResponse{
  31. Id: res.Id,
  32. }, nil
  33. }

6.5.4 添加支付详情逻辑 Detail

  1. $ vim api/internal/logic/detaillogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/service/pay/api/internal/svc"
  5. "mall/service/pay/api/internal/types"
  6. "mall/service/pay/rpc/pay"
  7. "github.com/tal-tech/go-zero/core/logx"
  8. )
  9. type DetailLogic struct {
  10. logx.Logger
  11. ctx context.Context
  12. svcCtx *svc.ServiceContext
  13. }
  14. func NewDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) DetailLogic {
  15. return DetailLogic{
  16. Logger: logx.WithContext(ctx),
  17. ctx: ctx,
  18. svcCtx: svcCtx,
  19. }
  20. }
  21. func (l *DetailLogic) Detail(req types.DetailRequest) (resp *types.DetailResponse, err error) {
  22. res, err := l.svcCtx.PayRpc.Detail(l.ctx, &pay.DetailRequest{
  23. Id: req.Id,
  24. })
  25. if err != nil {
  26. return nil, err
  27. }
  28. return &types.DetailResponse{
  29. Id: req.Id,
  30. Uid: res.Uid,
  31. Oid: res.Oid,
  32. Amount: res.Amount,
  33. Source: res.Source,
  34. Status: res.Status,
  35. }, nil
  36. }

6.5.5 添加支付回调逻辑 Callback

  1. $ vim api/internal/logic/callbacklogic.go
  1. package logic
  2. import (
  3. "context"
  4. "mall/service/pay/api/internal/svc"
  5. "mall/service/pay/api/internal/types"
  6. "mall/service/pay/rpc/pay"
  7. "github.com/tal-tech/go-zero/core/logx"
  8. )
  9. type CallbackLogic struct {
  10. logx.Logger
  11. ctx context.Context
  12. svcCtx *svc.ServiceContext
  13. }
  14. func NewCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) CallbackLogic {
  15. return CallbackLogic{
  16. Logger: logx.WithContext(ctx),
  17. ctx: ctx,
  18. svcCtx: svcCtx,
  19. }
  20. }
  21. func (l *CallbackLogic) Callback(req types.CallbackRequest) (resp *types.CallbackResponse, err error) {
  22. _, err = l.svcCtx.PayRpc.Callback(l.ctx, &pay.CallbackRequest{
  23. Id: req.Id,
  24. Uid: req.Uid,
  25. Oid: req.Oid,
  26. Amount: req.Amount,
  27. Source: req.Source,
  28. Status: req.Status,
  29. })
  30. if err != nil {
  31. return nil, err
  32. }
  33. return &types.CallbackResponse{}, nil
  34. }

6.6 启动 pay rpc 服务

提示:启动服务需要在 golang 容器中启动

  1. $ cd mall/service/pay/rpc
  2. $ go run pay.go -f etc/pay.yaml
  3. Starting rpc server at 127.0.0.1:9003...

6.7 启动 pay api 服务

提示:启动服务需要在 golang 容器中启动

  1. $ cd mall/service/pay/api
  2. $ go run pay.go -f etc/pay.yaml
  3. Starting server at 0.0.0.0:8003...

项目地址

https://github.com/zeromicro/go-zero

欢迎使用 go-zerostar 支持我们!

微信交流群

关注『微服务实践』公众号并点击 交流群 获取社区群二维码。

带你十天轻松搞定 Go 微服务系列(六)的更多相关文章

  1. 带你十天轻松搞定 Go 微服务系列(一)

    本文开始,我们会出一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建(本文) 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Au ...

  2. 带你十天轻松搞定 Go 微服务系列(二)

    上篇文章开始,我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分(本文) 用户服务 产品服务 订单服务 支付服务 RPC 服务 ...

  3. 带你十天轻松搞定 Go 微服务系列(三)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务(本文) 产品服务 订单服务 支付服务 RPC 服务 Auth ...

  4. 带你十天轻松搞定 Go 微服务系列(五)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务(本文) 支付服务 RPC 服务 Auth ...

  5. 带你十天轻松搞定 Go 微服务系列(七)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证( ...

  6. 带你十天轻松搞定 Go 微服务系列(八、服务监控)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证 ...

  7. 带你十天轻松搞定 Go 微服务系列(九、链路追踪)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证 ...

  8. 带你十天轻松搞定 Go 微服务之大结局(分布式事务)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证 ...

  9. 【微服务】之二:从零开始,轻松搞定SpringCloud微服务系列--注册中心(一)

    微服务体系,有效解决项目庞大.互相依赖的问题.目前SpringCloud体系有强大的一整套针对微服务的解决方案.本文中,重点对微服务体系中的服务发现注册中心进行详细说明.本篇中的注册中心,采用Netf ...

随机推荐

  1. 【Android开发】找乐,一个笑话App的制作过程记录

    缘起 想做一个笑话App的原因是因为在知乎上看过一个帖子,做Android可以有哪些数据可以练手,里面推荐了几个数据开放平台.在这些平台中无一不是有公共的笑话接口,当时心想这个可以拿来练手啊,还挺有意 ...

  2. 使用Java对接永中格式转换

    永中格式转换服务基于永中DCS的文档转换能力,支持不同格式文件之间的高质量互转,可实现PDF文档与Word.Excel.PPT.图片的高质量互转,PDF文档转换完美保留原文档的版式,格式等,转换效果出 ...

  3. 一个网关服务性能问题的Dump分析

    本篇文章分为三部分,首先简单介绍一下分析的工具Windbg,其次针对一个网关服务性能问题进行逐步刨析,最后针对性能问题的分析总结. 一 Windbg介绍 1.Windbg是个非常强大的调试器,它设计了 ...

  4. 「HAOI 2006」数字序列

    Description 给定一长度为 \(n\) 的数列 \(a\),可将 \(a_i\) 改为任意整数 \(k\),代价为 \(\mid a_i-k\mid\). 问最少改变多少个数能把它变成一个单 ...

  5. matplotlib 进阶之Customizing Figure Layouts Using GridSpec and Other Functions

    目录 对Gridspec的一些精细的调整 利用SubplotSpec fig.add_grdispec; gs.subgridspec 一个利用Subplotspec的复杂例子 函数链接 matplo ...

  6. Vue的安装及使用(Vue的三种安装使用方式)

    vue是一个JavaMVVM库,是一套用于构建用户界面的渐进式框架,是初创项目的首选前端框架.它是以数据驱动和组件化的思想构建的,采用自底向上增量开发的设计.它是轻量级的,它有很多独立的功能或库,我们 ...

  7. MySQL数据库安装Version5.7

    MySQL数据库版本: mysql-5.7.22-linux-glibc2.12-x86_64 Linux服务器系统: CentOS 7.4 64bit MySQL安装用户: mysql/aliyun ...

  8. Solon 1.6.12 发布,类似 Spring 的生态体系

    关于官网 千呼万唤始出来: https://solon.noear.org .整了一个月多了,总体样子有了...还得不断接着整! 关于 Solon Solon 是一个轻量级应用开发框架.支持 Web. ...

  9. vs2017 快捷键 - 总结

    1.格式化代码 先选中需要格式的代码,一般是全选[Ctrl+A]后,Ctrl+K+F[按定Ctrl不动,依序点击 K和F,然后再放开 Ctrl ] 2.多行注释 注释: 先CTRL+K,然后CTRL+ ...

  10. [ flask-migrate ] 记自己犯的一次低级错误

    问题描述 从github上pull了别人的项目学习,项目用flask-migrate来迁移数据库.查看了一下,作者把数据库文件 app.db 删除了,不过migrations文件夹留着的,因此我只需要 ...