介绍go proxy sever的实现原理以及athens是如何实现的。

  前言
  
    上一篇文章介绍了athens私服的安装以及vgo download protocol的简要介绍。本文着重介绍go proxy sever的实现原理以及athens是如何实现的。
  
  go get原理
  
    当GOPROXY没有设置的时候,通过-x参数,可以看到go get获取module的详细过程。
  
  [eventer@localhost]# go get -x github.com/gin-gonic/[email protected]
  
    对于git来说,go依赖于git命令,通过git命令的组合获取module库的元数据及各版本源码包。而其中的第一步在于向源码仓库获取module的元数据。
  
  [eventer@localhost]# curl -sSL 'https://swtch.com/testmod?go-get=1'
  
  
  
  
  
  Nothing to see here.
  
    go cli根据返回的元数据从指定的地址获取module,说白了就是在本地执行git的各个命令,跟大家平时从源码库拿代码的过程差不多一样。
  
    当GOPROXY被设置的时候,按照《Defining Go Modules》一文中关于proxy server的定义,情况发生了一些变化,而这也正是athens所要实现的内容。
  
  athens概述&流程
  
    按照vgo download protocol中的定义,go proxy server是一个高效、可用、安全,且遵循module格式标准、下载协议、本地缓存以及支持按需下载的代理服务。显然,这是一个构件系统的定义,而athens也正是朝着这个目标实现的。
  
    但由于go get与go mod命令的设定及其主动获取这些特征,使得其与java阵营的nexus、jfrog不同。java的库是由开发者主动deploy到公有仓库或私有仓库中,程序构建的时候再根据pom或gradle配置文件的声明从仓库获取指定的package。而go则省略了第一步,直接在构建的时候由go get或go mod根据go.mod文件的声明从源码库中获取module。因而这就意味着athens首先必须实现从当前流行的源码库中获取公开、私有的module,比如github、gitlab、bitbuckt;又要考虑如何从私有的源码库中获取module。
  
    所以显而易见,athens需要实现的功能列表如下:
  
  功能项    性质    功能说明
  
  下载协议    必需    4个必需接口,2个可选接口
  
  本地存储    必需    module存储方式,本地磁盘or内存。athens都支持, 可配置
  
  云端存储    增强    module存储方式,支持gcp、minio、mongo、s3、AzureBlob,可配置
  
  公仓用户认证    必需    github token
  
  私仓用户认证    必需    SVN、Bazaar、Bitbucket、github、gitlab
  
  版本控制    增强    提供方案控制哪些module的哪些版本使用代理、是否可用等
  
  日志跟踪    增强    使用opencensus实现
  
  并发控制    增强    多个并发请求同一个module,处理第一个请求,后续请求等待并获取结果
  
  健康检测    增强    实现服务状态接口
  
  管理功能    增加    实现查询module若干接口
  
    那么按照预想,go get指令的流程如下:
  
  image
  
    而再次获取同一个版本的module时,流程如下:
  
  image
  
    通过代理取包的过程其实也很简单。athens按照约定,提供了4个或6个接口供go get指令使用。当GOPROXY被设置时,go get切换至新流程,如下(goproxy.io是proxy server):
  
  https://www.yunyougj.cn goproxy.io/github.com/gin-gonic/gin/@v/list
  
  https://www.chenhaiyulp.cn goproxy.io/github.com/gin-gonic/gin/@v/v1.3.0.info
  
  https://www.dayuzaixianyL.cn goproxy.io/github.com/gin-gonic/gin/@v/v1.3.0.mod
  
  https://www.365soke.com goproxy.io/github.com/gin-gonic/gin/@v/v1.3.0.zip
  
    这组协议对应至本地文件系统的一组目录$GOPATH/pkg/mod/cache/download,这里保存了对应上述4个接口的文件,这4个文件内容可以到这个目录下自行查看,它们的格式即是协议描述的内容。
  
  接口实现
  
    athens本身是一个web服务,采用gorilla框架实现。main.go位于cmd/proxy包下,关键代码读取配置文件,然后根据配置文件参数初始化程序。
  
  //读入配置文件
  
  conf, err := config.Load(*configFile)
  
  if err != nil {
  
  log.Fatalf("could not load config file: %v", err)
  
  }
  
  //根据配置初始化程序
  
  handler, err := actions.App(conf)
  
  if err != nil {
  
  log.Fatal(err)
  
  }
  
    在app.go文件中,配置了storage、github token、NETRCPath、HGRCPath、log、FilterFile、路由注册。auth.go中的代码将NETRCPath、HGRCPath声明的文件内容转写到当前用户home目录下的预定位置;而关键的路由注册,则由下面的代码完成,调用的是app_proxy.go中的addProxyRoutes方法。
  
  if err := addProxyRoutes(
  
  proxyRouter,
  
  store,
  
  lggr,
  
  conf,
  
  ); err != nil {
  
  err = fmt.Errorf(www.yunyouuyL.com"error adding proxy routes (%s)", err)
  
  return nil, err
  
  }
  
    addProxyRoutes方法注册了的路由如下:
  
  路由    说明
  
  /    首页
  
  /healthz    健康检测
  
  /readyz    -
  
  /version    athens版本
  
  /catalog    所有module列表
  
    在这之后,定义了GoGetFetter用于处理module的下载、upstream vcs监听器、并发控制器、vgo download protocol协议实现。
  
  handlerOpts := &download.HandlerOpts{Protocol: dp, Logger: l}
  
  //RegisterHanlders方法注册了list、www.tianscpt.com version.info、version.mod、version.zip这4个接口的路由
  
  download.RegisterHandlers(r, handlerOpts)
  
    athens包说明:
  
  包    用途    描述
  
  pkg/config    配置文件对应实体    存取配置文件参数
  
  pkg/download/    vgo download protocol协议实现    核心入口
  
  pkg/errors    errors统一定义及堆栈跟踪    良好的错误设计,可以快速定位到出错的包、方法
  
  pkg/log    logrus日志框架集成    -
  
  pkg/middleware    中间件    module缓存、日志、请求验证、module获取策略
  
  pkg/module    module获取策略、仓库源码获取、zip获取实现    -
  
  pkg/observ    日志及统计数据输出    datadog
  
  pkg/paths    module path解析工具    -
  
  pkg/stash    module获取与存储包装类及module并发请求控制    -
  
  pkg/storage    存储实现    包括内存、本地磁盘、数据库(mongodb)、文件系统(afero抽象文件系统)、云存储(s3,gcp,minio)等
  
    module获取策略:
  
  项    定义    说明
  
  module.Exclude    排除    忽略对指定包的请求
  
  module.Include    -    不走代理,按常规模式获取包,本地私仓使用此配置
  
  module.Direct    -    走代理
  
    获取module流程图:
  
  获取module流程图
  
    在athens的实现中,各个包之间的调用关系如下:
  
  包调用关系
  
    GET baseURL/module/@v/list时序图:
  
  GET baseURL/module/@v/list时序图
  
    GET baseURL/module/@v/version.info时序图:
  
  GET baseURL/module/@v/version.info时序图
  
  baseURL/module/@v/version.mod与baseURL/module/@v/version.zip的过程与baseURL/module/@v/version.info一致,只是调用不同的实现而已。

你可能感兴趣的:(介绍go proxy sever的实现原理以及athens是如何实现的。)