首先我们项目的定位是一个图片,音频为主体的分享应用,于是服务器对于大资源的存储有了常规数据库,nginx静态资源存储和对象存储服务的选型问题.常规数据库(如mysql)的业务存储不可避免的遇到服务器带宽问题和单点问题.于是我们选择了COS服务进行大对象存储,同时对于生成目录等用户关键信息进行云Redis存储并选择双机备份.项目开发,压测结束Redis只占用了2M内存空间,COS服务+CDN溯源提供了优秀的读写带宽和数据保持.
其次一开始我们两位后台开发同学对于架构的选型的第一目的其实是以”复杂装逼”为先,但是实际搭建过程中发现需要意识到每个组件选型的原因,因为每个组件的选型对于访问压力和安全都有可能有灾难性的错误,在具体架构图的体现上可能是”一粒老鼠屎”.因此我们转而明确我们需要什么样的服务器.阅读往年KM经验总结得到互联网服务器的核心在于可用容灾,简单点说要先解决每个服务的单点问题.举个项目过程中的接口例子:
我们COS的上传服务是客户端先向服务器请求一个临时Token而后利用这个临时Token存储,读取资源.由于COS不能设计给CVM的回调函数,于是基本设计是通过两条请求分离1. 取token和路径, 2. 校验,存Redis数据库当中.在这个流程中一开始我们的单机设计是在本地对于key做一个缓存,然后再确认请求中读取缓存;通过超时删除策略清理缓存池.这样的策略当接入多机时候需要cookie/session保持对单机的服务连接,接入弹性伸缩时候就完全不可用了.因此重构代码,将缓存信息存储到Redis里面,而后读取其中信息.这样配置了服务的开机自启之后就可以有效的进行弹性伸缩的业务可用性保证.总而言之服务器应该作为无状态服务,对于每个请求原子化操作.
进一步服务的解耦是在这次mini项目中理解的部分.对于python的sdk/api/算法实现,我们服务端最初解决的策略有二:
使用go-python包进行封装调用(如轨迹识别算法调用了opencv,go的opencv很不好用) hack python版本的sdk,模拟Python服务进行发包(如向cam申请cos的临时秘钥) 相对应的,遇到了以下问题:
用go-python包python内部业务出错难以定位,文档不全,内部业务更新需要宕机整个业务系统 hack python sdk相当于把接口直接暴露在公网,安全问题和稳定性有待考究 于是我们分离核心模块与算法模块到内部服务器,类似外网负载均衡业务,接入内网负载均衡服务,内网弹性伸缩组通过内网ip调用算法弹性伸缩组,这样golang的代码看起来优雅(没有wrap和hack)许多,也进一步保证了安全性.另外可以对于不同服务设计不同弹性伸缩策略(业务服务设计CPU监控,图像算法服务设计内存监控)来进行伸缩组操作.
另外值得一提有三点:
备案域名申请https或者申请TLog(CLS)这样的内测服务周期对于mini项目而言压力较大,与具体业务相关性较小,需要尽早开始流程. AI时代云服务很多组件附带提供了内容安全(如CDN鉴黄,语音SDK敏感词屏蔽),DDOS服务,可以减轻业务模块接入这些服务的压力,也就是说前期SDK功能,调用的调研对于技术选型和设计十分重要. 镜像服务是一个很不错的免费功能,在这次mini项目中我们要求使用tlinux进行业务部署和实现,其中opencv,golang组件的安装可以短期(1h)租用高性能服务来完成,销毁服务之前花十分钟进行镜像备份就可以新建服务器时候选择自定义镜像定义.另一方面负载均衡,弹性伸缩组的请求对于镜像的更新要求更高;除了设置启动服务之外,我们还可以通过取出单个主机更新代码->制作镜像重启->更新弹性伸缩镜像->分批重装其他服务 这样的流程可以不关闭服务的时候修复代码,上线功能. 反思 内网模块:当时设计两层服务器模块其实是因为sdk和图像包对于golang友好度很差..虽然hack了golang版本的python cos sdk,但是测试过程中发现及其不稳定,于是换回了原生的python服务.但是内网的模块应该更加微服务,我当时的实现是每台主机flask路由到两个业务(sdk+opencv), 但是这两个模块应该进一步解耦,原因在于sdk交互是需要外网ip的,尽管设置了端口防火墙,但是运维成本比解耦高很多. 内网CLB: 图像识别和调用外部sdk的网络耗时会使得整个系统的qps变低,应该加入CMQ进行限流削锋. 云Redis存储: 腾讯云redis不支持跨地,也就是没有云sql的异地容灾. COS存储: 权限管理由于hack的sdk不稳定,做的不够细致.另外没有考虑利用归档存储做冷热分离. 监控虽然接入了内测的tlog,但是后期开发量还是很大,包括对于客户端日志的收集,邮件通知服务 (TODO)WNS接入: 对于腾讯云部署的业务是免费的~~ 准备移植小程序,用nodejs做后端试试。