WebSphere IMS Connector V6.2 开发计费应用

IBM WebSphere IP Multimedia Subsystem (IMS) Connector 简介

IBM WebSphere IP Multimedia Subsystem (IMS) Connector V6.2(以下简称WebSphere IMS Connector)是IBM 面向电信行业服务提供平台(Service Delivery Platform,SDP)的重要组成部分。在 IMS 架构中,它作为一个中介服务器,起到连接 SIP 应用程序与 IMS 核心网元的作用。 WebSphere IMS Connector V6.2 通过一系列 Web Service 接口,提供了对 OCS、CCF、HSS、CSCF 网元的支持,为用户提供了离线/在线计费、用户信息管理等功能。

WebSphere IMS Connector 作为 IBM SDP 平台最重要的 Enabler 之一,为用户提供了离线计费(Rf)、在线计费(Ro)、用户信息管理(Sh)等功能。V6.2 是当前的最新版本,与上一版本最大的区别是增加了对在线计费的支持。

WebSphere IMS Connector 的架构如图 1 所示。其中 WebSphere Application Server (WAS) 是 IBM 的 J2EE 应用程序服务器软件,它在 V6.1版本中以聚合容器的方式处理 SIP 和 Web 应用程序,即使用相同的容器处理这两种应用程序构件。这种实现方式的优点是,SIP 应用程序可以访问 Web 容器资源,如 HTTP 会话和 JNDI 对象,反之,Web 应用可以访问 SIP API。聚合 SIP 和 Web 容器还允许创建聚合的 HTTP/SIP Web 服务。


图 1. IBM WebSphere IMS Connector V6.2 架构

构建在 WAS 之上的 WebSphere IMS Connector 充分利用了聚合容器的优点,它以 Web 服务的方式为上层应用程序提供了访问 Home Subscriber Server (HSS) 和 Charging Function 的能力,它是 SIP 应用程序与电信核心网络基础设施间的桥梁。同时,Web 服务的实现方式使得 WebSphere IMS Connector 可以方便地作为 SDP 平台的 Enabler 与其他系统集成,并且无需考虑底层通信协议的复杂性,显著降低了编程的难度。

此外,IMS Service Control (ISC) 接口组件定义了运行在 WAS 上的 IMS 应用程序与 Call Session Control Function (CSCF) 的通信方式。它提供了基于标准的连接功能,使得部署在 WAS V6.1 上的 J2EE 应用程序与电信世界中现有的 SIP 设备进行通信和联网。ISC 接口隐藏了与各种 CSCF 电信网络组成元素连接的复杂性。IBM 与多个网络设备提供商开展了合作,以确保 WebSphere IMS Connector与 IMS 核心网络组成元素的互操作性。

WebSphere IMS Connector V6.2 计费接口

WebSphere IMS Connector 以 Web 服务的方式提供了离线计费(Rf)和在线计费(Ro)接口,并在底层实现了 Diameter 协议栈,使两个计费接口都能够以 Diameter 消息的方式与 IMS 核心网元进行交互,见图 2。应用开发人员可以使用 JAX-RPC 方式调用这些 Diameter Web 服务,而无需了解底层 Diameter 协议的复杂性。


图 2. WebSphere IMS Connector V6.2 计费接口

这里提到的 Diameter 是继 RADIUS 协议之后的下一代身份验证、授权和记帐(Authentication, Authorization, and Accounting,AAA)协议。在 IMS 体系结构中,Diameter 被广泛用于在 IMS 实体间交换 AAA 信息。

离线计费接口

离线计费的执行使用了 3GPP TS32.225 和 TS32.299 中定义的 Rf 接口,该接口用于执行非实时的计费操作,也即后付费方式。具体的调用方式是:当 Rf Web 服务接口接到IMS应用程序的调用请求后,会构造相应的计费请求(Accounting Request,ACR)消息,发送到 Charging Collection Function (CCF)报告账户信息,以生成计费记录(Charging Data Records,CDR),同时将计费应答(Accounting Answer,ACA)返回给 IMS 应用程序。

离线计费可以分为基于事件的计费(Event-based Charging)和基于会话的计费(Session-based Charging)这两种方式。

离线计费 Rf Web 服务接口提供以下计费操作:

  • startRfAccounting(),用于启动计费会话,AVP(Attribute Value Pair)中包含 START_RECORD 值,通常发生在当应用程序接收到初始 SIP INVITE 的 200 OK 消息时。
  • interimRfAccounting(),用于更新会话,AVP 中包含 INTERIM_RECORD 值,通常发生在当应用程序发送 SIP RE-INVITE 或 UPDATE 消息时。
  • stopRfAccounting(),用于停止计费会话,AVP 中包含 STOP_RECORD 值,通常发生在当应用程序接收到一个 SIP BYE 消息时。
  • eventRfAccounting(),基于事件的计费,AVP中包含 EVENT _RECORD 值,用于离散事件的一次性计费。
  • accountingRaw(),用于构造自定义的 AVP 值。

对 Rf Web 服务调用以上操作时,WebSphere IMS Connector 会将调用请求封装为 Diameter 消息,并将其传递到 CCF 进行记录。这样,开发人员并不需要具有 Diameter 协议的全面知识,而是通过在代码中进行几个简单的 Web 服务调用就可以完成这些工作。

在线计费接口

在线计费的执行使用了 3GPP TS 32.225 和 TS32.299 中所定义的 Ro 接口,该接口用于将计费信息提供给 Online Charging System (OCS),从而能够在用户使用网络资源之前进行实时的计费操作,也即预付费方式。 Ro 接口同样允许执行基于事件的计费和基于会话的计费。

在线计费 Ro Web 服务接口提供以下计费操作:

  • sendCCInitial(),用于启动计费会话,AVP 中包含 START_ REQUEST 值,通常发生在当应用程序发送 SIP INVITE、NOTIFY、MESSAGE、REGISTER、SUBSCRIBE、REFER 和 PUBLISH 消息时。
  • sendCCUpdate(),用于更新会话,AVP 中包含 INTERIM_ REQUEST 值,通常发生在当应用程序收到 SIP INVITE、RE-INVITE 或 UPDATE 的200 OK 确认消息时。
  • sendCCTermination(),用于停止计费会话,AVP 中包含 STOP_ REQUEST 值,通常发生在当应用程序异常中止 SIP 会话或收到 SIP BYE 时。

除此之外,Ro 接口还有一些高级功能,例如用户权限控制等等。 Ro Web 服务的工作方式与 Rf Web 服务一样,但不是连接到 CCF,而是连接到 OCS 服务器,进行在线计费。


开发计费程序

本节将以 Rf Web 服务接口为例,详细介绍如何基于 WebSphere IMS Connector 开发简单的离线计费程序,在后续的章节中将对该程序做一些改进。

可以使用任何 J2EE 开发工具,例如 Eclipse,来开发计费程序;为了更为方便地进行开发,建议使用 IBM Rational Application Developer (RAD) 集成开发工具或者是随 WAS 产品附送的 Application Server Toolkit (AST);本文将以 RAD V7 为平台进行后续介绍。

首先,在 RAD 里新建一个 Java Project,然后,将所需 jar 包添加到该项目的构建路径中去,如图 3:


图 3. 项目构建路径

其中 com.ibm.ws.webservices.thinclient_6.1.0.jar 是开发 Web Service 客户端所必需的库文件,它位于[RAD_INSTALL_PATH]\runtimes\base_v61\runtimes\ 目录下;DHADiameter*.jar 是开发Diameter计费客户端所必需的库文件,它们位于 WebSphere IMS Connector 产品安装包(DHAImsConnectorInstallPackage_6.2.0.tar)的\installableApps\ImsConnector\client\tooling.zip 中。

接着,在这个 Java Project 中新建一个 Java Class,并在其构造函数中初始化 Rf Web 服务调用端点,具体参见代码清单1。本文涉及的代码片段可从文章末尾给出的链接下载。


清单 1. 初始化服务调用端点

// Create a new locator
DiameterRfService_SEIServiceLocator locator = new DiameterRfService_SEIServiceLocator();
URL endpointURL = 
 new URL("http://localhost:9080/DHADiameterRfWebService/services/DiameterRfService");
// Get Rf service
DiameterRfService_SEI service = locator.getDiameterRfService(endpointURL);
// Start a session based accounting
startRfAccounting(service, destinationRealm, 0, acctInterimInterval);
interimRfAccounting(service, destinationRealm, 1);	 
stopRfAccounting(service, destinationRealm, numberOfIntervals + 1);

其中 endpointURL 是 Rf Web 服务所在的 URL,通过 locator 可以获取调用 Rf 接口所需要的 Stub 类(service),接着就可以在这个 service 实例上调用 Rf 接口的各个计费方法。如果 Rf Web 服务所在的WAS开启了全局安全性设置,那么需要在服务调用点,即 service 实例,设置相应的用户名和密码。本段代码中发起了一个基于会话的计费请求,它首先调用 startRfAccounting 方法启动一个计费会话;接着调用 interimRfAccounting 方法,以一定的时间间隔循环更新这个会话的计费信息;最后调用 stopRfAccounting 方法结束这个会话。这三个计费方法详见清单2。这些计费方法根据传入的计费参数,调用 buildAccInfo 方法来构造计费信息,并以这些信息为参数调用相应的 Rf Web 服务,完成计费请求。这里的计费信息只包含了基本的计费参数,可以根据实际需要进行添加。


清单 2. 计费方法

// Start accounting
public static RfAccountingResults startRfAccounting(DiameterRfService_SEI service, 
 String destinationRealm, int recordNumber, int acctInterimInterval) throws Exception {
 RfAccountingInfo acct = buildAccInfo(destinationRealm, recordNumber);
 RfAccountingResults results = service.startRfAccounting(acct);
 return results;
}
// Interim accounting
public static RfAccountingResults interimRfAccounting (DiameterRfService_SEI service, 
 String destinationRealm, int recordNumber) throws Exception {
 RfAccountingInfo acct = buildAccInfo(destinationRealm, recordNumber);
 RfAccountingResults results = service.interimRfAccounting(acct);
 return results;	
}
// Stop accounting
public static RfAccountingResults stopRfAccounting(DiameterRfService_SEI service, 
 String destinationRealm, int recordNumber) throws Exception {
 RfAccountingInfo acct = buildAccInfo(destinationRealm, recordNumber);
 RfAccountingResults results = service.stopRfAccounting(acct);
 return results;	
}

异步调用计费接口的 Adapter

IMS应用程序在处理 SIP 信令的时候有很高的性能要求,因此,在程序中发起计费请求时也需要尽快返回以处理后续操作。然而,IMS 中的计费网元,特别是 CCF,不是为了实时响应用户操作而设计的,它们的响应速度普遍比较慢;如果采用同步调用的方式,很可能导致 IMS 应用程序阻塞在计费接口调用上,无法处理后续操作,最终导致客户端超时。解决方法就是使用异步调用接口。

目前 WebSphere IMS Connector 所提供的操作接口都是同步调用方式的 Web 服务接口。为了使IMS应用程序更高效地使用 WebSphere IMS Connector 所提供的 Web 服务接口,本节以 Rf 接口为例实现了异步调用Rf接口的适配器——AsyncRfAdapter。通过 AsyncRfAdapter 的适配,可以实现对 Rf 接口的异步调用,从而显著改善 IMS 应用程序的整体性能。

AsyncRfAdapter 的设计

要实现 Rf 接口的异步调用,最简单的方式是在调用前新建一个子线程,由子线程负责调用 Rf 接口。然而,如果每次调用都新建一个子线程,在高并发的情况下将导致 JVM 中存在上千个线程,JVM 疲于调度这些线程而无法正常运作。因此,需要采用线程池的方式复用线程,使线程的数目处于可控范围内,同时也减少了创建销毁线程所带来的开销。

此外,基于会话的计费要求计费消息的发送要符合时序逻辑,例如,在一个计费周期内,必须首先发送 START_RECORD 消息,接着发送 INTERIM_RECORD,最后发送 STOP_RECORD,这对线程同步提出了重大挑战。要满足这一要求,需要利用 FIFO 队列对将要发送的消息进行排序,并且还要利用线程同步机制和回调机制保证队列中的消息当且仅当其前驱消息被处理完毕之后才能发送。本文提出了异步 Diameter 消息适配器 AsyncRfAdapter,其架构如图4所示,它通过改进的多 FIFO 队列和单线程池的方式,在保证计费消息时序和性能的前提下,实现了对 Rf 接口的异步调用,调用结果通过回调函数输出。


图 4. AsyncRfAdapter 架构图

每个连接到 AsyncRfAdapter 的 IMS 应用程序,都独占拥有自己的 FIFO 队列,可以向队列提交计费请求,所有的队列都连接到唯一的一个工作线程池,线程池里的线程通过调用 Rf 接口来处理各个队列里的计费请求,并且利用线程同步和回调机制实现每个 FIFO 队列内各元素的依次顺序处理以及结果的获取。

AsyncRfAdapter 的实现

AsyncRfAdapter 由以下几个 Java 类组成:

1. DiameterMessage

用于封装 Diameter 消息,代码见清单3。


清单 3. DiameterMessage 类
import com.ibm.diameter.charging.util.*;
public class DiameterMessage {
 public int acrType;
 public RfAccountingInfo acrInfo;
 public DiameterMessage(int acrType,RfAccountingInfo acrInfo){
 this.acrType=acrType;
 this.acrInfo=acrInfo;
 } 
}

其中 acrType 用于描述计费消息类型,info 用于描述 Diameter 消息中所要包含的计费信息。

2. DiameterListener

Diameter 异步调用监听器,用于接收回调请求;要求实现 diameterCallback 回调函数接口,见清单4。


清单 4. DiameterListener 接口
public interface DiameterListener {
public void diameterCallback(DiameterEvent event);
}

3. DiameterEvent

Diameter 异步调用事件接口,用于获取异步调用结果;要求实现 getWorkResult 结果获取接口,见清单 5。


清单 5. DiameterEvent 接口
import com.ibm.diameter.charging.util.RfAccountingResults;
public interface DiameterEvent {
 public RfAccountingResults getWorkResult();
}

4. DiameterWork

Diameter 异步调用工作单元,实现了 Runnable DiameterEvent 接口,它将根据计费消息的类型调用不同的离线计费 Web 服务,见清单 6。


清单 6. DiameterWork 类
public class DiameterWork implements Runnable,DiameterEvent{
 public DiameterWork(DiameterRfService_SEI serviceRef,
 DiameterMessage dm,DiameterListener dl) {
 this.serviceRef=serviceRef;
 this.dm=dm;
 this.dl=dl;
 }
 public void run(){
 switch(dm.acrType){
 case AccountingRecordType.START_OFFLINE_ACCOUNTING:
 this.results=serviceRef.startRfAccounting(dm.acrInfo);
 case AccountingRecordType.INTERIM_OFFLINE_ACCOUNTING:
 this.results=serviceRef.interimRfAccounting(dm.acrInfo);
 case AccountingRecordType.STOP_OFFLINE_ACCOUNTING:
 this.results=serviceRef.stopRfAccounting(dm.acrInfo);
 }
 dl.diameterCallback(this);
 }
 public RfAccountingResults getWorkResult() {
 return this.results;
 }
}

5. AsyncDiameter

异步 Diameter 消息处理线程池实现类,所有客户端发送的 Diameter 消息都将由此线程池的线程异步处理。可以通过构造函数对线程池的大小、队列长度等工作参数进行配置。


清单 7. AsyncDiameter 类
public class AsyncDiameter {
 public AsyncDiameter(int min_pool,int max_pool,int timeout,int qSize){
 if(executor==null){
 queue=new LinkedBlockingQueue(qSize);
 executor=new ThreadPoolExecutor(min_pool,max_pool,timeout,TimeUnit.SECONDS,queue);
 }
 }
 public void asyncSend(DiameterRfService_SEI ep,DiameterMessage dm,DiameterListener dl){
 executor.execute(new DiameterWork(ep, dm, dl));
 }
 public int getQueueSize(){
 return queue.size();
 }
}

6. DiameterHandler

AsyncRfAdapter 的主实现类。首先,在构造函数中对 Rf Web 服务调用端点以及 AsyncDiameter线程池进行初始化。每个 DiameterHandler 实例使用链表存储需要发送的 Diameter 消息,并且用可重入锁对访问链表的线程进行同步。一般情况下,使用 ReentrantLock 作为同步锁可以获得比 synchronized 更好的性能。同时,实现了 diameterCallback 回调函数接口,以获取 Diameter ACA 消息。sendDiameter 方法用于对 Diameter 消息进行排队,并依次向处理线程池提交 Diameter 消息。getRfSession 方法用于获取当前计费会话的 ID。清单 8展示了DiameterHandler 类的代码片段。


清单 8. DiameterHandler 类
public class DiameterHandler implements DiameterListener{
 public void diameterCallback(DiameterEvent event) {
 event.getWorkResult();
 setState(DIAMETER_MESSAGE_SENT);
 this.sendDiameter(null);
 }
 public void sendDiameter(DiameterMessage dm){
 lock.lock();
 DiameterMessage firstDiameterMsg=queueingDiameterMessage(dm);
 lock.unlock();
 if(firstDiameterMsg!=null)
 sending(firstDiameterMsg);
 }
 private DiameterMessage queueingDiameterMessage(DiameterMessage dm){
 DiameterMessage firstMessage=null;
 if(dm!=null)
 list.add(dm);
 if((state==DIAMETER_MESSAGE_SENT)&&(list.isEmpty()==false)){
 firstMessage=(DiameterMessage)list.remove();
 state=DIAMETER_MESSAGE_SENDING;
 }
 return firstMessage;
 }
 private void setState(int state){
 lock.lock();
 this.state=state;
 lock.unlock();
 }
 private static String getRfSession(){
 return SessionIdFactory.getRef().getSessionId(origin_host.getBytes());
 }
}

Main 方法展示了客户端调用 AsyncRfAdapter 发送计费消息的方法。由于采用异步操作,客户端没有任何阻塞,有效保证了客户端的实时性,同时调用结果可以通过回调接口获取。


清单 9. Main 方法
public static void main(String[] args) throws Exception {
 DiameterHandler dh=new DiameterHandler();
// start offline accounting
 RfAccountingInfo acrInfo=dh.buildAccInfo("ibm.com");
 DiameterMessage dm=new DiameterMessage(AccountingRecordType.START_OFFLINE_ACC,acrInfo);
 dh.sendDiameter(dm);
// interim offline accounting
 dm=new DiameterMessage(AccountingRecordType.INTERIM_OFFLINE_ACCOUNTING,acrInfo);
 dh.sendDiameter(dm);
// stop offline accounting
 dm=new DiameterMessage(AccountingRecordType.STOP_OFFLINE_ACCOUNTING,acrInfo);
 dh.sendDiameter(dm);
}

WebSphere IMS Connector 计费服务的性能优化

WebSphere IMS Connector 计费服务可以通过构建 WAS 服务器集群的方式实现水平及垂直扩展,从而达到电信级的性能与可靠性要求。对于单个服务器节点而言,可以通过修改各个服务对应的 properties配置文件和 WAS 的配置来提高性能和可靠性。

Properties 的配置

WebSphere IMS Connector 计费服务可优化的 Properties 参数如下:

1. maxWatchDogExpirations 参数

该参数指定了 WebSphere IMS Connector 与后端计费服务器的心跳超时次数,默认为 2 次;超过 2 次没有响应的后端服务器将被标记为不可用,后续请求将不发往该服务器。

2. watchDogTimeout 参数

该参数指定了 WebSphere IMS Connector 与后端计费服务器的心跳超时时间,默认为 30 秒;如果 maxWatchDogExpirations 设为 1,那么超过 30 秒还没有响应的后端服务器将被标记为不可用,后续请求将不发往该服务器。

3. reconnectInterval 参数

重试时间间隔;默认值为 30 妙,指示当后端服务器被标记为不可用时,经过 30 秒后重新尝试建立连接。

4. maxPendingQueueLength 参数

消息处理队列的长度,如果队列长度达到最大值,则后续消息将被丢弃;默认值为 30,建议设置为15000,以满足性能要求。

5. packetTimeout 参数

队列内消息超时时间,默认值为 30,表示存在处理队列中超过 30 秒的消息将被删除;建议设置为 600。

6. maxPacketSize 参数

系统能处理的最大消息大小;默认值为 10000 bytes,超过该大小的消息将被丢弃,以保护服务器不会超载。

WAS 的配置

作为运行 WebSphere IMS Connector 的基础平台,WAS 的配置优化如下:

1. JVM 堆大小

设置 WebSphere IMS Connector 所在 WAS 服务器的 JVM 堆大小,必须额外考虑到各个服务模块所使用的消息队列所占用的内存空间,其估算值为 maxPacketSize 与 maxPendingQueueLength 之积。通常情况下应设置在 512 MB 到 768 MB 之间,尽量不要超过 1GB,以免大幅度增加 GC 延时。可以通过创建 WAS 集群的方式进一步扩展 JVM 堆大小。

2. DiameterThreadPool

该线程池用于处理 Web 服务入栈消息。对该线程池的调整,应该通过 TPV 工具实时监控其工作状态,如果池内线程使用率超过80%,则应考虑增加线程数目。线程池大小最大不应超过300,否则会降低 JVM 调度线程的效率。可以通过创建 WAS 集群的方式进一步扩展线程池大小。

3. DiameterWorkManager

该 Asynchronous beans 工作管理器用于处理 Web 服务出栈消息。可以根据需要调整工作超时及工作请求队列大小。对 DiameterWorkManager 所属线程池的调整方式同 DiameterThreadPool。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14789789/viewspace-589257/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14789789/viewspace-589257/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值