Zhigang Zhang's Blog

an idealist's cheap talk

永远的重构[3]-使用队列提高系统可用性

这是一个类似应用状态监控的系统,系统需要不断地调用其它系统提供的 WebService 获取状态信息。试运行阶段,发现该 WebService 执行效率比较低,而监控系统则以每5秒钟到10分钟不等的频率调用 WebService 里不同的方法,导致服务器内存使用量居高不下。

本案例暂且不关注如何提升 WebService 性能的问题,重点关注监控端的程序设计。通过与项目组一起分析相关的代码结构,总结如下:

  1. 监控系统创建了10个左右的定时器,周期是5秒到10分钟不等;
  2. 每个定时器调用 WebService 里不同的方法;
  3. 定时器中每调用 WebService 时均生成一个 WebService 引用;
  4. 使用同步方式调用 WebService 方法;
  5. 调用后将返回的数据暂存起来;

为了缓解 WebService 端的压力,对监控端进行了一次重构,重点是减小单位时间内对 WebService 的请求量,使其能保持正常运行。主要思路如下:

  1. 由于 WebService 的执行效率不高,应考虑使用异步的方式进行调用;
  2. 为确保 WebService 能够正常处理,应考虑同时不会产生多个对 WebService 的调用
  3. 考虑使用队列管理对 WebService 的请求

重构具体的办法为:

  1. 定义一个全局的队列 L,用LinkedList实现;
  2. 定时器中不再直接调用 WebService ,而是将需要调用的方法写入到队列中;
  3. 定义一个全局的静态变量 R 用于标记运行状态;
  4. 定义一个静态方法 S 用于处理队列里的内容;
  5. S 执行时将 R 标记为 true,方法结束时将 R 标记为 false;
  6. S 执行时如果发现 R 为 true,则直接返回;
  7. S 执行的逻辑是遍历队列,逐项调用 WebService 里对应的方法;
  8. 定时器完成队列的操作后,调用 S 方法;
  9. 将 WebService 引用提升为类变量,而且不应每次重新生成。

重构后将带来至少3个好处:

  1. 使对 WebService 的调用由原来的并发变为串行,将在很大程度上减轻 WebService 的压力;
  2. 利用队列,可以在 WebService 响应慢的时候进行一些去重的处理,重复的方法只需调用一次;
  3. 通过对队列 L 的长度监测,可以比较明确的计算出 WebService 的吞吐量。

Posted: