介绍交易系统核心服务在可用性可靠性高性能上的一些思考
ET6工程化演进之路
提纲
1、模块介绍
2、以一笔交易例,贯穿调用链路
3、可用性、性能优化、代码可维护性 各举一例
4、展望未来
5、总结
关注点
- 安全 客户资产安全是第一要务
- 准确
- 稳定 系统稳定和业务连续性
- 高效 在以上基础上追求更高的业务处理能力
可用性/准确性
衡量可用性标准
可靠消息队列
ack = waitforall,isr 选举 数据冗余 防丢失 容错性 高吞吐量 低延迟
同步通信机制造成的阻塞,另一方面通过消息队列进行业务解耦。
mysql高并发下性能瓶颈,主从架构。
未来如果做清算,补偿等功能都无需侵入核心服务,可扩展性高
最大尝试,超时控制
本地数据库,正反向消息机制+定时任务(幂等),补单对账,终极兜底
一致性提升, 多副本冗余 可靠性和鲁棒性
业务并发问题
1)交易类型之间
2)手动触发跟自动触发之间
应对- 引入用户锁,同一个用户同一时刻只能执行一个事物
- 交易系统的所有订单是一个有序队列。不同的用户在同一时刻下单,也必须由定序系统确定先后顺序。冻结保证金.
Price 作为交易系统的血液
- 准确
- 顺序(全局)
- 完整(丢失情况)
- 实时(延迟情况)
- kafka 有序队列保证顺序
- 根据系统运行状况,动态丢弃报价,防止剥头皮(滑点),当然丢弃策略理论上是比较严格的,且可追溯的。
隔夜息
- 打包成kafka事物消息
充分充足的集成测试和压力测试:包括不限于单用户单品种,单用户多品种,多用户多品种,系统和手动交叉
性能优化
- 减少syscall
- decimal ,作为系统最重要数据类型 自研10x 于shopspring
- 日志异步
- 内存复用
- 底层热点函数去锁,zero malloc
- calc 并发优化,至今最大的性能优化 持仓单10倍增长
- sync.pool减少堆对象生成,时间轮来减少锁竞争,分段锁map
可维护性
- account
1 | //顶层 对外暴露 service抽象 |
- trade
1 | //模版模式vs面向过程 |
其他栗子:
throwBuffer 中 选项模式//pipeline
configer :symbol source session 静态数据 ,集成在同一个模块,对crud等功能抽象,对外提供的能力
- 其他隐性共识:
- defer清理资源
- 错误包装 error.Wrapping,业务场景上抛error 需要添加上下文,以便错误消息提供更多信息
- 不要panic
- 显式初始化
- 锁变量
- 全局变量要具有描述性,局部变量要短i,o,u
框架工具清单
xorm
sarama
redigo
govalidator
logrus/file-rotatelogs
golang-lru
计划开源自研工具:ringbuffer、decimal、gpool、gosafe、snow-short
gomonkey
goconvey
sentry-go
jaeger
gopsutil
ansible+jenkins
chaosBlade
etcd
elg / pg
展望未来
- 上图
总结
- 介绍了项目现有功能 并通过一笔交易介绍了主要业务流程
- 就像cap一样 不可能全都要,所以我们按关注点在开发中有所侧重
- 在服务可用性和准确性上 通过kafka解决服务拆分和性能问题,用户锁解决单用户并发问题
- 介绍了几个高收益的性能优化点
- 通过介绍项目中用到的几个设计模式,使项目尽可能跟高内聚低耦合沾边。