您的位置:首页 > 其它

12306这样的超大规模实时事务系统到底应该怎么设计?其实不难

2015-01-17 13:31 716 查看
12306这样的超大规模实时事务系统到底应该怎么设计?

%

听说阿里要帮助12306重新设计订票系统,不过12306这个系统就真有这么难吗?是那些写软件的没有好好思考这个问题吧?

显然,12306这个系统不同于一般的关系数据库,做系统架构设计必须考虑实际的应用业务流程和数据本身的性质才行。

这么说吧,我不觉得这个问题有多困难,为了设计好这个系统,下面的几条是需要考虑的:

1、假设系统必须允许1亿人同时抢票,其实就算10亿人也没什么关系,我就不信系统不能水平扩展。那也就意味着,假如是一台超级单核CPU机器的话,每个事务平均就必须在1/100000000秒内完成,1/10000毫秒。而普通中等CPU机器假设能在10毫秒内完成的话,则这个性能容量需要通过水平扩展和垂直扩展扩大10万倍。

2、有了前面的理论上限分析,剩下来的事情就好办了:我们如何做到这一点?

2.1 先垂直扩展,使得服务器主机的性能提高10倍,这应该是可以做到的;

2.2 使用内存数据库及内存计算,不应该要求事务需要同步的磁盘IO,但可以像大部分NoSQL数据库引擎那样,使用WAL日志异步同步到磁盘

当然,磁盘本身应该是SSD的,毋庸置疑。

2.3 网络的分流

在与核心服务器的网络通信上,不应该使用每个事务一个TCP连接,显然可以使用加密的TCP连接,并在这一条连接上做所有的事情。

或者可以使用类似于UDP的数据报,每个订票请求封装成一个大的数据包。

当前余票查询可能不能做到实时更新,但至少可以保证1分钟或30秒更新一次,这只是指的繁忙时候,不忙时候不需要这么做。

在实际的UI交互体验中,可以做成“悲观视图”,也就是说,用户如果看到又余票,并且他在30秒内手工下了订单,那么系统应该保证他一定能够买到票。当然,也可以修改UI接口,使用类似于“智能代理”的自动规则引擎,这样,可以直接订票无须先查询。毕竟常规的先读再写类型的事务实际上导致了读锁,潜在地降低了并发程序。

网络数据包应该可以在内核级别负载均衡地路由到不同的CPU核,这样,假如每个机器是16核的,又可以进一步将扩展性提高了10倍。

2.4 避免大并发情况下的加锁导致的开销

七牛云的许式伟(使用Go语言作为服务器后端开发语言)都认为加锁是不可避免的,真的是这样吗?

事实上,可以通过更细粒度的物化视图数据库来降低不必要的全局锁。比方来说,把每趟车次乘以相邻两站作为做小操作单位,而不是对一个全局的“票数”进行加减读写操作。

也就是说,假设某人购票A-->B地,中间经过C、D站,则数据库中存在A->C、C->D、D->B共3个数据项(每个座位都是一个单独的数据项),而整个订票事务通过对这些数据项进行顺序的无锁原子操作。注意,购票的座位不应该随机分配,随机分配一般是伪随机的,在大并发的情况下必然有很大的冲突概率。

在这种粒度上,基本上没有由于加锁设计导致的开销

2.5 现在还有1000倍的水平扩展系数。这时候就要考虑分布式系统负载均衡了

首先,考虑不同的订票终端,12306系统应该部署成层次式的拓扑结构,其中,更上一层(性能更好、与核心服务器网络连接更快)的事务处理终端可以直接为下一层提供事务代理。在这个级别,我仍然考虑整个系统是集中式的,但对于某些地方非核心交通网络,可以完全下发到某一下层来全权处理。

其次,可以引入一定的消息队列,而不是同步请求,Lock-free队列用于消息队列是最常见的用法,队列的数据结构存储可以将瞬间的并发造成的网络、内存开销降低到最小程序,前提是这个队列不是基于全局锁(也就是信号量)来实现的。

关于12306的核心设计,我觉得说到这里就可以了。关键是我之前所说的“物化视图”,或者称之为“最小化事务操作数据项”的核心概念。作为通用的关系数据库技术可能不能满足这个需要。但也许可以通过定制MySQL的数据库存储引擎来说到这一点。

在这个“物化视图”,或者称之为“最小化事务操作数据项”的技术基础上,使用顺序的Lock-free测试并设置,基本上不会有传统的MutexLock保护共享变量读写技术所带来的并发访问冲突。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐