服务器技术纵横谈

     好久没有在csdn上发过什么文了,实在没有什么好写的是一方面,另外,我的大部分时间都在阅读中渡过,等到我意识到我应该写点什么的时候,已经到了现在.现在,我确实想整理思路写点什么出来,这不是一个强加给自己的任务,确实是有点想要喷薄出的想法而已。如果只是本能的向大脑里面塞什么东西进去,其实只是使用了他一部分的功能而已难道不是吗 ?大脑我觉得应该更像一个面包机,我们放进去面粉,苏打,它产生发泡以后的结果给我们;存在因为我们思考,有哲人是这么说的。所以,不管什么时候,不要让自己的思考能力闲置,长期这样,确实会让人回到智力萎缩的状态。

     我回想最近所做的事,所吸收的想法都是关于:“服务器”,不错,是这个东西。随着进入ipv5的年代,它会成为一个司空见惯的东西。其实,不用ipv5,目前你在网页上做的一切事情,背后都有服务器的支持。但ip5的年代,会让每一个家庭都至少拥有一个服务器 ,随着智能家居概念的普及,所有家电的“cpu”化,它们将拥有常规家电之外的能力--计算,以及数据共享。这样一个未来预示着,家用数据共享平台(服务器)存在的必然性,也许未来有一天,你可以直接通过互联网给自己做一顿晚餐,或者跟自己的猫咪喂食等。

这应该是全球进入智能电器化社会的一个必然阶段。。。未来,你或许可以跟你的煤气灶说:我明天需要买早上8点的飞机票。

    其实,对于服务器这个领域,我知之甚少。所以这篇文,将随着我知识的深化而逐渐扩展。看这篇文的性急观众请不要骂我。。。我其实与你们一样,都是处于学习,或者研究阶段。。。。希望我能早日完成这个文吧。另外,我可能啰啰嗦嗦说一些跟主题无关的话,都是一些我个人的不成熟见解,如果错误遗漏,请大家教我。

     我们从组建服务器最根本的东西说起吧:线程,不错,就是这个东西。目前所有伟大的服务器,都是基于多线程的,但有些系统平台可能没有多线程概念,比如linux,它是基于多进程的,但基于posix标准线程库的应用,我想,使用“多线程”来描述一切服务器,应该是勉强可以吧。长期以来,多线程 的控制,是一项比较难以掌握的技术。线程的同步,异步,并发,等问题,属于考虑不周,使用不当就会犯严重错误,特别对服务器的“负载均衡”而言,好的线程应用模式是成功的一半。临界这个概念,是设计线程控制结构必要先考虑的问题,尽管现在已经进入oo设计的年代,仿佛一切都是可以化为独立的对象,不用考虑其上下文的相关性。但对线程而言,还是一个需要“启,承,转,和”的完美状态机器。其实,作为计算机的这个机器,本身就是一个纯粹的“符号”系统,或者说,计算机,已经它上面运行的操作系统,就是一个庞大的符号系统。所以,对于线程的操作,还是要首先对需要完成的任务进行流程化的考虑,然后可以进一步进行基于任何方式的抽象。我所说“临界”这个概念与常规不同,是基于时间,而不仅仅是资源。指的是线程之间需要同时运作的时刻,这个时刻,它们可能同时去访问同样一个结构,或者变量,因此带来互相影响的相关性。我常见的一种线程控制退出方式:一个线程通过改变一个符号的值,去控制另外一个线程退出。当一个线程开始去改变符号时,这个符号其实也时常在另外一个线程的访问之中,在这个时刻,两个线程就处于“临界访问”状态。处于“临界”的两个线程,必须要进行状态机的同步,如果一个线程退出,析构了一些资源,而另外一个线程继续访问,显然会让程序痛快的crash掉。因此,这个控制线程,需要有目的的等待另外一个线程退出,而继续进行下一步操作。而这一切都需要时间,比之“简单一层”的 ui程序,服务器如果要退出自己,是相当的艰难。我个人认为,半分钟内完全退出服务器应该是可以接受的。如果在10秒钟内,不是过于简单,就是设计的太棒了。对于等待这方面,window下常规的api 提供了一组:waitfor*系列的函数,能够等待的对象句柄包括:1.thread 2.mutex  3.semphore  4.event 等。这些api接口的设计方法论,基本上来自常规的操作系统设计理论,可以放心大胆的使用。但使用方法需要特别注意,这里需要特别提出2个问题1.线程互锁 2.线程自锁  对于线程互锁,指的是线程因为互相等待,而进入deadlock状态,线程自锁,指的是线程进入递归式等待,造成自身deadlock。对于线程互锁问题,其实,没有什么好的解决方案,这一切取决你在代码之初的规划,对于此,我只能给出一个建议:尽量让线程自己处理自己,减少控制的交互,比较好的方法是用通知或者消息的方式进行通信,而不是直接的操控句柄或者数据结构。对于自锁定,幸好,操作系统已经给出了一种解决方案:可以递归锁定的核心对象这样的对象有二个,一个是critical_section(临界区),一个是mutex。使用critical_section来做递归锁,是一种通用的方式,已知的应用包括boost库的实现。所以,没有必要大家不必要去做这件工作,使用boost库即可。对于mutex它是window的特有核心对象,与critical_section的不同之处在于它可以在进程之间被打开使用,而critical_section,只可在一个进程的线程之间使用。对于linux系统,critical_section仍然支持递归,我想这也许是boost库选择其作为可递归锁的理由之二吧。

        创建一个线程很简单,有n多的接口可用,window平台提供了 CreateThread,这个函数。调用很简单,你可以在其参数中显式指明线程堆栈大小,入口函数地址,默认的函数传入参数,以及几个可以完全设置为NULL的参数。另外,posix线程库,以及常规的c运行时库也提供了几个对应的调用封装,比如_beginThread, _beginThreadEx ,pthread_create 等。在window平台上,很多人认为这几个函数其实与win32 CreateThread没什么不同。确实,这几个函数最终还是调用了CreateThread,在系统平台上,产生线程,其实是一个操作系统核心功能的调度过程。但基于c运行时得_begin*系列函数,还是有些略微的不同。最大的不同在于TLS( Thread Local Storage)机制的使用。TLS这个东西其实很好理解,如果把每个线程当作顽皮孩子的话,TLS就相当于给他穿上了带口袋的衣服,然后他就可以带着口袋到处玩耍。而这个口袋,成为这个线程独有的一个使用空间,他可以放各种各样的东西进去--当然,这个口袋数量可以不仅仅是一个的。TLS 的应用实例,开发中大家可能直接使用的比较少,但其实,很多库,或者工业框架的实现广泛使用了TLS,比如大名鼎鼎的MFC,c运行时库等。但也由此带来了一些负面效应,比如 MFC窗体类缺乏多线程安全性,调用一些c运行函数可能造成内存泄漏等。对于MFC的非多线程安全性,这个问题知道的人很多,真正明白的人比较少,经常看到很多半懂不懂的程序员因此诟病MFC,不将之干掉毫不罢休。其实你在一个线程里面操作它所创建的窗体对象是没有问题的,在另外的线程里面,直接使用原生句柄发消息怎可以避过不安全问题。至于详细为什么,只要了解下MFC 基于TLS 做了什么事,马上就一目了然。所以一般的原则是,你如果只使用win32完成工作,使用createthread即可,如果你需要在线程中调度运行时库,就去使用_begin*系列的函数吧。但基于为未知的安全因素的考虑,还是建议大家多使用_begin*系列函数。还有一个重要的使用它的理由就是工业级别MFC中的AfxBeginThread,CWndThread等,都是使用_begin*系列的函数封装,微软尚且如此,你还有什么理由不抛弃CreateThread ?
      谈论完 thread,接下来我们要说一说网络通讯的基本技术api:socket,这一块相关的介绍资料很多,我就不多论述,只是简单说下工作模式相关的东西: 阻塞,非阻塞模式.这2种基本模式是网络api的2种工作方式,它决定了上层逻辑的实现方式.所谓阻塞,指的是线程进行网络传输应答动作时,一定要等待一个应答周期完成,其实就是你send一个数据出去后,要马上进行wait动作,直到服务器发来响应的数据.非阻塞呢,一个线程发数据到服务器后,不进行等待,甚至也不去接受数据,而另外有一个线程专门进行数据收发工作,它收到相应数据后,就去处理数据.这是一种将send动作,和receive动作放在2个线程进行处理的行为.我个人认为这种非阻塞行为方式较好.它可以在界面线程里面工作,但又不会因此而挂起界面,另外,基于线程模型的考虑,这种方式逻辑架构更为清晰.它的主要缺点在于具体的网络交互动作可能出现"交叠"或者"乱序"的行为,也就是如果存在几个线形关系的命令,可能会产生命令发送次序混乱的问题,这个问题需要在客户端,或者服务器进行一定逻辑上的限定.阻塞方式中,当前线程会被挂起,直到服务器响应为止.如果在ui线程中做这件事情,ui就会经常性的不能响应用户操作,整个程序处于假死状态.

 

服务器的传统架构


1.一线程,一服务

这个是最传统的架构(也许不应该称为架构),早期很多伟大的方案都是基于这个思想。在window平台,确确实实是 一个服务器,对应服务一个socket连接,

但在linux上就是一个进程对应一个socket服务。比较早的http cgi服务程序,就是基于这种方式。

此种方式占用资源大,同时并发保持连接少。无法充分利用服务器资源,理论上1024个线程会占用完所有资源,即使线程不做什么工作,仅仅一个sleep(1)(睡眠一毫秒)的动作。只是context swich的时间就会让服务器cpu达到100%的运转。负载均衡效率较低,目前的cgi程序都应该已经抛弃了这种架构。


2. 1一线程多服务

这个应该是目前用的最多的架构 ,一个服务器线程负载多个socket服务 ,这种做法可以充分使用服务器资源,同时保持巨量的连接数目。但它也不是万能的,

常见的问题为 如果一个socket在io过程中挂起,或者在事物运算中出现bug导致崩溃,会导致所有连接的socket受到影响。




 


    

    



 


   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值