Java 业务系统之架构升级-上篇

1,622 阅读12分钟
原文链接: zhuanlan.zhihu.com

摘要

基于JAVA不断的技术演进和丰富的社区支持,在很多业务领域,使用JAVA构建业务系统目前仍为主流。对于我比较熟悉的金融支付系统,在过去几年中,尽管主体开发语言没变,仍旧以JAVA为主进行构建,但其体系架构正在随着新技术的涌现不断更新换代。本文以我比较熟悉的支付交易系统为案例(不限于支付交易系统,所有基于JAVA构建的业务系统都可以参考借鉴),在传统以JAVA构建的支付系统中,已经存在诸多问题或瓶颈,本文重点阐述新的技术架构,尤其是微服务相关架构的实际应用和体会。

说点题外话,在技术方案上我一直崇尚的是“技术即产品”,或者也可以理解成:只有象产品一样能解决问题的技术才是好技术。(在有一段时间,有不少小伙伴为解决简单问题而使用了不实用技术即被我challenge,哈哈)其实,不光只有我是这么认为的,比如李开复老师,他也曾说过,只做有用的创新,道理是一样啦。

在这篇文章里,重点不是讨论如何设计某个系统,所以我不准备画任何系统架构图,况且每个产品、每个团队、甚至产品的不同阶段,需要的架构都是不同的。在这一篇我给出一些主流的技术的理念、方法和我们使用的体验,也许在下一篇中,可以根据实际案例再谈怎么去架构或如何为现在的技术做升级。

微服务架构观

上次跟一个朋友聊到某个银行的业务系统,也是JAVA开发的,所有的业务逻辑写在一个巨大无比的WAR包里,跑在巨重无比的WebLogic下,每次启动需要十分钟以上,不要说快速迭代了,就连每次系统的小变更对开发或运维来说都惶恐无比,因为一旦很小的变动都需要变整个WAR包,且每次变动又需要花费很久时间。

所以,对于很多老的系统架构来说,其实已经到了非拆不可的程度了。使用微服务架构观是解决这一问题的最好思路。在此我需要强调一个观点:我并不是说一定要使用微服务各种工具,而是理解微服务架构观来帮助我们解决实际问题,微服务的一系列工具就看你怎么灵活使用了。

在谈微服务之前,我们不得不先谈到SOA服务,如果一句话来谈SOA和微服务的区别,即微服务不再强调传统SOA架构里面比较重的ESB企业服务总线,同时SOA的思想进入到单个业务系统内部实现真正的组件化。

微服务其思路很简单,就是避免开发一个巨大的单体式的应用,而是将应用分解为小的、互相连接的微服务。这样做的好处很明显,除了能避免以上这个问题以外,还有很多好处:其一、实现部署分离,负载大的应用部署在配置更好的机器,启动更多的实例;其二、每个微服务独立部署,升级和迭代不影响整个系统,所以加快迭代变得可能;其三、每个服务或技术相近的服务有专门团队开发,这点对于技术管理者和开发者来讲也非常不错,比如在金融业务系统中,有些是重业务的开发团队(比如风控系统服务),有些是技术更重的团队(比如安全加密服务),所以这对团队完全是不同的要求,所以放在不同的团队非常合理。除此以外,对于一个注重安全的管理者其实还有一个额外的好处,就是便于代码管控,一个人不会拿到所有代码,除非你的团队就一个人,呵呵。

所以,优化老架构的第一步,我觉得是:拆。

微服务拆分原则

拆分原则,几个点比较关键:

1、单一职责

一个微服务专注做一件事情,这个很好理解,如果一个服务做很多事就不叫微服务了。

2、不同技术领域或业务领域需要拆分

比如,在我们给用户的服务中,包括支付服务,也包括咨询服务业务,两块根本是不同业务领域,技术实现也不一样,果断拆分。

3、拆分粒度

并不是越细越好,没有统一标准,我的经验是:

如果复用性强的服务,比如我们有一些获取市场行情的数据处理模块、支付账务处理模块,这些果断拆出来;

有些业务涉及到事务一致性保证的(涉及多张数据库表记录,通过数据库实现一致性保证),如果拆分出来,一致性保证需要在服务层面实现,又是一个课题。我建议团队资源有限,就先不要拆,如果资源OK,则一劳永逸解决。

微服务的无状态化

本来我准备先谈微服务框架的选择,考虑到我们使用微服务的一个重要目标是平行扩展,所以首先需要让服务无状态化,就是说,服务不要和用户session挂钩。这是一个前提条件。其实不光是微服务,就算是想做到负载均衡Load Balance,也一样需要实现这个前提条件。

传统的JAVA构建的业务系统往往把用户信息和状态存放在服务器内存的Session对象中,当我们使用多节点分布式架构时,Login服务和业务服务可能分散在不同节点实例,这就导致业务不可用(Session找不到用户信息)。

我建议的方案是,采用独立的Sesssion缓存,该方案有两个点需要考虑,一个是存储介质,一个是实现机制。

存储介质目前最成熟和最广泛接受的就是Redis,性能很高,支持持久化,支持集群部署,针对Redis我们还有独立章节阐述。

实现机制上,我觉得有两个方案供选择,方案一是直接使用SpringSession,SpringSession功能很多并但不一定都用的上,而且对开源的产品本来就有一个学习成本,所以还有一个方案就是参考SpringSession的理念自己实现了。具体实现机制为,使用SessionFilter进行用户请求拦截,然后通过Request包装类接管应用服务器的Session管理。在Request包装类中重写getSession方法。让用户在进行Session读写的时候去Redis中进行操作,而且使用Session的方法与过去一样,使得管理方案对用户透明。

以上独立的Sesssion缓存方案就说完了,值得再提一句的是,在系统架构初期,一定要把认证服务、Sesssion缓存服务这样的基础服务和业务服务实例独立出来,这点非常重要,避免做的越多,改的越多。

微服务框架选择

当我们完成了服务的拆分,形成了一个个微小服务的时候,我们自然需要服务注册管理、服务发现、异常机制、服务监控等配套框架,此时需要选择一个靠谱的微服务框架了,目前有两个主流框架选择:Spring Cloud或者Dubbo。

Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于阿里巴巴集团的各成员站点,在国内也非常火。Spring Cloud,是 Spring Source 的产物,Spring 社区的强大背书可以说是 Java 企业界最有影响力的组织,除了 Spring Source 之外,还有 Pivotal 和 Netfix 是其强大的后盾与技术输出。其中 Netflix 开源的整套微服务架构套件是 Spring Cloud 的核心。具体可参考下面这张图:

有关这两个框架更详细的的对比可以看这篇文章:微服务架构的基础框架选择:Spring Cloud还是Dubbo?

在这里需要说明一下Spring Boot,该开源产品是由Pivotal团队提供,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。使用Spring Boot是整个团队都不会后悔的决定,开发迅速、打包和发布及其方便(打包成一个jar便可),所以能帮助团队快速开发一套restful风格的web应用程序。而且对于之前使用Spring框架的团队来说,移植也不算大动干戈。

对我们来说,我们准备选择的是Spring Cloud。原因很简单,因为我们使用了SpringBoot作为主开发框架,SpringBoot和Spring Cloud天然整合良好,SpringBoot项目很容易就能成为SpringCloud的注册服务。

对于大部分开发者来说,不论使用Spring Cloud或者Dubbo,都需要花费时间和学习成本,此时你们要考虑的是你的业务到底有多复杂,或者微服务划分的到底有多细,当然对于很多情况,其实完全可以考虑以下替代方案。

API Gateway + Load Balance方案

一个简单的服务发现的解决方案就是使用 LoadBalancer 。你可以使用NGINX或者使用硬件LB设备,当然如果使用阿里云等云计算服务,使用LB将会是成本最低的选择。当然,缺点也一定会有,因为不是分布式处理模式,会产生性能上的瓶颈或单点故障,同时无法作为精细粒度控制(比如权限管控等),但不管怎样,这是一个不错的阶段性方案,我们很长一段时间也是这么使用的。

对外提供服务的方式不得不提的就是API Gateway。API Gateway作为系统的入口,具有服务转发、授权验证、负载均衡等作用,可以快速对外封装一系列HTTP Rest风格 API。阿里云、AWS等云服务商已经提供了完整的API Gateway服务产品,也可以使用Spring Integration Gateway来构建自己的gateway。

一般来讲,API的调用方来自于自有应用或第三方应用,渠道可能是PC网站、移动客户端等。使用API Gateway是开放业务服务的首选。

总之,如果API Gateway可以作为简单的微服务框架的实现产品,配合负载均衡,完全可以构建一个不错的微服务架构。

高性能的RPC方案

微服务架构确定后,则需要考虑的是内部服务之间的高效的RPC框架,它是架构微服务化的基础组件,它能大大降低架构微服务化的成本,提高调用方与服务提供方的调用效率,屏蔽跨进程调用函数(服务)的各类复杂细节。

RPC框架在逻辑上分为二层,一是传输层,负责网络通信;二是协议层,将数据按照一定协议格式打包和解包。

以下是有几个朋友用过或推荐的跨语言RPC框架,大家做个了解。

thrift是一个facebook开源的高效RPC框架,其主要特点是跨语言及二进制高效传输(当然,除了二进制,也支持json等常用序列化机制),官网地址:Apache Thrift - Home

Hessian是一款基于HTTP协议的RPC框架,采用的是二进制RPC协议,非常轻量级 ,且速度较快。其通讯效率高于WebService和Java自带的序列化

Avro Welcome to Apache Avro! 大名鼎鼎的Hadoop的子项目。它本身即是一个序列化框架,同时也实现RPC的功能。Avro序列化特点:支持跨语言实现,与 Apache Thrift 和Google的Protocol Buffers相比,Avro的优势在于支持动态模式,即可以不生成代码,避免了侵入性,作为POJO的DTO(数据传输对象)是不适合用代码生成的。还有Avro序列化时由于不需要字段标识符来打标签,所以使用它序列化生成的数据小(应该是现有序列化系统中最精简的了),最后它的性能也非常优秀。

除此以外,国内的nfs-rpc 淘宝牛人开源的一个RPC框架,Dubbo 为 阿里开源的一个分布式服务框架,也提供高性能和透明化的RPC远程服务调用方案。大家可以从网上找更多资料了解。

另外介绍一下 Protocol Buffers:谷歌创建的一种基于二进制连接格式的接口描述语言。在解析和网络传输方面Protocol buffers非常高效,并经历了谷歌高负荷环境的考验。

从序列化方式来看,Apache Thrift 、Google的Protocol Buffers和Avro应该是属于同一个级别的框架,都能跨语言,性能优秀,数据精简,但是Avro的动态模式(不用生成代码,而且性能很好)这个特点让人非常喜欢,比较适合RPC的数据交换。

上篇先写这么多吧,后面还有一些话题,通过消息队列构建异步的系统环境、通过Redis实现性能优化、持续集成方案、混合云带来的好处,以及一些实际案例带给大家,供探讨,谢谢!

作者:肖旻

简介:金融/支付IT,持续关注支付/跨境支付/创新金融科技-区块链,曾在银联数据、国内大型支付机构、专注外汇的初创金融科技公司工作。

微信:wx1489968049

知乎:肖旻FINTECH