PD api基础框架源码分析
作者:薛港-移动云
原文来源: https://tidb.net/blog/df7a1570
PD提供两类API,一类是restful api ,一例是grpc 服务。这两类服务都依赖于ETCD。也就是依赖ETCD实例提供restful以及grpc服务。我们要做的就是启动ETCD的时候,参数配置里设置以下两类参数:
// Config holds the arguments for configuring an etcd
// server.
type Config struct {
// UserHandlers is for registering users handlers and only used
// for
// embedding etcd into other applications.
// The map key is the route path for the handler, and
// you must ensure it can’t be conflicted with etcd’s.
UserHandlers map[string]http.Handler json:"-"
// ServiceRegister is for registering users’ gRPC services. A
// simple usage example:
// cfg := embed.NewConfig()
// cfg.ServerRegister = func(s *grpc.Server) {
// pb.RegisterFooServer(s, &fooServer{})
// pb.RegisterBarServer(s, &barServer{})
// }
// embed.StartEtcd(cfg)
ServiceRegister func(*grpc.Server) json:"-"
}
ETCD里这两个参数初始代码如下:
// CreateServer creates the UNINITIALIZED pd server with
// given configuration.
func CreateServer(ctx context.Context, cfg *config.Config,
serviceBuilders …HandlerBuilder) (*Server, error) {
s := &Server{
cfg: cfg,
persistOptions: config.NewPersistOptions(cfg),
member: &member.Member{},
ctx: ctx,
startTimestamp: time.Now().Unix(),
}
// Adjust etcd config.
etcdCfg, err := s.cfg.GenEmbedEtcdConfig()
if len(serviceBuilders) != 0 {
userHandlers, err := combineBuilderServerHTTPService(ctx,
s, serviceBuilders…)
etcdCfg.UserHandlers = userHandlers
}
etcdCfg.ServiceRegister = func(gs *grpc.Server) {
pdpb.RegisterPDServer(gs, s)
diagnosticspb.RegisterDiagnosticsServer(gs, s)
}
}
先分析 combineBuilderServerHTTPService(ctx, s, serviceBuilders…),这个函数生成UserHanders 对象,用于提供restful api 服务
这个函数接受HandlerBuilder参数,返回一个map结构,key对应api path, value对应http.handle 用于处理restful 对应请求的处理逻辑。
这个函数本身没什么特别的,就是基于ServiceGroup信息,给一类API引入异常恢复中间件,依赖于第三方库( github.com/urfave/negroni)
func combineBuilderServerHTTPService(ctx context.Context, svr *Server, serviceBuilders …HandlerBuilder) (map[string]http.Handler, error) {
}
combineBuilderServerHTTPService的重点是参数serviceBuilders ,这是一个slice,元素类型是函数定义,ServiceGroup 用于生成对应的api的path,http.Handle用于restful 函数请求处理
// HandlerBuilder builds a server HTTP handler.
type HandlerBuilder func(context.Context, *Server) (http.Handler, ServiceGroup, error)
下面我们分析serviceBuilders参数实例化代码,
serviceBuilders := []server.HandlerBuilder{api.NewHandler,
swaggerserver.NewHandler, autoscaling.NewHandler}
serviceBuilders = append(serviceBuilders,
dashboard.GetServiceBuilders()…)
svr, err := server.CreateServer(ctx, cfg, serviceBuilders…)
serviceBuilders 是一个slice,每一个元素都是一个函数定义,返回api 处理handle,以及用于决定api path的数据结构serviceGroup.
我们重点分析slice元素api.NewHandler,然后一通都通,其它api定义也是类似框架:
// NewHandler creates a HTTP handler for API.
func NewHandler(ctx context.Context, svr *server.Server) (http.Handler, server.ServiceGroup, error) {
group := server.ServiceGroup{
Name: “core”,
IsCore: true,
}
router := mux.NewRouter()
r := createRouter(ctx, apiPrefix, svr)
router.PathPrefix(apiPrefix).Handler(negroni.New(
serverapi.NewRuntimeServiceValidator(svr, group),
serverapi.NewRedirector(svr),
negroni.Wrap®),
)
return router, group, nil
}
重点分析createRouter(ctx, apiPrefix, svr),这个函数生成一个route,包含restful api的path以及处理函数
func createRouter(ctx context.Context, prefix string, svr *server.Server) *mux.Router {
operatorHandler := newOperatorHandler(handler, rd)
apiRouter.HandleFunc("/operators", operatorHandler.List).Methods(“GET”)
apiRouter.HandleFunc("/operators", operatorHandler.Post).Methods(“POST”)
apiRouter.HandleFunc("/operators/{region_id}", operatorHandler.Get).Methods(“GET”)
apiRouter.HandleFunc("/operators/{region_id}", operatorHandler.Delete).Methods(“DELETE”)
schedulerHandler := newSchedulerHandler(svr, rd)
apiRouter.HandleFunc("/schedulers", schedulerHandler.List).Methods("GET")
apiRouter.HandleFunc("/schedulers", schedulerHandler.Post).Methods("POST")
apiRouter.HandleFunc("/schedulers/{name}", schedulerHandler.Delete).Methods("DELETE")
apiRouter.HandleFunc("/schedulers/{name}", schedulerHandler.PauseOrResume).Methods("POST")
…
}
有意思的是如下代码
router.PathPrefix(apiPrefix).Handler(negroni.New(
serverapi.NewRuntimeServiceValidator(svr,
group),
serverapi.NewRedirector(svr),
negroni.Wrap®),
)
上面代码hander接受一个negroni创建的handle对象,这个对象可以理解服务中间件拦截器,也就是任何一个api请求会依次经过前面两个hanlde拦截,才会被业务route 处理。我们重点关注第二拦截器:
serverapi.NewRedirector(svr)。这个拦截器也很简单,主要检察当前接受请求的pd 实例,是否是leader,如果不是,那么这个pd作为服务转发方,给pd leader转发restful api 请求
func (h *redirector) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
r.Header.Set(RedirectorHeader, h.s.Name())
leader := h.s.GetMember().GetLeader()if leader == nil {http.Error(w, "no leader", http.StatusServiceUnavailable)return}urls, err := config.ParseUrls(strings.Join(leader.GetClientUrls(), ","))client := h.s.GetHTTPClient()NewCustomReverseProxies(client, urls).ServeHTTP(w, r)
}
下面分析grpc服务,主要通过ETCD 参数注册grpc服务,下面的代码表明Server对象提供grpc服务
etcdCfg.ServiceRegister = func(gs *grpc.Server) {
pdpb.RegisterPDServer(gs, s)
diagnosticspb.RegisterDiagnosticsServer(gs, s)
}
我们先关注一下grpc提供服务api,然后后面分析每个模块细节时,一个个api开展深入分析
type PDServer interface {
// GetMembers get the member list of this cluster. It does not require
// the cluster_id in request matchs the id of this cluster.
GetMembers(context.Context, *GetMembersRequest) (*GetMembersResponse, error)
Tso(PD_TsoServer) error
Bootstrap(context.Context, *BootstrapRequest) (*BootstrapResponse, error)
IsBootstrapped(context.Context, *IsBootstrappedRequest) (*IsBootstrappedResponse, error)
AllocID(context.Context, *AllocIDRequest) (*AllocIDResponse, error)
GetStore(context.Context, *GetStoreRequest) (*GetStoreResponse, error)
PutStore(context.Context, *PutStoreRequest) (*PutStoreResponse, error)
GetAllStores(context.Context, *GetAllStoresRequest) (*GetAllStoresResponse, error)
StoreHeartbeat(context.Context, *StoreHeartbeatRequest) (*StoreHeartbeatResponse, error)
RegionHeartbeat(PD_RegionHeartbeatServer) error
GetRegion(context.Context, *GetRegionRequest) (*GetRegionResponse, error)
GetPrevRegion(context.Context, *GetRegionRequest) (*GetRegionResponse, error)
GetRegionByID(context.Context, *GetRegionByIDRequest) (*GetRegionResponse, error)
ScanRegions(context.Context, *ScanRegionsRequest) (*ScanRegionsResponse, error)
AskSplit(context.Context, *AskSplitRequest) (*AskSplitResponse, error)
ReportSplit(context.Context, *ReportSplitRequest) (*ReportSplitResponse, error)
AskBatchSplit(context.Context, *AskBatchSplitRequest) (*AskBatchSplitResponse, error)
ReportBatchSplit(context.Context, *ReportBatchSplitRequest) (*ReportBatchSplitResponse, error)
GetClusterConfig(context.Context, *GetClusterConfigRequest) (*GetClusterConfigResponse, error)
PutClusterConfig(context.Context, *PutClusterConfigRequest) (*PutClusterConfigResponse, error)
ScatterRegion(context.Context, *ScatterRegionRequest) (*ScatterRegionResponse, error)
GetGCSafePoint(context.Context, *GetGCSafePointRequest) (*GetGCSafePointResponse, error)
UpdateGCSafePoint(context.Context, *UpdateGCSafePointRequest) (*UpdateGCSafePointResponse, error)
UpdateServiceGCSafePoint(context.Context, *UpdateServiceGCSafePointRequest) (*UpdateServiceGCSafePointResponse, error)
SyncRegions(PD_SyncRegionsServer) error
GetOperator(context.Context, *GetOperatorRequest) (*GetOperatorResponse, error)
SyncMaxTS(context.Context, *SyncMaxTSRequest) (*SyncMaxTSResponse, error)
SplitRegions(context.Context, *SplitRegionsRequest) (*SplitRegionsResponse, error)
GetDCLocationInfo(context.Context, *GetDCLocationInfoRequest) (*GetDCLocationInfoResponse, error)
}
PD api基础框架源码分析相关推荐
- SPI驱动框架源码分析
SPI驱动框架源码分析 2013-04-12 16:13:08 分类: LINUX SPI驱动框架源码分析 SPI协议是一种同步的串行数据连接标准,由摩托罗拉公司命名,可工作于全双工模式.相关通讯设 ...
- Linux驱动修炼之道-SPI驱动框架源码分析(上)
Linux驱动修炼之道-SPI驱动框架源码分析(上) SPI协议是一种同步的串行数据连接标准,由摩托罗拉公司命名,可工作于全双工模式.相关通讯设备可工作于m/s模式.主设备发起数据帧,允许多个从设 ...
- S3C24XX DMA框架源码分析
基于S3C2440 的DMA 框架源码分析 基于S3C2440 的DMA 框架源码分析 二寻根溯源 1 设备类的注册 2 s3c2410_dma_init 3 s3c24xx_dma_order_se ...
- Java集合类框架源码分析 之 LinkedList源码解析 【4】
上一篇介绍了ArrayList的源码分析[点击看文章],既然ArrayList都已经做了介绍,那么作为他同胞兄弟的LinkedList,当然必须也配拥有姓名! Talk is cheap,show m ...
- Spark RPC框架源码分析(二)RPC运行时序
前情提要: Spark RPC框架源码分析(一)简述 一. Spark RPC概述 上一篇我们已经说明了Spark RPC框架的一个简单例子,Spark RPC相关的两个编程模型,Actor模型和Re ...
- windows C++ Opengl基础框架源码
windows C++ Opengl基础框架源码 项目开发环境 项目功能 项目演示 项目源码传送门 项目开发环境 开发语言:C++和IDE:VS2017,操作系统Windows版本windows SD ...
- Android框架源码分析——从设计模式角度看 Retrofit 核心源码
Android框架源码分析--从设计模式角度看 Retrofit 核心源码 Retrofit中用到了许多常见的设计模式:代理模式.外观模式.构建者模式等.我们将从这三种设计模式入手,分析 Retrof ...
- php+yii框架,yii框架源码分析(一)
yii框架源码分析(一) 本文将对yii中的mvc,路由器,filter,组件机制等最主要的部分进行自己的一点浅析,力求说明自己做一个php mvc不是那么的遥不可及,其实是很简单的. 源码基于yii ...
- golang gin框架源码分析(二)---- 渐入佳境 摸索Engine ServeHTTP访问前缀树真正原理
文章目录 全系列总结博客链接 前引 golang gin框架源码分析(二)---- 渐入佳境 摸索Engine ServeHTTP访问前缀树真正远原理 1.再列示例代码 从示例代码入手 2.r.Run ...
最新文章
- 一份很不错的敏捷产品需要文档模板
- 圆柱属于能滚动的物体吗_中班科学活动教案:滚动的物体教案(附教学反思)
- IE6.0,ie7.0与Firefox的CSS兼容性问题
- 【软件开发底层知识修炼】二十五 ABI之函数调用约定二之函数返回值为结构体时的约定
- 拓扑排序 codevs 4040 cojs 438
- atitit.hbnt orm db 新新增更新最佳实践o7
- asp.net中实现登陆的时候用SSL
- BuildTools下载地址
- STC15单片机使用AT命令的C语言编程
- git从本地添加项目到远程仓库
- (转)一些个人感悟(2008)
- 计算机专硕可以考事业编吗,专硕考事业编制遇冷
- python代码实现卷积示意图快速制作
- python的cfg是什么模块_python操作cfg配置文件方式
- 基于FPGA的VGA时序控制器
- 15本经典金融投资著作
- 2020北大软微复试知识整理
- RecyclerView中播放视频
- WPARAM 与 LPARAM 参数的解析 [C#、WinAPI]
- 【王喆-推荐系统】评估篇-(task2)推荐模型评估指标