zoukankan      html  css  js  c++  java
  • 再谈kbmMW垃圾回收

    很早就写了关于kbmMW Server如何实现的垃圾回收,但最近一段时间还是为此遇到问题,实现的Server不能稳定运行,发生问题后不响应客户端的查询请求,在客户端得到服务端返回地址错误信息,只能重启Server解决。这是让人最头的问题,还好,今天终于搞定。

    先复习一下早前写过的资料,回顾一下何为kbmMWServer的垃圾回收及实现机制,然后再看我遇到的具体问题。

    kbmMWServer垃圾回收处理机制(一)

    kbmMWServer垃圾回收处理机制(二)

    kbmMWServer垃圾回收处理机制(三)

     总结前文,kbmMWServer通过两个属性来控制是否做垃圾回收及定时回收垃圾的时间间隔:

    GarbageCollection:是否做垃圾回收

    GarbageInterval:回收垃圾的时间间隔,单位是秒

    这里的垃圾,是指不应该保留的Service实例。

    当客户端发来一个请求时,kbmMWServer会取得一个对应的Service实例来处理该请求,在服务端,kbmMWServer通过池(Pool)来管理Service实例,随着客户端的不断请求及服务端的响应,会在Service实例池中产生多个Service实例,当客户端的请求数量降下来,或者极端的说长时间没有了客户端的请求,那么在服务端的Service实例池中就会有多个不用的实例,因此需要定时的清理、删除,以节省服务器资源。

    更具体的说,到底什么样的Service实例需要视为垃圾来清理呢?还是通过代码来说更为明确,找到TkbmMWServiceDefinition类的实现,下面几个属性决定Service实例是否被回收:

      TkbmMWServiceDefinition = class(TkbmMWCustomServiceDefinition)
      public
         ...
         property MinCount;//服务端保留的最小Service实例数,小等于这个数时,Service实例不被回收
         property MaxIdleTime;//一个Service实例最大的空闲时间,当超过这个时间时,将被回收
         property MaxIdleStatefulTime;//一个有状态Service实例最大的空闲时间,当超过这个时间时,将被回收
         property Timeout;//一个Service实例执行时的超时时间,当正在执行时超过这个时间,将被回收
         ...
      end;

     当开发者不设置这几个属性,也就是默认情况下:

    MinCount为-1,表示在服务端不保留Service实例,所有的Service实例都将做回收处理

    MaxIdleTime为0,表示不管空闲多长时间,Service实例都不会被回收

    MaxIdleStatefulTime为0:有状态Service实例,不管空闲多长时间,都不会被回收

    Timeout为0,一个Service实例不管执行多长时间,都不会被回收

    现在,我们可以找到最核心的垃圾回收处理的代码,具体看看,kbmMW如何例用上面所说的四个属性来实现的逻辑,因为版权的问题,不能贴出完整代码,只能用文字来描述这一过程。

    前文中提到,kbmMWServer是利用TkbmMWServicePool来管理Service实例池的,这个TkbmMWServicePool类实现了一个方法GarbageCollect(All:boolean),执行垃圾回收。

    其中的参数All,指回收所有的Service实例,什么情况下这个All为True呢?就是在停止kbmMWServer时,或者退出Server时。

    TkbmMWServicePool.GarbageCollect进一步委托给ServiceDefiniation.Instances.GarbageCollect来执行回收动作,

    if All or (sd.MaxIdleTime>0) or (sd.MaxIdleStatefulTime>0) or (sd.Timeout>0) then
       sd.Instances.GarbageCollect(All);

    这里用到了上面所说的三个属性:MaxIdleTime,MaxIdleStatefulTime及Timeout做为执行垃圾回收的条件,由此可以理解,如果开发者设置了这三个属性其中之一不为0,才实际做垃圾回收动作,否则的话,只有在退出Server时才做。换句话说,仅设置kbmMWServer的GarbageCollection及GarbageInterval属性是不够的,还需要设置TkbmMWServiceDefinition的MaxIdleTime,MaxIdleStatefulTime及Timeout三个属性才会执行垃圾回收。

    接下来,就到了TkbmMWServiceInstances.GarbageCollect方法,执行具体的垃圾回收动作,此方法是垃圾回收的核心代码,有源码的开发者可以直接去看。

    作者首先建立一个lstExpired列表对象,目的是把需要清理的Service实例放入此列表对象中,接下来,就是循环FInstances,取出每个Service实例,先计算Service实例最后被请求时间与当前时间差:

    cs:=FInstances.Items[i];//取出Service实例
    d:=trunc((n.UTC-cs.FLastRequestTime.UTC)*SECSPERDAY);//计算所用时间,单位秒

    下面这句,意思是说,如果一个Service实例没有被预先锁定并且处在闲置状态,即没有正在处理客户端请求,则按MaxIdleStatefulTime及MaxIdleTime回收,否则,按Timeout进行回收。FPendingLock在对一个Service加锁前为True,加锁后为False,当为True,表示正在锁定一个Service实例,我称之为预先锁定。FRequests,当锁定一个Service前,加1,解锁一个Service前减1,默认值为0。当一个Service.Requests为0,表示没有被锁定,可以解读为闲置。

    if (not cs.FPendingLock) and (cs.FRequests<=0) then
    //按MaxIdleStatefulTime及MaxIdleTime回收
    else
    //按Timeout进行回收

    在这一过程中,还会触发kbmMWServer.OnGarbageCollectQuery事件,利用该事件,可以进一步决定一个Service实例是否被回收。

    当判定一个Servcie实例应该被回收时,把他加入到lstExpired对象列表,同时,从实例池中删除。

    最后代码,就是按lstExpired,做Service实例的销毁。

    整个过程大体就这样,那我犯的什么错误呢?就是设置了短的Timeout时间为60秒,同时Server也设置为60秒,在这种情况下,服务端每60秒检查一次Service实例,当一个正在执行的实例执行超过60秒时,被视为超时而被回收,从而造成服务端不稳定!

    找到问题原因,自然就解决,不设置Timeout,让其保持默认值0。

  • 相关阅读:
    【原】Go语言及Web框架Beego环境无脑搭建
    Treap学习笔记
    读书笔记--Head First PMP目录
    Linux操作系统常用命令合集——第四篇-文件系统权限操作(5个命令)
    Linux操作系统常用命令合集——第三篇-系统管理操作(25个命令)
    Linux操作系统常用命令合集——第二篇- 用户和组操作(15个命令)
    路由器与交换机配置——配置文件和系统映像备份与恢复
    路由器配置——密码重置
    交换机配置——端口安全
    路由器与交换机配置——交换机默认网关(实现跨网段telnet)
  • 原文地址:https://www.cnblogs.com/kinglandsoft/p/9426815.html
Copyright © 2011-2022 走看看