一探B站后台架构, 他山之石, 何以攻玉? -- 仅从一个一线Golang开发者的角度谈B站4.22代码

七月天_5092 · 2019-04-25 07:54:12 · 19449 次点击 · 预计阅读时间 5 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2019-04-25 07:54:12 的文章,其中的信息可能已经有所发展或是发生改变。

4月22日, B站部分后台源代码因为某愤怒的员工, 被上传至Github. 本文我们不讨论安全, 法律 (根据代码漏洞, 去恶意攻击或者获利是违法的! 我们工作时也要注意代码安全), 我仅从开发者的角度谈谈, 这份代码我们能学到什么? B站Golang生态建设, 代码规范, 工具建设, 技术栈选择, 对于Go在部门或公司的推广又有哪些值得借鉴?

首先必须得说, B站这份代码整体还是不错的, 不是说组件或者基础库多么的厉害, 而是从整体目录分布, 业务代码分布, API易用性, 业务代码风格, 工具的统一, 上手难度上来评价.
这里是一个小小的总结.

  1. 约329个Go服务, 历史约170人左右贡献过Go代码.
  2. 代码和目录规范性比较好, 代码生成工具建设比较好, 大家可以借鉴一下.
  3. 对于一个Golang开发者来说, 入职B站, 我觉得大概2-3天就可以copy&&paste开始贡献业务代码了. 其他语言开发者, 3-4天吧, 因为学习Golang花一天.
  4. B站Go不依赖CGO, 业务代码可以在windows编译通过! 启动!
  5. 组件基本是基于开源组件封装.
  6. RPC基于grpc封装, 协议编码为proto, 没有我们通常那样的包头.
  7. 服务注册与发现已经包装在RPC中. 注册使用自研的discovery, 基于类似url的方式去注册和寻址.
  8. 数据存储多使用memcache, redis和DB.
  9. hbase也使用比较多. 用于鉴权, 用户数据存储. 对于一些kv数据, 外部没有支持冷热分离的kv存储, hbase是一个非常好的选择: 基于HDFS, 热数据加载到内存, 列式存储, 强一致, 可配置副本数.
  10. 消息队列为使用基于kakfa, 实现了redis协议的databus.
  11. 小文件存储: B站自己实现的bfs
  12. 监控上报使用的是prometheus, 对于中小公司, 没法建设自己的监控组件, prometheus是很不错的选择.
  13. 简单浏览了下, 这份代码在SQL上没有注入风险. 生产环境的配置并没有在这份代码中. 一个合格的开发者, 即使所有源码流出去, 也不会对系统造成任何危害.
  14. 不过B站的代码似乎打点监控做的不是很多(可能没有太多的去强调?)

可以看出B站有一定的技术建设能力, 能够基于开源技术栈做封装和改进, 所选技术栈适合中小型公司业务. 技术总监毛剑水平的确挺不错, 下面会给出两篇B站在Gopher China上的分享.
详细请看下文

PS: 学习完代码已删除, 不要问我要代码哈.

[TOC]

哔哩哔哩的Go微服务实战
文章上: https://mp.weixin.qq.com/s/bPFUGQDZCnt2aeIf7JI2cQ (主要讲B站从PHP, Java转为Go微服务之路)
文章下: https://mp.weixin.qq.com/s/4uA6iE7HC_SAfdIATAdrrA (主要讲B站中间件建设情况)
视频: https://www.bilibili.com/video/av29079011

以上两篇(上面后两篇)是B站公开分享的Go微服务实战, 上文讲B站的微服务演进, 下文讲B站的中间件建设.
本文中很多情况的确和本文中一致. 详细可参考这两篇文章.

目录结构及整体情况

通过main.go启动文件统计, 整体约329个Go服务. 有170人左右贡献过Go代码.

整体目录结构

admin是管理后台的服务, service是提供RPC内部服务, job是处理消息队列的服务, interface目录是对外http的服务.
其中admin目录下54个, infra目录下5个基础组件服务, interface下77个, job目录下80个, service目录下113个.


整理目录结构

可以看出来B站Go后台代码管理使用的是一个大仓库的方式(从源码目录整齐度以及大仓库的README来看, 应该是这样的, 当然还有个东西叫git submodule). 这种方式有好处也有坏处.

  1. 上手很快, 所有的库, 依赖, 业务都在一个仓库中, 下载了就有提示, 马上开始撸代码.
  2. 后期版本管理变得很混乱. 分支开发也很重.

我在前公司也有这种情况, 前人把大概某20个服务放在一个仓库中, 后续的git log简直没法看. 幸好后面大家没这么做了.

服务目录结构

服务目录结构
cmd: 放main.go和配置文件, 作为启动入口
conf: 放配置文件对应的golang struct, 使用的是toml
model: 放结构体, 比如Http参数转换用的struct, DB存储对应的struct, 各层之间传递用的struct
dao: data access object, 数据库访问方法, redis, memcache访问方法, 还有一些RPC调用也放在这里面
http: 提供http服务, 主要是提供协议转换, 聚合. 逻辑还是再service层做.
service: 对于后端服务来说, 该目录提供服务的实现, 对于http服务, 该目录提供http服务的实现.

目录规范性

所有的服务均遵守该目录结构. model层放VO, DO等, dao层用于数据层封装, 隔离本服务的领域逻辑与外部数据. http层提供协议转换. service实现具体逻辑.
比较像Java开发的模式, 可能在公司很多人不是很喜欢这样复杂的目录, 喜欢什么都放在一个目录下.
不过这样的分目录是一种比较好的实践. 各层分的清清楚楚, 一个服务从1个接口到10个接口, 都比较清晰. 对于服务改动来说,也比较好聚焦于某一层.

生成工具的重要性

目录做到规范性, 服务维护, 其他人接手也容易多了. 然而大家都是有各自习惯, 每个人都喜欢偷懒, 靠规范, 靠说教来使得程序员保持目录规范, 实践证明是不可能的. 所以得靠生成工具.你给程序员生成好的代码目录和模式, 99%的人是不会去改的...能把业务逻辑实现了, 还管其他的干啥?

此份代码的300多个服务, 目录都是一致的, 不管是http服务, 还是接收消息队列的服务, 还是后台service. 同时service包下, http包下的代码流程都基本一致, rpc调用方式一致, 都是靠生成工具来实现.

B站Golang技术栈分析

技术栈 技术选型 参考链接
RPC 基于grpc封装的warden框架, 已开源 https://github.com/bilibili/kratos
HTTP框架 基于gin封装的blade master框架, 已开源 同上
服务注册与发现 初期为zk, 后面逐步改为参考Spring Cloud体系Eureka自研的discovery 已开源 https://github.com/bilibili/discovery
存储 DB, redis, memcache, hbase存储一些用户kv信息和历史流水, 已封装好库 library/database/ client库已开源 https://github.com/bilibili/kratos
搜索 B站视频, 用户, 历史记录等使用es搜索, 客户端已封装在基础库中 library/database/elastic
小文件存储 毛剑个人研发的bfs, 已开源. https://www.toutiao.com/i6272104949560115714/ https://github.com/Terry-Mao/bfs
消息队列 基于kafka封装的databus
log 基于uber的zap封装的日志框架
配置及配置中心 支持从环境变量读取配置, 从toml中解析配置, 支持远程配置中心(自研, mysql存储, 本地落地,http协议, long poll, 客户端有更新事件, 类似于携程开源的Apollo)
监控 使用开源的prometheus, 框架和库(sql, redis, hbase等)中已预埋计数点和时间统计点, 同时也可以在业务逻辑中打点. library/stat/stat.go
trace trace似乎是基于agent的方式, 使用unix domain socket进行传送, 框架和库已预埋点. library/net/trace.go
研发流程管理 TAPD, 哈哈, 有相关的tapd struct信息

其中RPC, HTTP框架, 数据访问的一些库封装, 包括生成工具, 均以kratos项目在github开源了(https://github.com/bilibili/kratos Kratos是bilibili开源的一套Go微服务框架,包含大量微服务相关框架及工具)

B站目前使用及封装的中间件的详细介绍在Gopher China 2017 B站的分享有提到原理和使用情况.
https://mp.weixin.qq.com/s/4uA6iE7HC_SAfdIATAdrrA
bfs介绍
https://www.jianshu.com/p/923917220d23
B站运维体系发展
https://myslide.cn/slides/3840

总结

简单分析了下B站的代码风格和后台架构, 目录规范性, 工具建设均做的不错, 其中代码生成工具做的很好, http服务, 后台grpc服务,均可通过proto生成(目前now也是这样做的), 也有使用go ast进行生成的工具(大家可以参考一下).
中间件方面, 技术选型大部分为一些目前业界比较实用和流行的开源组件, 进行了一些封装, 比较适合员工上手. 同时像配置中心, 小文件存储, 为自研. 全套解决方案比较关键路径均开源.
可以看出B站有一定的技术建设能力. 技术选型比较符合中小型公司的实际情况.

对于我们而言, 可以借鉴一下, 完善生成工具, 提高API的易用性, 降低入门门槛, 根据业务选用适合组件.


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

19449 次点击  ∙  5 赞  
加入收藏 微博
5 回复  |  直到 2019-07-09 16:17:56
CarlJi
CarlJi · #1 · 6年之前

看起来编译运行这块,使用了google的bazel工具。

JiaLiangoooo
JiaLiangoooo · #2 · 6年之前

hbase里面有鉴权吗?

kehuai007
kehuai007 · #3 · 6年之前

辛亏fork了一份哈哈哈哈

Justin19960208
Justin19960208 · #4 · 6年之前

自动化运维程度应该比较高。 当时接触到一个方案:

接入层:Nginx
API网关:自己撸的代码根据 url 路由
服务发现治理:consul
消息队列:NATS
数据库:redis + MySQL 使用的 gorm

golang 在微服务上的应用越来越广泛了,组件也趋于成熟。

fuckaholic
fuckaholic · #5 · 6年之前

以fork~~ 拜读中~

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传