今天和人电话聊了很长的技术问题,人家是成都卧龙工作室的,技术应该是很行的,但是在几个问题上我们的见解不一。
一个单线程能不能形成几万的并发。
这个问题首先就是个错误的提法,换个说法:nginx是不是就可以达到几万的并发。
两个问题犯的是相同的错误。
所有的并发都是针对业务处理的,业务简单点,像对于一些静态网页的处理,或者是无IO的事务,单线程和nginx都是可以达到几万的并发的。
可是这兄弟对单线程能达到几万的并发还是表示不可想象。
前面一个单线程服务器博文就可以达到2W的并发,另外nginx的单进程模式其实就是单线程模式,对静态网页的处理轻松达到几W的并发。
另外一个问题就是服务器的架构。
服务器的的架构无非两种:
单线程事件模型,将事件与事务放在同一个线程中处理,用多进程方式进行负载分担,如nginx。
多线程模型,将事件与事务分隔开来,或者事件也分隔开来。
你能说上面的模型哪个好哪个不好么。
长期接触过搞服务器的人,各种各样的有,我发现经常有这样的一个情况,就是喜欢自我满足,比如,上次一个朋友硬说nginx比apache好,还从事件模型,缓存,架构上把nginx给我狠狠的补了一回课,结果我问了一句,你看过apache的代码么,你对apache了解多少。
如果有朋友坚持认为nginx比apache好的,无非是因为nginx的事件模型可以多路复用,那么负载,伸缩性,模块动态处理这些有没有了解过呢,有争议的朋友可以在评论里说说。
有人常用多线程模型,就觉得要比单线程好,觉得单线程的服务器很低级,对单线程的服务器嗤之以鼻,却又说不出让人信服的道理,我觉得人不能停留在一个既定的认识水平上,而应该去往深处探索,而不是为了工作而工作。
这样想来,卧龙的游戏服务器想必是个多线程模型。
回到正题,之前有篇架构博文里画了一个图,图中土黄色的管子代表高性能的模块,红色的管子代表低性能的模块,这个图可以明确什么是瓶颈,现在咱们再举个数据:
高性能的模块每秒处理能力为1W, 低性能的模块每秒处理能力为1K,如图
如果要让服务器的处理能力达到1W,先说说第二种模型,则业务层的线程至少要有10个,如图
而如果采用第一种模型,则通过分担负载的方式让每个进程的负载均匀降低,用10个进程就可以了,如图
这样看来,两种模型能干相同的事,还能说孰优孰劣么,只能说大家更熟悉哪一种模型了,可能第二种模型里涉及到线程的同步,互斥,然后内存的分配与管理上要复杂一些,从架构上来说,应该尽量避免这样的做法,因这无论从开发周期还是测试周期,都会延长,容易陷入一些复杂的应用场景中。
其实这两种模型我都经历过,前几年喜欢用第二种,设计过一些多线程的技术方案比如内存池,曾经以为这些很不错,自从上一个项目用了第一种方案后,就发现其实单线程的优点还是有很多的,人员的开发分工上也简单很多,架构逻辑、进程的控制、扩容管理、灾难恢复上都要简单很多。
这样想来,其实nginx选择这样的单纯线程其实不是并无道理的吧。
为什么我在这里主要讨论迭代式软件开发?本文在此抛开千篇一律的理论,拟就根据多年的实践,总结出一套比较务实、可操作性强的方法,以期望在有限的资源下确保软件质量得到较大保证。一家之见,纰漏之处还请大家多多指正。
迭代式软件开发模式简要流程如下:
上图绿色大框内,我们就称之为一个迭代周期。每一个迭代,都可以形成一个可交付的小版本。事实上,每一个迭代周期内,对于编码和测试也可以进行多次迭代。通过快速发布测试构建的方式,验证开发完成的新功能,再通过测试发现问题来驱动开发人员对软件进行修改完善,循环往复。即:根据开发情况有针对性地组织测试,根据测试结果反作用于开发人员去完善软件质量。以这种小步快跑的方式,经过若干测试构建后,软件质量可以在较短时间内达到稳定状态。
质量保证,需要系统性的方法。那么在迭代式开发的各个阶段,都需要怎样的措施呢?
1)需求
这个阶段的主要工作是需求制定与评审。该阶段的工作分三步走:收集原始需求 -> 制定产品需求 -> 产品需求评审。具体说来,首先我们通过各种渠道收集原始需求,由于原始需求多半是概念性的、模糊的,不能直接用来指导开发工作,所以需要进行归类、筛选,整合为产品需求。基本原则是,结合当前开发产品的特性,争取以最小的改动以及最大的可扩展性来制定产品需求。降低风险,同时提高灵活性。经验告诉我们,在需求没有考虑透彻的情况下,不要贸然开始设计并实现,可能导致大量返工,费时费力。产品需求制定好后,需要进行评审,一定不要觉得浪费时间而不去评审,磨刀不误砍柴工嘛!
2) 设计
这个阶段的主要工作是将产品需求转化为设计需求,指导后续的编码工作。软件行业有一名老话是:软件质量是设计出来的,对于迭代式开发也是如此。设计的好坏直接决定了软件质量的高低。设计需求一般阐述了产品需求的详细设计方案,包括页面布局、数据结构、算法以及易用性、安全性、可扩展性、健壮性和性能等诸多方面的设计思路。即使让不同的开发人员根据设计需求来进行编码,开发出的功能也八九不离十。有此可见,设计需求是非常必要的。也就是说,我们在正式编码前,必须针对需求写出相应的设计文档来指导后续的编码工作。这样做有两大好处:一是在编码之前就充分预见到将来可能遇到的问题,可以尽早规避风险;二是为开发工作搭好框架,降低因开发人员的差异导致开发过程的不确定性,避免出现“一千个人心中有一千个对需求的理解”。
3) 编码
这个阶段的主要工作是严格按照设计需求来完成编码,并组织进行代码评审。每一行代码都是软件大厦的一砖一瓦,我们拒绝豆腐渣工程,所以我们重视每一行代码。进行代码评审可以有效保证代码质量,借助一些IT管理工具可以轻松进行代码评审和代码管理。笔者曾经使用过青铜器RDM软件来做代码评审(CodeReview),十分方便。代码评审的重点应该是对程序结构的审查,发现深层次的软件错误,而不要停留在表面。同时,建议大家在做代码评审时,以代码的一个“提交”为单位进行评审。这样做的前提是,每个“提交”里包含相对完整的功能。对于迭代式开发,我们要尽量保证,每一个编码-测试迭代里,都要完成相对独立、可测试性强的功能点。
4) 测试
测试实质上是一种鉴定性的工作,是对软件质量的鉴定和最后一道把关。这个阶段的主要工作是,在每一个测试构建中,尽可能多地覆盖需求点,并根据轻重缓急合理安排测试优先级,尽可能将影响较大的缺陷提前暴露出来。测试优先级的安排应遵循以下原则:
a、先测试经过变更的部分,然后测试没有变更的部分
b、先测试程序的核心功能,然后测试一般功能
c、先测试逻辑性的功能,然后测试业务性的功能
d、先测试常规情况,然后测试异常情况
e、先测试功能,然后测试性能
按照上述原则进行测试,可以更快地发现更多软件中的严重错误,这是使软件能尽快稳定下来的一个关键因素。除此以外,在每一个迭代周期结束之前还要进行系统测试。
编码-测试的不断迭代,保证了每个测试构建里的新功能没有问题,但整个软件系统的质量还没有得到充分验证,系统测试就是为此而生。在版本发布前的最后冲刺阶段,“车轮战”是很管用的一个手段,即:调集测试人员、开发人员等全面参与测试,将这些人员分为若干个小组,每个小组分别对系统进行测试。每个测试模块由多人进行测试,可以有效降低缺陷的遗漏率。但需要注意的是,开发人员应该避免测试自己开发的功能,即进行交叉测试。
软件质量保证的实质是,使用一些流程、方法来管控软件开发过程,从而使最终交付的软件产品质量得到最大程度的保证。同时,相信大家可以看出,在整个产品开发过程中会产生很多数据,如需求、设计文档、代码、测试用例、缺陷等。使用IT管理工具可以有效提高工作效率,青铜器RDM全面实现CodeReview+
Testlink + Mantis功能组合,可以管理需求、测试用例、缺陷、代码评审等,对于小规模团队,已
译文:Socket中winsock.h和winsock2.h的不同
原文:Is there a difference between <winsock.h> and <winsock2.h>?
译者:MilkCu
引言初学Socket网络编程,很明显<socket.h>用于linux操作系统,但是<winsock.h>和<winsock2.h>除了版本不同外,还有什么不同呢?
译文windows.h在新的Windows版本下编译时会包含winsock2.h,而在老版本中包含winsock.h,但是问题不仅局限在windows.h。当winsock.h在winsock2.h前包含时,编译会报错,因为两个文件不能共存的很好。winsock2.h设计的目的是替代winsock.h,而不是扩展它。在winsock.h中定义的所有内容在winsock2.h中也都定义了。如果winsock2.h在winsock.h前包含,winsock2.h定义了_WINSOCKAPI_,阻止编译器去处理后面的winsock.h,编译不会报错。但是如果winsock.h在winsock2.h前包含,winsock2.h没有检测到这些,而去重新定义winsock.h已经定义的东西,从而编译报错。
在同一个项目中同时使用winsock.h和winsock2.h要格外小心。例如,当使用winsock2.h编写自己的代码,但是使用仍包含winsock.h的第三方库的时候。
原文windows.h includes winsock2.h when compiling for newer Windows versions, but for older development it includes winsock.h instead. The problem is not limited to just windows.h, though. Any time winsock.h gets included before winsock2.h, there will be compiler errors. The reason is because the two files DO NOT co-exist very well. winsock2.h was designed to replace winsock.h, not extend it. Everything that is defined in winsock.h is also defined in winsock2.h. If winsock2.his included before winsock.h, winsock2.h defines _WINSOCKAPI_ to prevent the compiler from processing subsequent winsock.h includes, and all is fine. But if winsock.h is included beforewinsock2.h, winsock2.h does not detect that and tries to re-define everything that winsock.hhas already defined, causing the compile to fail.
You have to be very careful when mixing code that uses winsock.h with code that uses winsock2.hin the same project. For instance, when writing your own socket code that uses winsock2.h, and using third-party libraries that still use winsock.h.
这是Stack Overflow上的一篇问答,有点像国内的知乎,有些回答的质量不错的,正确性就要自己判断啦。
(全文完)