对于高并发的一些思考
夜宵时的思考
刚刚排错了一个小时,终于搞定了,奖励自己一碗泡面,在等微波炉前等待的时候想了挺多事的。
并发似乎是所有程序员的噩梦,也是所有程序员的“粮食”,如果计算机不支持并发,世界上的Error Log应该能少一半,同时程序员的”魔力“也少了三分。
所谓的秒杀系统,其实是一种泛指,代表着多并发,高可用系统。为什么说至今没有一个类似Spring一样的框架,能在并发领域脱颖而出呢,因为每个领域,各个场景的情况不一样,每个解决并发的方案,脱离了实际,就没了价值。
面熟了,我依旧在思考,如果有可能的话,我会怎么去实现一个高并发的方案呢。
以我最近在写的“秒杀”系统为例,一群人,同一时间,抢一个东西。我能怎么去优化呢?
从数据库入手:减少数据库操作
数据库在哪?磁盘。CPU的速度和磁盘的速度差几倍?差不多就像马云的赚钱速度和我的赚钱速度的差距吧。因此,必须减少对数据库的访问,能少则少。
还有另一个原因,如果每多一次对数据库的操作,则高并发导致的数据不一致的风险也高了一分。(脏读,幻读等)如何解决这个问题?缓存呗,加锁呗。这个是老生常谈了,对于缓存的思考,后面再讲。
数据库也要划分:订单DB,支付DB。尽量不要在一台DB上布置多个表对象。
此外,还有一个概率,是我上数据库课的时候,想到的一个方案:
可不可以设两台机器,上面的数据库是同一个(双点),一台负责读,一台负责写?这样既解决了备份问题,有解决了IO切换问题。
从用户入手:增加答题环节
这个解决方案有点缺德,同时也必不可少,除了能拦截刷单机器人,还能把激增的用户量分流了,就像大坝一样,一下子拦住了大水,再慢慢放出去。但是,不能把题目设置太偏僻(如早期的12306)。
我今天写“秒杀”功能的代码时,每次写到SQL语句,我都在想,这有必要吗?
还真没必要!复现一下,当我写完“购买”功能后,正常思路是什么?查询库存?这就对数据库一次操作了。高级点的做法是把“库存数据”放在缓存当中,每次购买时查询。
再高级点的做法是防患于未然,当我在对用户“分流”时,我只放等于库存数的请求,然后关闭接口。后面的人也不用查询数据库和缓存了,你们来晚了。
从系统入手:系统分级
这里的系统指的是根据功能划分的系统,在“秒杀”系统中,什么系统的等级最高?支付系统,然后是优惠券系统等。我们可以吧支付功能系统的等级设置为最高,在资源不够时,优先给等级高的系统分配。不要让不重要的系统拖慢了高等级系统,这个做法带来的弊害还被人“津津乐道”,就是去年双十一的时候,无法更改收货地址。(退款系统也无法运行)
而且,不要让高等级系统去依赖低等级系统,这样就自相矛盾了。
说明这个做法在业内已经是一个标准了,其实解决高并发,就是取舍。
从数据入手:提前布局
还是双十一为例:你是不是会在双十一前一个月就开始物色你的猎物?
然后加入购物车。对了,通过类似购物车的系统,后台能知道有哪些东西是“热点数据”,然后对他们进行“优化”与”隔离“。
优化能理解,但是隔离是什么意思?
我们不能因为小部分商品的带来的请求而拖垮了大部分商品,因此最好对热销商品隔离,美女们抢你们的五折化妆品,不要打扰到我抢一折咖啡。
还有优惠卷等,这些其实都是可以提前计算的,没必要浪费并发时的计算资源,大多数人都是在购物车计算完最终价格,然后掐着时间点击购买。
因此,优惠券系统在双十一的时候,并没有造成多大的性能损失。反而变成了一个数学难题。
从缓存入手:集群与划分
在高并发的世界里,缓存就是金钱。集群就是军队。
像库存这样的重要数据,完全值得划分出一块缓存集群专门供他使用。
像支付系统这样大佬,也完全值得划分一块集群给他。
缓存集群有什么好处?便于维护,好打理,好定制。可以根据要处理的数据的特点,去定制和维护,比如处理库存数据的缓存,完全可以不支持范围查找。通过对商品的唯一ID进行HASH,直接定位到桶上。
再高层面点,对“缓存”进行hash。把每台机器当初一个桶,然后建造一个大型的hashMap。HashMap的检索速度,大家有目共睹。
从队列下手:服务排队
这里的服务,指的是库存服务,订单服务这种,我们可以在应用层进行排队,插队,比如库存服务优先。
暂时写到这吧,有点晚了。