zoukankan      html  css  js  c++  java
  • 不是所有的大作业都叫微信抢票大作业

      为时四周的微信抢票大作业终于接近尾声,回首这段时间,真是感慨万千。不是所有的大作业都是微信抢票大作业,能够让人同时体验产品经理、开发工程师、测试工程师、运维工程师四个角色。经过了微信抢票大作业的洗礼,才知道之前对老师上课讲的内容只是一知半解,只有实践才能出真知。

    一、搞开发

      讲道理,这次大作业的开发工作其实不是很多。因为框架设计的很好,接口也介绍的很详细,只需要按部就班填坑就可以达到基本要求了。

      但是既然助教上课都提到了几个优化方案,比如内存型数据库,异步队列等,好奇如我怎能不试呢。于是就开始给自己挖坑,然后再吭哧吭哧填坑。。。缓存机制和异步队列的设计实现文档里都有提及,不再赘述了(毕竟说起来真是好麻烦,一把辛酸泪。。。)

      就讲一个很有趣的debug经历吧:

     1         with transaction.atomic():
     2             try:
     3                 if is_key:
     4                     act = Activity.objects.select_for_update().get(key=key_or_id)
     5                 else:
     6                     act = Activity.objects.select_for_update().get(id=key_or_id)
     7                 ticket = Ticket.objects.select_for_update().get(student_id=self.user.student_id, activity_id=act.id)
     8                 reply_text = {
     9                     'Title': self.get_message('ticket_title', act_name=act.name),
    10                     'Description': self.get_message('ticket_description', act_description=act.description),
    11                     'Url': self.url_ticket(ticket.unique_id)
    12                 }
    13                 is_reply_text = False
    14             except Activity.DoesNotExist:
    15                 reply_text = "活动不存在"
    16             except Ticket.DoesNotExist:
    17                 if act.book_start > timezone.now():
    18                     reply_text = "抢票尚未开始"
    19                 elif act.book_end < timezone.now():
    20                     reply_text = "抢票已经结束"
    21                 elif act.remain_tickets <= 0:
    22                     reply_text = "对不起,票已经被抢光啦"
    23                 else:
    24                     act.remain_tickets -= 1
    25                     act.save()
    26                     t = Ticket(student_id=self.user.student_id,
    27                                activity_id=act.id,
    28                                unique_id=gen_unique_id(self.user.student_id, act.id),
    29                                status=Ticket.STATUS_VALID)
    30                     t.save()
    31                     reply_text = "抢票成功,请稍后查看抢票结果"
    32                     is_success = True
    33         if is_success:
    34             task_update_activity_in_cache.delay(act.id)

      这是我抢票部分的代码,大概就是在锁内读取数据库,更新数据库,在锁外以异步队列更新缓存。

     1 @task
     2 def task_update_activity_in_cache(id):
     4     acts = Activity.objects.filter(id=id)
     5     print(acts[0].remain_tickets)
     6     print(timezone.now())
     7     if not acts:
     8         return
     9     if acts.count() > 1:
    10         raise DbError("duplicated id")
    11     activity = acts[0]
    12     cache.set(querykey_of_act('id', activity.id), activity)
    13     cache.set(querykey_of_act('key', activity.key), activity)

      这是我的task_update_activity_in_cache。设想中如果抢到票,会先更新数据库该活动的余票数,然后我异步更新缓存的时候,从数据库中读取这个活动,更新缓存中该活动的余票数。然而实际上我抢了票之后,再查看活动详情,余票数并没有-1。一开始我以为是celery没配好,没执行这个任务,但是后来我加了第五行后,控制台打印了信息,而且就是原来的余票数,并没有减一。查看数据库,余票数又是更新了的,so interesting...

      在我一筹莫展的时候,突然有一次,异步任务成功更新了缓存,这就更加玄学了。。。突然我灵机一动,决定分别在两个函数里打印save()操作和filter()操作的时间,发现当两个时间只相差0.0001秒的时候,filter()从数据库读取的还是原来的值,当时间差大一点之后,filter()从数据库读取的就是新值。所以。。。续一秒,解决问题:)

      唯二的遗憾就是没能用异步队列实现定时更新菜单的操作,以及部署时没能以deamon的方式运行celery,原因都是实在配不起来,查遍文档也配不起来,搜遍谷歌也配不起来,只好选择放弃T T

    二、配环境

      我对配环境这件事的唯一印象就是:只要有大作业就要配环境,只要配环境就会头疼,配着配着就不知道自己配到哪里了,查遍谷歌度娘结果全是骗人的。但是这次大作业不仅要配环境,而且还要配很多很多的环境,而且不仅要配开发环境,还要配生产环境。也许是做好了长期抗战的心理准备,这次反而很淡定,也很顺利。现在我觉得,配环境这件事也不是那么枯燥乏味的。心得体会就是:配环境最重要的是要动脑子,要明白基本的工作原理,一定一定要查文档,一定一定要好好学习英语,一定一定不要迷信谷歌度娘,一定一定要看比较新的answer。。。

    三、做测试

      部署完成之后,就可以开始做性能测试。性能测试我使用了jmeter进行压测。性能测试必须是在功能正确的基础上进行测试。所以从我准备开始性能测试到我真正开始性能测试,花了整整一天时间debug。。。因为是学生党,经费有限,所以选了一个配置最低的服务器,刚开始测的时候在并发数为200的时候就有超过10%的错误率,平均响应时间为几万毫秒。感觉这种错误率实在是太可怕了,所以又对抢票和缓存的代码进行重构,效果也只是将平均响应时间缩短了几百毫秒,错误率并没有下降。

      一筹莫展的时候,我突然想到可以用jmeter的结果分析树看看都是哪里出了问题,然后我发现错误都是no http response,也就是请求超时。说明错误率高并不是程序的问题,于是花了20块钱将服务器的带宽从1mbps调为2mbps,能承受的最大并发数一下子提高到500,零错误率,平均响应时间几百毫秒。一颗赛艇!!!

      当并发数达到600时,又开始有错误。立刻查看响应,是nginx发了502 BAD GATEWAY。说明nginx在转发请求之后迟迟得不到响应,也就是uwsgi的问题,为了进一步提高性能,我又提高了uwsgi的listen参数,但是由于系统net.core.somaxconn为128,所以这个参数只能到128。重新测试,能承受的并发量提高到700。因为服务器配置确实比较低,所以基本上达到瓶颈了。

    总结下来,虽然最后仍有一些遗憾,但是成功完成了如此challenging的大作业,还是很开心的。

  • 相关阅读:
    How To : OCR / Vote disk Maintenance Operations: (ADD/REMOVE/REPLACE/MOVE)
    循序渐进解读Oracle AWR性能分析报告
    为11gR2 Grid Infrastructure增加新的public网络
    12C开始oracle实现了SCALABLE LGWR多进程并行写redo log
    万字详解Oracle架构、原理、进程,学会世间再无复杂架构
    PowerShell 连接SQL Server 数据库
    Oracle 性能分析与诊断|跟踪诊断&优化SQL 语句
    安装oracle 11gr2 rac on solaris
    oracle EOS
    K8S集群认证之RBAC
  • 原文地址:https://www.cnblogs.com/zizhao/p/6030213.html
Copyright © 2011-2022 走看看