前言

  上一篇文章介绍了athens私服的安装以及vgo download protocol的简要介绍。本文着重介绍go proxy sever的实现原理以及athens是如何实现的。

go get原理

  当GOPROXY没有设置的时候,通过-x参数,可以看到go get获取module的详细过程。

[eventer@localhost]# go get -x github.com/gin-gonic/gin@v1.3.0

  对于git来说,go依赖于git命令,通过git命令的组合获取module库的元数据及各版本源码包。而其中的第一步在于向源码仓库获取module的元数据。

[eventer@localhost]# curl -sSL 'https://swtch.com/testmod?go-get=1'
<!DOCTYPE html>
<meta name="go-import" content="swtch.com/testmod mod https://swtch.com/testmodproxy">
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指令的流程如下:

  而再次获取同一个版本的module时,流程如下:

  通过代理取包的过程其实也很简单。athens按照约定,提供了4个或6个接口供go get指令使用。当GOPROXY被设置时,go get切换至新流程,如下(goproxy.io是proxy server):

  1. https://goproxy.io/github.com/gin-gonic/gin/@v/list
  2. https://goproxy.io/github.com/gin-gonic/gin/@v/v1.3.0.info
  3. https://goproxy.io/github.com/gin-gonic/gin/@v/v1.3.0.mod
  4. https://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("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、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流程图


  在athens的实现中,各个包之间的调用关系如下:


  GET baseURL/module/@v/list时序图


  GET baseURL/module/@v/version.info时序图


baseURL/module/@v/version.mod与baseURL/module/@v/version.zip的过程与baseURL/module/@v/version.info一致,只是调用不同的实现而已。

欢迎关注个人公众号

不一样的go语言-athens源码概览的更多相关文章

  1. go语言nsq源码解读八 http.go、http_server.go

    这篇讲另两个文件http.go.http_server.go,这两个文件和第六讲go语言nsq源码解读六 tcp.go.tcp_server.go里的两个文件是相对应的.那两个文件用于处理tcp请求, ...

  2. (转)go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin

    转自:http://www.baiyuxiong.com/?p=886 ---------------------------------------------------------------- ...

  3. c语言memset源码

    c语言memset源码 一.用法 void *memset(void *s, int ch, size_t n);作用:将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的 ...

  4. spring源码概览

    阅读spring源码需要具备的基本技能: 1,设计模式(工厂模式,单例模式,代理模式,模板模式,观察者模式,装饰器模式,适配器模式) 2,数据结构和算法(栈,队列,树以及一些基本的算法) 3,反射(如 ...

  5. go语言nsq源码解读七 lookup_protocol_v1.go

    本篇将解读nsqlookup处理tcp请求的核心代码文件lookup_protocol_v1.go. 1234567891011121314151617181920212223242526272829 ...

  6. go语言nsq源码解读一-基本介绍

    简单介绍一下nsq. 参考 http://feilong.me/2013/05/nsq-realtime-message-processing-system 的介绍:NSQ是由知名短链接服务商bitl ...

  7. go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin

    nsqlookupd: 官方文档解释见:http://bitly.github.io/nsq/components/nsqlookupd.html 用官方话来讲是:nsqlookupd管理拓扑信息,客 ...

  8. go语言 nsq源码解读三 nsqlookupd源码nsqlookupd.go

    从本节开始,将逐步阅读nsq各模块的代码. 读一份代码,我的思路一般是: 1.了解用法,知道了怎么使用,对理解代码有宏观上有很大帮助. 2.了解各大模块的功能特点,同时再想想,如果让自己来实现这些模块 ...

  9. 网易2017校园招聘算法题c语言实现源码

    题目: 给定一个数组,除了一个数出现1次之外,其余数都出现3次.找出出现一次的数.如:{1, 2, 1, 2, 1, 2, 7}, 找出7. 格式: 第一行输入一个数n,代表数组的长度,接下来一行输入 ...

随机推荐

  1. Python爬虫进阶 | 多线程

    一.简介 为了提高爬虫程序效率,由于python解释器GIL,导致同一进程中即使有多个线程,实际上也只会有一个线程在运行,但通过request.get发送请求获取响应时有阻塞,所以采用了多线程依然可以 ...

  2. java代码操作Redis

    1.导入需要的pom依赖 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEn ...

  3. 23-ESP8266 SDK开发基础入门篇--编写Android TCP客户端 , 加入消息处理

    https://www.cnblogs.com/yangfengwu/p/11203546.html 先做接收消息 然后接着 public class MainActivity extends App ...

  4. 表单提交 curl和浏览器方式

    表单被提交时,每个表单域都会被Url编码之后才在被发送. 浏览器每次向服务器发送url时,会进行编码,然后web服务器再进行解码. 所以,理论上,curl模拟登陆时,所传参数都必须urlencode一 ...

  5. x64内核强删文件.

    目录 x64内核中强删文件的实现 一丶简介 1.步骤 2.Nt驱动代码 x64内核中强删文件的实现 一丶简介 说道删除文件.有各种各样的方法. 有ring3 也有ring0. 而且也有许多对抗的方法. ...

  6. mysql pi() 获取pi

    mysql> select pi(); +----------+ | pi() | +----------+ | 3.141593 | +----------+ row in set (0.00 ...

  7. MATLAB关闭科学计数法显示

  8. 欢迎来到地狱 WriteUp(2019暑假CTF第一周misc)

    目录 0707,0708,0709 题目地址:欢迎来到地狱 1.地狱伊始.jpg 1.5地狱之声.wav 2.第二层地狱.docx 3.快到终点了.zip 参考 0707,0708,0709 题目地址 ...

  9. mysql增删改查sql语句

    未经允许,禁止转载!!!未经允许,禁止转载!!! 创建表   create table 表名删除表    drop table 表名修改表名   rename table 旧表名 to 新表名字创建数 ...

  10. ip地址掩码和位数对应关系表、子网掩码、网络地址、主机地址-yellowcong

    本文链接:https://blog.csdn.net/yelllowcong/article/details/76736594ip的地址掩码,刚开始感觉特别蒙蔽,网掩码都是每段8位二进制,共32位,子 ...