本文旨在经过对某省高速公路联网收费运营管理平台的架构设计过程进行案例分析,描述架构设计的决策过程。数据库
某省的高速公路分为近百个路段,不一样的路段归属不一样的公司建设与运营,形成了车辆在跨越不一样路段时,须要停经收费站缴费换卡,下降了高速公路的车辆通行效率。缓存
随着信息化技术的发展,将全省的高速公路联网收费的条件成熟,改造后车辆在高速公路上行驶,在出发地上高速时领卡,到目的地出高速时全程只需缴费一次。随着信息化推动,将来车辆在全国范围内高速公路通行,均只需缴费一次。安全
为了适应全省联网收费系统改造,迫切须要能集中对全部路段内的收费交易流水,高清卡口流水与图像进行检索,对交易流水进行从新拆分,对全省高速上车辆进行视频监控与防逃费稽查。与之前最大的改进是数据由分散在各个路段系统,集中到省中心,并提供信息共享查询与统计分析报表。服务器
根据业务需求,各个层级系统间数据流向以下图所示:网络
1) 全省路网约有100个路段中心;每一个路段中心对应几个到几十个不等的收费站,每一个收费站平均有4个入口车道,2个出口车道,合计全省约有2000个入口车道,1000个出口车道。多线程
2) 车辆驶入收费站上高速时,产生交易入口流水和高清卡口信息(包含图像);车辆从收费站出口缴费时产生交易出口流水信息。各个车道中设备的状态信息,定时发送到路段中心。架构
3) 各路段中心的数据须要及时汇总到省运营管理平台。车辆从收费站出口缴费时,收费站系统须要到省运营平台查询该车辆对应的入口流水数据,以及高清卡扣流水数据,必要时还须要调取高清卡扣图像进行肉眼比对。并发
4) 由省收费结算中心根据路段中心提供的交易流水进行费用拆分,并将拆分结果下发给省运营平台。省运营平台再将拆分结果下发给各个路段中心。负载均衡
5) 省运营平台下发基础费率、设备控制指令、运营参数信息到路段中心。路段中心再逐级下发到收费站。框架
对业务需求做进一步了解分析,发现系统具备以下特色:
1) 绝大多数场景对实时性要求不高。只有查询入口交易流水须要在1秒内响应。
2) 系统的并发访问量小。普通用户数量小于2000。应用接口查询并发数小于500。(在不考虑移动APP公众应用的场景下)
3)复杂的业务逻辑少,系统需求集中于对数据进行查询分析与信息管理。只有交易流水拆分规则较为复杂。
4) 查询入口交易流水与查询高清卡口流水要求7 * 24高可用性,不然收费站程序可能会没法对车辆进行收费计算处理,进行人工干预会大大下降收费效率,易形成交通堵塞。
5)交易流水与高清卡口流水数据量大,日均在3千万和2千万以上。业务管理上要求对交易流水存档一年时间以上,高清卡口流水3个月以上。每张高清卡口图片大小为200K,集中存储在省平台将是巨大的容量。
在系统设计过程当中做重大决策,必须在分析清楚主要功能需求与质量性需求的基础上,结合已有系统现状,可支出经济成本,技术团队素质现状,网络环境,业务管理约束,工期要求等因素做出平衡性取舍。
在该系统的实施过程当中,最大的现实约束是工期赶,牵涉到的工程实施方多,开发测试时间被压缩到2个月内,必须把握好进度不能影响其它单位联调测试。在架构设计时必需要结合技术团队现有的知识技能储备,新技术预研须要成本,同时还会引入风险,必须谨慎。
因为整个系统的业务功能很是多,划分为15个以上的子系统。对公共的用户、组织机构、道路、收费站、基础字典等信息放在一个数据库(Schema)中,对其它业务系统不能公用的分别划分一个数据库。对于重点业务功能专门划分一个数据库。为每个业务系统分配一个独立的数据库用户,便于使用与管理。
充分利用Oracle数据库其分区表机制,对于入口流水,出口流水,高清卡口流水等大表按照日期(例如按照3天,10天)进行分区,确保每一个分区内数据量在1亿条之内。这样在同一个分区内单表查询时,只要数据库索引创建合理,服务器资源充足,Oracle能保障在1秒内响应。同时在对历史记录作清理时可直接删除分区文件,大数据量删除性能获得很大提高。
虽然已经对数据库做了优化,但因为车辆在收费出口缴费时,收费软件均要查询入口流水以及高清流水。若是并发查询数上升,数据库在处理并发查询时就不必定能保证在1秒内响应了。该功能的响应性能,是用户的痛点,直接决定了该项目被不被承认。
所以必须考虑引入NoSQL数据库,将最近3天的流水数据加载到内存中,处理来自收费站的并发查询请求,确保查询在10~100毫秒内完成。
在咱们的业务场景中,数据已经持久化在Oracle中,引入分布式缓存或NoSQL产品只是为了直接从内存检索数据提高性能。因而,对几款开源的分布式缓存和内存数据库产品作了大体了解。
Memcached适合作分布式缓存,但它自己不提供检索查询功能。它将数据所有放在内存中,不实现文件持久化机制。同时在集群部署时,节点之间是不做通讯的,一旦某个节点宕机则该节点上数据所有丢失。要实现查询检索功能,应用开发的工做量会比较多,不适合咱们的场景。
Redis与MongoDB都提供了持久化到文件的机制,Redis的查询性能优于MongoDB。但MongoDB在查询API上实现了不少相似SQL语句查询的便利功能,同时在集群部署时它能自动实现数据分片,灾难转移,应用开发的工做量也要小一些。两相比较,我的倾向于引入MongoDB的。可是苦于工期短,没有人力与时间作深刻的预研,若是研究的不够深刻,又会增长风险。
后来Vmware公司推荐一款叫GemFire的内存数据库产品,称在12306网站应用取得了不错的效果。因而他们的售前就过来给咱们洗脑,演示了一些成功案例,让咱们对这个产品增长了很大信心。让我印象最深入的是这个产品定位为内存计算平台解决方案,能够直接在数据节点进行计算(相似于在数据库中预先定义好函数,在应用中进行调用),再将计算的结果合并后返回给应用,这就是分布式计算的意思了。
因为商业产品能够提供可靠性保障,又能节约咱们的人力投入,项目预算也足够,何乐而不为。后面的实施状况证实,这个产品性能与稳定性仍是不错的,能将查询时间下降到几十毫秒级,固然也比较耗费内存与CPU(3台服务器,每台10G内存起)。
互联网应用由于服务器规模庞大,为了节约成本必须去IOE化,大量采用廉价服务器与开源软件。企业应用由于规模小,相比之下,服务器资源没有那么大的规模,高配置的硬件成本企业还能负担。该项目中采用IBM服务器,EMC存储,思科的交换机,F5硬负载均衡器。
这种经过硬件来提高性能的方式,在成本容许的条件下,是能够节省力气的。采用了专用存储,其自身已经作了冗余机制,提供了灾备的解决方案。应用层面就不用再去考虑数据灾备的问题。硬盘坏了,就换个新硬盘插上去就行了,由于作了RAID10/5已经保证了数据不丢失。若等研究完几个月的HDFS,终于敢用到项目里面,项目工期已经结束了。
采用Oracle数据库RAC集群,提供了数据库层面的高可用性。
采用IBM Websphere来部署重要业务系统,例如接口查询子系统。它自身提供了软负载均衡和集群功能,可经过Web界面来对应用服务器集中管理与监控。这样应用层的高可用也获得了解决。(在咱们的重要业务场景中,接口查询是无状态的,会话不须要进行复制,也就是采用粘连性会话便可)。
业务场景中,省运营平台还须要下发控制指令,运营参数等信息到各个路段。同时路段上传的大量流水数据,若是先缓冲到消息服务器中,则拆分子系统能够直接从消息服务器读取数据,多线程处理或者单线程部署多份,部署模式很是灵活。同时引入消息中间件还能够下降各个子系统的耦合度。
开源的有ActiveMQ、RabbitMQ,商用的也了解了下IBM MQ。比较诧异的是IBM MQ的并发性能测试指标很是差,比前二者都弱。
最终咱们采用了开源的RabbitMQ,看重的是它的并发性能和对于高可用以及灾难转移的支持。目前将服务端部署在省运营平台,路段只使用客户端进行链接。这样也是考虑到部署与运维成本,路段的各合做方技术水平有限,分散部署不利于故障诊断。
通常大点的系统都有必要划分红多个子系统,易于团队并行开发,部署升级也快。核心业务系统,咱们能够集群多部署一些实例,多给点硬件资源。不重要的业务系统,配置管理类的,甚至单实例部署,直接部署到Tomcat上。同时有些后台服务,自己就是一个Java进程,与数据库相关的,设计时就限定了只能部署一个实例。
子系统和子系统之间,能够经过消息服务器来解耦,一个子系统宕机,不会影响另外的子系统运行。
在整个系统的实施过程当中,咱们引入了Portal门户、统一用户管理、单点登陆来进行不一样Web之间页面级的集成。
借鉴公司私有云建设的成功经验(基于Vmware的产品组件),咱们认为能够经过对服务器进行虚拟化来充分利用资源,下降成本,也便于集中进行运维管理。
在实施过程当中,咱们将3台豪华配置服务器虚拟出近百台服务器,同时为Oracle作集群留下了2台较高配置的服务器。
若是不进行虚拟化,可能须要更多的服务器,同时多个应用部署在一台服务器上,运维监控起来很是麻烦。虚拟化后,能够根据业务场景动态对服务器资源进行分配,这也是云计算机的特色。
值得注意的是,在虚拟机上部署集群应用时,要确保把节点分布到不一样的物理机器上,这样才能真正保证高可用性。
前文提到,高清图片数据量大,若集中存储到省平台耗费存储容量。用专用存储来存这些图片,有些浪费。若将图像从路段传输到省平台,也将浪费大量的通讯带宽。
实际业务场景中,收费站只在某些特定场景才调用图像查询接口,访问量并不大。也就是说只有很是少的图片真正须要被读取。因而咱们定义了HTTP接口规范,由路段提供服务端实现,省平台负责调用。由于HTTP接口简单易于实现,给各路段增长的工做量很小。
也就是说,这里咱们牺牲了图像的查询性能,节约了带宽与存储。
已有系统的接口方式都是经过中间数据库来实现的,考虑到引入新的接口方式,路段太多,对合做公司的技术能力与集成工做量都将大大增长。因而咱们遵循了之前的方式,定义了中间表规范,由各个路段负责提供一套中间数据库,往其中写数据。
考虑到现有系统各类类型的数据库都存在,因而咱们采用了开源数据抽取工具Kettle来进行数据迁移。同时数据库抽取的数据量较大,各类不一样的业务表结构,若是开发接口程序去实现,则工做量会很大,稳定性也是难以保证。
为了保证数据抽取的效率,每10个路段分为一组,部署一套Kettle抽取程序去作搬迁。
也就是说,这里咱们考虑到现实技术条件,用最简单适用的方式去实现业务功能。实际实施下来,这种数据抽取的方式为项目节省了不少时间。
用户与组织机构信息是存储在公用数据库中的。可是用户的角色、可访问的资源、以及资源URL等信息在各个子系统中是不同的。为了提高性能,各个子系统将用户和组织机构信息缓存到内存中,对于受权与访问控制这块的功能,经过代码级别(class文件或者Jar包)的重用实现复用。
实际上,若是子系统数量愈来愈多,是能够把用户认证与受权以及查询用户信息这块的功能服务化,包装成HTTP REST服务或RPC调用服务。考虑到项目的工期,以及开发的成本,咱们并无这样为了技术而技术,直接经过数据库访问做接口和缓存用户信息来提高性能。
注意这里对用户信息做缓存时必定要设置时效性,例如5分钟。
下章节表述的是系统的总体架构,用来讲明各个子系统及业务组件的划分与所处的层次,还未细化到足以指导开发工做的程度。
1) 基础设施层为服务器、交换机、路由器、防火墙、安全防御、磁带备份等硬件网络设备。还包括虚拟化软件与操做系统。
2)中间件层为商用的数据库、应用服务器、内存数据库以及开源的消息中间件、数据抽取软件。
3) 服务组件层为可复用的业务组件,二次开发框架。
4)业务应用层为各个业务子系统。
1) Kettle将抽取到的流水数据存入数据库,同时写入到消息服务器RabbitMQ。
2)GemFire从流水数据库装载最近几天的流水数据到内存。
3)接口查询服务调用GemFire的客户端API查询入口流水。
4)交易流水拆分服务从消息服务器读取数据进行处理,将拆分结果写入业务数据库。
5) 各个Web子业务系统须要依赖CAS服务实现单点登陆。
6)由统一用户管理系统集中管理用户与组织机构信息。
7)单点登陆服务从用户数据库查询用户信息以实现集中认证。
8)Portal门户将各个Web子业务系统集成起来。
因为子系统设计会涉及到公司具体的业务,这里不作进一步描述。设计时只要按照通用功能抽取,不一样业务功能划分不一样子系统原则便可。
一般子系统设计中须要描述清楚具体的功能模块设计,业务处理流程,开发包划分,领域模型,关键的类图,内部接口及外部接口的规范。
玩过即时战略类电子游戏的朋友,都知道何时采矿,几个农民采一堆最大效率,何时造什么兵种来克制对方,何时侦查与扩张,做战时候多兵种如何摆阵配合才能发挥最佳优点。这里不妨做一下类比,架构设计就是实施战略的过程,具体的技术是兵种武器,模式理论就是各类战术。