互联网金融系统分布式应用实践与挑战

来源:互联网 发布:ubuntu sd卡挂载 编辑:程序博客网 时间:2024/06/07 15:03

1 互联网金融下的技术选型

1.1 分布式架构-微服务

对于一个用户访问量比较大的互联网系统,当用户数达到一定数量时,系统总会存在瓶颈或处理极限,即很难做出快速响应,处理效率逐步低下。对于如何应对用户量不断增长的情形,较直观的方案就是采用分布式系统架构。

微服务架构(MSA),在2014年开始受到关注。现在越来越多的公司开始从单体式架构迁移到微服务架构,比如AmazoneBayNetFlix都已完成迁移。互联网金融业务复杂多样,简单的单休式设计已不能满足其需要,更多的采用微服务架构建系统。微服务架构,是从单体式应用、面向服务架构(SOA)发展而来的。

1.1.1 单体式应用

架构模型:系统只有一个应用,相应地,代码放在一个工程里管理;打包成一个应用;部署在一台机器;在一个DB里存储数据。

单体式应用采用分层架构,按照调用顺序,从上到下一般为表示层、业务层、数据访问层、DB层,表示层负责用户体验,业务层负责业务逻辑,数据访问层负责DB层的数据存取。

1.1.2 面向服务架构(SOA

面向服务的体系结构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种这样的系统中的服务可以以一种统一和通用的方式进行交互。

现在SOA系统一般通过web service实现的。WSDLUDDISOAPSOA基础的基础部件。WSDL用来描述服务;UDDI用来注册和查找服务;而SOAP,作为传输层,用来在消费者和服务提供者之间传送消息。SOAPWeb服务的默认机制,其他的技术为可以服务实现其他类型的绑定。一个消费者可以在UDDI注册表(registry)查找服务,取得服务的WSDL描述,然后通过SOAP来调用服务。SOA系统的实现都需要企业服务总线(ESB)支持。

1.1.3 微服务架构(Microservices

对微服务架构我们没有一个明确的定义,但简单来说微服务架构是:采用一组服务的方式来构建一个应用,服务独立部署在不同的进程中,不同服务通过一些轻量级交互机制来通信,例如 RPCHTTP等,服务可独立扩展伸缩,每个服务定义了明确的边界,不同的服务甚至可以采用不同的编程语言来实现,由独立的团队来维护。

理论基础

微服务架构的理论甚而是康威定律康威定律(Conway's law)指出:organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations.

任何设计系统的组织,最终产生的设计等同于组织之内、之间的沟通结构。

由于微服务尽量都是通过HTTP API(推荐RESTful架构)的方式暴露出去的,因此这种服务管理平台不需要像传统企业内部的ESB服务总线这么重。但是最基本的服务注册服务代理服务发布服务简单的路由安全访问和授权服务调用消息和日志记录这些功能还是需要具备。类似淘宝的Dubbo架构,即可以做为微服务架构下的服务管控平台。

微服务架构模式下,每一个服务实例都是一个Docker容,服务实例前是一层诸如NGINX的负载均衡器,他们负责在各个实例间分发请求。负载均衡器也同时处理其它请求,例如缓存、权限控制、API统计和监控微服务架构每,每个服务都有自己的数据库,需要处理分布式事务相关问题。

SOA不同

微服务架构模式有点像SOA,他们都由多个服务构成。但是,可以从另外一个角度看此问题,微服务架构模式是一个不包含Web服务(WS-)和ESB服务的SOA。微服务应用乐于采用简单轻量级协议,比如REST,而不是WS-,在微服务内部避免使用ESB以及ESB类似功能。微服务架构模式也拒绝使用canonical schemaSOA概念。

微服务架构的好处

微服务架构模式有很多好处:

首先,通过分解巨大单体式应用为多个服务方法解决了复杂性问题。在功能不变的情况下,应用被分解为多个可管理的分支或服务。每个服务都有一个用RPC-或者消息驱动API定义清楚的边界。微服务架构模式给采用单体式编码方式很难实现的功能提供了模块化的解决方案,由此,单个服务很容易开发、理解和维护。

第二,这种架构使得每个服务都可以有专门开发团队来开发。开发者可以自由选择开发技术,提供API服务。

第三,微服务架构模式是每个微服务独立的部署。开发者不再需要协调其它服务部署对本服务的影响。这种改变可以加快部署速度。UI团队可以采用AB测试,快速的部署变化。微服务架构模式使得持续化部署成为可能。

最后,微服务架构模式使得每个服务独立扩展。你可以根据每个服务的规模来部署满足需求的规模。甚至于,你可以使用更适合于服务资源需求的硬件。比如,你可以在EC2 Compute Optimized instances上部署CPU敏感的服务,而在EC2 memory-optimized instances上部署内存数据库。

微服务架构的挑战

微服务架构模式面临很多挑战:

1. 系统边界如何划定。怎么有效的拆分应用,实现敏捷开发和部署。

2. 微服务应用是分布式系统,由此会带来固有的复杂性。开发者需要在RPC或者消息传递之间选择并完成进程间通讯机制。相应的增加了服务间通信成。

3. 对于数据库架构。单体式应用只有一个数据库。在微服务架构应用中,需要更新不同服务所使用的不同的数据库。分布式事务的一致性需要特别关注。

4. 微服务架构的应用测试,对一个单体式web应用,测试它的REST API,是很容易的事情。反过来,同样的服务测试需要启动和它有关的所有服务(至少需要这些服务的stubs)。需要系统集成测试。

5. 系统部署依赖使部署复杂,一个微服务应用一般由大批服务构成。每个服务都有多个实例。这就造成许多需要配置、部署、扩展和监控的部分,除此之外,你还需要完成一个服务发现机制(后续文章中发表),以用来发现与它通讯服务的地址(包括服务器地址和端口)。成功部署一个微服务应用需要开发者有足够的控制部署方法,并高度自动化。  一种自动化方法是使用PaaS服务,例如Cloud FoundryPaaS给开发者提供一个部署和管理微服务的简单方法,它把所有这些问题都打包内置解决了。同时,配置PaaS的系统和网络专家可以采用最佳实践和策略来简化这些问题。另外一个自动部署微服务应用的方法是开发对于你来说最基础的PaaS系统。一个典型的开始点是使用一个集群化方案,比如配合Docker使用Mesos或者Kubernetes

1.2 分布式缓存与NoSQL 

在一些高并发高性能的场景中,使用cache可以减少对后端系统的负载,承担可大部分读的压力,可以大大提高系统的吞吐量,比如通常在数据库存储之前增加cache缓存。但是引入cache架构不可避免的带来一些问题:cache命中率的问题、cache失效引起的抖动、cache和存储的一致性。

cache中的数据相对于存储来讲,毕竟是有限的,比较理想的情况是存储系统的热点数据,这里可以用一些常见的算法LRU等等淘汰老的数据;随着系统规模的增加,单个节点cache不能满足要求,就需要搭建分布式Cache;为了解决单个节点失效引起的抖动 ,分布式cache一般采用一致性hash的解决方案,大大减少因单个节点失效引起的抖动范围;而对于可用性要求比较高的场景,每个节点都是需要有备份的。数据在cache和存储上都存有同一份备份,必然有一致性的问题,一致性比较强的,在更新数据库的同时,更新数据库cache。对于一致性要求不高的,可以去设置缓存失效时间的策略。

数据库和缓存的不一致

Cache的常用用法:

对于写操作:会先淘汰cache,再写数据库。

对于读操作:先读cache,如果cache hit则返回数据,如果cache mis则读数据库,然后把读出来的数据再入缓存。

这样会引发严重的一致性问题,考虑这样一个特殊的时序:

1. 先来了一个写请求,淘汰了cache,但未写数据库;

2. 又来了一个读请求,读cachecache miss了,然后读库,此时写请求还没提交,于是读了一个脏数据,接着脏数据入缓存;

3. 最后写请求写入数据库;

这个时序会导致脏数据一直在缓存中没有办法被淘汰掉,数据库和缓存中的数据严重不一致。

三个实践:

1. 缓存双淘汰,针对读写分离的情况。传统的作法在进行写操作的时候,先淘汰cache再写主库。上文提到,在主从同步时间窗口之内可能有脏数据入cache,此时如果再发起一个异步的淘汰,即使不一致时间窗内脏数据入了cache,也会再次淘汰掉。这样大降低了cache中入脏数据的概率,但不能完全杜绝。

2. 为所有item设定超时时间,例如10分钟。极限时序下,即使有脏数据入cache,这个脏数据也最多存在十分钟。带来的副作用是,可能每十分钟,这个key上有一个读请求会穿透到数据库上,产生cache失效引起的抖动。

3. 数据修改后设置缓存临时超时时间(临时超时时间只是修改数据时淘汰缓存临时使用的,不是该缓存新增时的超时时间,新增该缓存时可以不设超时时间)

临时超时时间 > 设置临时超时时间开始到事务完成这个区间的时间+数据库同步时间(读写分离

使用时要结合实际业务情况,像我们公司没有做严格的读写分离,在使用时设置redis的超时时间,对于写操作,写后淘汰cache,写操作和淘汰cache是一个事务,如果删除缓存失败,事务回滚。这样也就保证了数据库与缓存的一致性。

常见nosql实现

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的速度。 

Redis是一个key-value存储系统。Memcached一样,为了保证效率,数据都是缓存在内存中,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。

Mongodb是文档型的非关系型数据库,其优势在于查询功能比较强大,能存储海量数据。

一些数据库和缓存服务器的特性与功能

见下图:

名称

类型

数据存储选项

查询类型

附加功能

Redis

使用内存存储(in-memory)的非关系数据库

字符串、列表、集合、散列表、有序集合

每种数据类型都有自己的专属命令,另外还有批量操作(bulk operation)和不完全(partial)的事务支持

发布与订阅,主从复制(master/slave replication),持久化,脚本(存储过程,stored procedure)

memcached

使用内存存储的键值缓存

键值之间的映射

创建命令、读取命令、更新命令、删除命令以及其他几个命令

为提升性能而设的多线程服务器

MySQL

关系数据库

每个数据库可以包含多个表,每个表可以包含多个行;可以处理多个表的视图(view);支持空间(spatial)和第三方扩展

SELECT、 INSERT、 UPDATE、 DELETE、函数、存储过程

支持ACID性质(需要使用InnoDB),主从复制和主主复制 (master/master replication)

PostgreSQL

关系数据库

每个数据库可以包含多个表,每个表可以包含多个行;可以处理多个表的视图;支持空间和第三方扩展;支持可定制类型

SELECT、 INSERT、 UPDATE、 DELETE、内置函数、自定义的存储过程

支持ACID性质,主从复制,由第三方支持的多主复制(multi-master replication)

MongoDB

使用硬盘存储(on-disk)的非关系文档存储

每个数据库可以包含多个表,每个表可以包含多个无schema(schema-less)的BSON文档

创建命令、读取命令、更新命令、删除命令、条件查询命令等

支持map-reduce操作,主从复制,分片,空间索引(spatial index)

 

1.3 关系型数据库下的分布式应用

1.3.1 读写分离

读写分离是对数据库来讲的,随着系统并发量的增大,提高数据访问可用性的一个重要手段就是写数据和读数据进行分离;当然在读写分离的同时,需要关注数据的一致性问题;对于一致性的问题,在分布式的系统CAP定量中,更多的关注于可用性。

1.3.2 分库分表

分库分表一般分四种形式:垂直分表、垂直分库、水平分表、水平分库分表。

垂直分表

即大表拆小表:需要改写以前的查询语句,会额外带来一定的成本和风险,建议谨慎

 

垂直分库

基本的思路就是按照业务模块来划分出不同的数据库,而不是像早期一样将所有的数据表都放到同一个数据库中。 

 

水平分表 

水平分表也称为横向分表,比较容易理解,就是将表中不同的数据行按照一定规律分布到不同的数据库表中(这些表保存在同一个数据库中),这样来降低单表数据量,优化查询性能。最常见的方式就是通过主键或者时间等字段进行Hash和取模后拆分

水平分表,能够降低单表的数据量,一定程度上可以缓解查询性能瓶颈。但本质上这些表还保存在同一个库中,所以库级别还是会有IO瓶颈。所以,一般不建议采用这种做法。

 

水平分库分表

水平分库分表与上面讲到的水平分表的思想相同,唯一不同的就是将这些拆分出来的表保存在不同的数据中。这也是很多大型互联网公司所选择的做法。

某种意义上来讲,有些系统中使用的“冷热数据分离”(将一些使用较少的历史数据迁移到其他的数据库中。而在业务功能上,通常默认只提供热点数据的查询),也是类似的实践。在高并发和海量数据的场景下,分库分表能够有效缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源的瓶颈。当然,投入的硬件成本也会更高。同时,这也会带来一些复杂的技术问题和挑战(例如:跨分片的复杂查询,跨分片事务等)

 

   垂直分库带来的问题和解决思路:

   跨库join的问题:在拆分之前,系统中很多列表和详情页所需的数据是可以通过sql join来完成的。而拆分后,数据库可能是分布式在不同实例和不同的主机上,join将变得非常麻烦。而且基于架构规范性能安全性等方面考虑,一般是禁止跨库join的。那该怎么办呢?首先要考虑下垂直分库的设计问题,如果可以调整,那就优先调整。如果无法调整的情况,下面笔者将结合以往的实际经验,总结几种常见的解决思路,并分析其适用场景。

1. 全局表:所谓全局表,就是有可能系统中所有模块都可能会依赖到的一些表。比较类似我们理解的“数据字典”。为了避免跨库join查询,我们可以将这类表在其他每个数据库中均保存一份。同时,这类数据通常也很少发生修改(甚至几乎不会),所以也不用太担心“一致性”问题。

2. 字段冗余:这是一种典型的反范式设计,在互联网行业中比较常见,通常是为了性能来避免join查询。

3. 数据同步: 定时A库中的tab_a表和B库中tbl_b有关联,可以定时将指定的表做同步。当然,同步本来会对数据库带来一定的影响,需要性能影响和数据时效性中取得一个平衡。

4. 系统层组装: 在系统层面,通过调用不同模块的组件或者服务,获取到数据并进行字段拼装。说起来很容易,但实践起来可真没有这么简单,尤其是数据库设计上存在问题但又无法轻易调整的时候。通常,我们都会通过缓存来避免频繁RPC通信和数据库查询的开销。

总结

根据系统架构和公司实际情况来,如果你们的系统还是个简单的单体应用,并且没有什么访问量和数据量,尽量不要“垂直分库”,通过数据库分区也可以改善某些查询的性能 ,同时会避免分库带来的管理负担。架构师和技术人员应该避免“过度设计”和“过早优化”。

其实互联网的业务系统中,本来就应该尽量避免join的,如果有多个join的,要么是设计不合理,要么是技术选型有误。可以考虑通过OLAP数据仓库去实现的(现在则更多是借助离线分析、流式计算等手段实现)

 

1.4 分布式的数据一致性

分布式事务是指会涉及到操作多个数据库的事务。其实就是将对同一库事务的概念扩大到了对多个库的事务。目的是为了保证分布式系统中的数据一致性。分布式事务处理的关键是必须有一种方法可以知道事务在任何地方所做的所有动作,提交或回滚事务的决定必须产生统一的结果(全部提交或全部回滚)。

为了解决这种分布式一致性问题,前人在性能和数据一致性的反反复复权衡过程中总结了许多典型的协议和算法。其中比较著名的有二阶提交协议(Two Phase Commitment Protocol)、三阶提交协议(Two Phase Commitment Protocol)等。

 

各实现方式 比较:

 

/三阶段

Sagas 长事务

补偿模式

TCC

可靠事件模式

一致性

强一致性

强一致性

最终一致

最终一致

最终一致

吞吐量

 

 

实现复杂度

 

 

 

1.4.1 /阶段

XA规范

X/Open组织(即现在的OpenGroup)定义了分布式事务处理模型。X/Open DTP模型(1994)包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理器(CRM)四部分。一般,常见的事务管理器(TM)是交易中间件,常见的资源管理器(RM)是数据库,常见的通信资源管理器(CRM)是消息中间件。XA定义的交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。XA接口函数由数据库厂商提供。二阶提交协议和三阶提交协议根据这一思想衍生出来的

二阶段提交Two-phaseCommit

算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。所谓的两个阶段是指:第一阶段:准备阶段投票阶段和第二阶段:提交阶段(执行阶段)。

1. 准备阶段:事务协调者事务管理器给每个参与者资源管理器发送Prepare消息,每个参与者要么直接返回失败如权限验证失败,要么在本地执行事务,写本地的redoundo日志,但不提交,到达一种“万事俱备,只欠东风”的状态。

2. 提交阶段:如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚Rollback消息;否则,发送提交Commit消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。注意:必须在最后阶段释放锁资源

 

二阶段提交看起来确实能够提供原子性的操作,但是不幸的事,二阶段提交还是有几个缺点的:

1. 同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。

2. 单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)。

3. 数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。

4. 二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

由于二阶段提交存在着诸如同步阻塞、单点问题、脑裂等缺陷,所以,研究者们在二阶段提交的基础上做了改进,提出了三阶段提交。

三阶段提交(Three-phase commit

三阶段提交,是二阶段提交(2PC)的改进版本。与两阶段提交不同的是,三阶段提交有两个改动点。

1. 引入超时机制。同时在协调者和参与者中都引入超时机制。

2. 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

也就是说,除了引入超时机制之外,3PC2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommitPreCommitDoCommit三个阶段。

1. CanCommit阶段:其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

2. PreCommit阶段:参与者接收到PreCommit请求后,会执行事务操作,并将undoredo信息记录到事务日志中。

3. doCommit阶段:该阶段进行真正的事务提交,协调者向向所有参与者发送doCommit请求。参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。

PC3PC的区别

相对于2PC3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。

了解了2PC3PC之后,我们可以发现,无论是二阶段提交还是三阶段提交都无法彻底解决分布式的一致性问题。Google Chubby的作者Mike Burrows说过, there is only one consensus protocol and thats Paxos” – all other approaches are just broken versions of Paxos.意即世上只有一种一致性算法,那就是Paxos,所有其他一致性算法都是Paxos算法的不完整版。后面的文章会介绍这个公认为难于理解但是行之有效的Paxos算法。

 

1.4.2 Sagas 长事务

Sagas事务模型中,一个长事务是由一个预先定义好执行顺序的子事务集合和他们对应的补偿子事务集合组成的。典型的一个完整的交易由T1T2、……、Tn等多个业务活动组成,每个业务活动可以是本地操作、或者是远程操作,所有的业务活动在Sagas事务下要么全部成功,要么全部回滚,不存在中间状态。

实现机制:

1. 每个业务活动都是一个原子操作;

2. 每个业务活动均提供正反操作;

3. 任何一个业务活动发生错误,按照执行的反顺序,实时执行反操作,进行事务回滚;

4. 回滚失败情况下,需要记录待冲正事务日志,通过重试策略进行重试;

5. 冲正重试依然失败的场景,提供定时冲正服务器,对回滚失败的业务进行定时冲正;

6. 定时冲正依然失败的业务,等待人工干预。

特点:Sagas长事务需要交易提供反操作,支持事务的强一致性,由于没有在整个事务周期内锁定资源,对性能影响较小,适合对数据要求比较高的场景中使用。

1.4.3 补偿模式

通过重试保证补偿过程的完整,从而满足最终一致性;实现补偿模式的关键在于业务流水的记录,补偿过程作为一个服务调用过程同样存在调用不成功的情况,这个时候需要通过重试的机制来保证补偿的成功率。当然这也就要求补偿操作本身具备幂等性。 

缺点:没有隔离性。从第一个工作服务步骤开始一直到所有工作服务完成(或者补偿过程完成),不一致是对其他服务可见的。另外最终一致性的保证还充分的依赖了协调服务的健壮性,如果协调服务异常,就没法达到一致性。

TCC是优化的补偿模式,TCC模式在一定程度上弥补了上述的缺陷,在TCC模式中直到明确的confirm动作,所有的业务操作都是隔离的(由业务层面保证)。另外工作服务可以通过指定try操作的超时时间,主动的cancel预留的业务资源,从而实现自治的微服务。

1.4.4 TCC型事务

三个执行动作:

1. Try:完成所有业务检查,预留必须业务资源;

2. Confirm:真正执行业务,不作任何业务检查;只使用Try阶段预留的业务资源;Confirm操作满足幂等性;

3. Cancel:释放Try阶段预留的业务资源;Cancel操作满足幂等性;

 

整个TCC业务分成两个阶段完成:

注意:第二阶段confirmcancel操作本身也是满足最终一致性的过程,在调用confirmcancel的时候也可能因为某种原因(比如网络)导致调用失败,所以需要活动管理支持重试的能力,同时这也就要求confirmcancel操作具有幂等性。

 

举个p2p系统的例子:

p2p系统接收到投资的支付请求后,需要扣减投资人账户余额、增加投资人红包账户余额、增加借款人账户余额;再假设:投资人系统、借款人系统、红包系统是独立的三个子系统,无法通过传统的事务方式进行处理。

1. Try阶段:我们需要做的就是投资人资金账户的资金预留,

即:冻结投资人账户的金额(投资金额)

2. Confirm阶段:我们需要做的就是积分账户增加红包余额,借款人账户增加账户余额;

3. Cancel阶段:该阶段需要执行的就是解冻释放我们扣减的投资余额。

以上所有的操作需要满足幂等性,幂等性的实现方式可以是:

1. 通过唯一键值做处理,即每次调用的时候传入唯一键值,通过唯一键值判断业务是否被操作,如果已被操作,则不再重复操作。

2. 通过状态机处理,给业务数据设置状态,通过业务状态判断是否需要重复执行。

1.4.5 可靠事件模式(本地事件表、外地事件表)

可靠事件模式属于事件驱动架构,当某件重要事情发生时,例如更新一个业务实体,微服务会向消息代理发布一个事件。消息代理会向订阅事件的微服务推送事件,当订阅这些事件的微服务接收此事件时,就可以完成自己的业务,也可能会引发更多的事件发布。

可靠事件模式(本地事件表)

本地事件表方法将事件和业务数据保存在同一个数据库中,使用一个额外的“事件恢复”服务来恢复事件,由本地事务保证更新业务和发布事件的原子性。考虑到事件恢复可能会有一定的延时,服务在完成本地事务后可立即向消息代理发布一个事件。

1. 微服务在同一个本地事务中记录业务数据和事件;

2. 微服务实时发布一个事件立即通知关联的业务服务,如果事件发布成功立即删除记录的事件;

3. 事件恢复服务定时从事件表中恢复未发布成功的事件,重新发布,重新发布成功才删除记录的事件;

其中第2条的操作主要是为了增加发布事件的实时性,由第三条保证事件一定被发布。本地事件表方式业务系统和事件系统耦合比较紧密,额外的事件数据库操作也会给数据库带来额外的压力,可能成为瓶颈。

 

可靠事件模式(外地事件表)

将事件持久化到外部的事件系统,事件系统需提供实时事件服务以接受微服务发布事件,同时事件系统还需要提供事件恢复服务来确认和恢复事件。 

 

 

实现机制:

1. 业务服务在事务提交前,通过实时事件服务向事件系统请求发送事件,事件系统只记录事件并不真正发送;

2. 业务服务在提交后,通过实时事件服务向事件系统确认发送,事件得到确认后,事件系统才真正发布事件到消息代理;

3. 业务服务在业务回滚时,通过实时事件向事件系统取消事件;

4. 如果业务服务在发送确认或取消之前停止服务了怎么办呢?事件系统的事件恢复服务会定期找到未确认发送的事件向业务服务查询状态,根据业务服务返回的状态决定事件是要发布还是取消;

该方式将业务系统和事件系统独立解耦,都可以独立伸缩。但是这种方式需要一次额外的发送操作,并且需要发布者提供额外的查询接口。可以有很多的变种实现,比如对消息可靠性不高的话,可以将本地表的方式换做缓存方式。为了提高消息投递的效率,可以将多次消息合并为投递模式。为了提供强一致性的事务保障,甚至可以将本地消息表持久化(保障发方法消息可靠落地)+远程消息表持久化(保障接收方消息可靠落地)结合的模式。

 

1.5 分布式环境下的交互-异步交互

对于平台各个系统之间的异步交互,是通过MQ组件进行的。在设计消息服务组件时,需要考虑消息一致性、持久化、可用性、以及完善的监控体系。业界开源的消息中间件主要RabbitMQkafka有两种。

RabbitMQ,遵循AMQP协议,由内在高并发的erlanng语言开发;kafkaLinkedin201012月份开源的消息发布订阅系统,它主要用于处理活跃的流式数据,大数据量的数据处理上。对消息一致性要求比较高的场合需要有应答确认机制,包括生产消息和消费消息的过程;不过因网络等原理导致的应答缺失,可能会导致消息的重复,这个可以在业务层次根据幂等性进行判断过滤;RabbitMQ采用的是这种方式。还有一种机制是消费端从broker拉取消息时带上LSN号,从broker中某个LSN点批量拉取消息,这样无须应答机制,kafka分布式消息中间件就是这种方式。

消息的在broker中的存储,根据消息的可靠性的要求以及性能方面的综合衡量,可以在内存中,可以持久化到存储上。

对于可用性和高吞吐量的要求,集群和主备模式都可以在实际的场景应用的到。RabbitMQ解决方案中有普通的集群和可用性更高的mirror queue方式。kafka采用zookeeper对集群中的brokerconsumer进行管理,可以注册topiczookeeper上;通过zookeeper的协调机制,producer保存对应topicbroker信息,可以随机或者轮询发送到broker上;并且producer可以基于语义指定分片,消息发送到broker的某分片上。

总体来讲,RabbitMQ用在实时的对可靠性要求比较高的消息传递上。kafka主要用于处理活跃的流式数据,大数据量的数据处理上。

1.6 分布式环境下的交互-同步交互

RPC是远程过程调用的简称,广泛应用在大规模分布式应用中,作用是有助于系统的垂直拆分,使系统更易拓展。Java中的RPC框架比较多,各有特色,广泛使用的有RMIHessianDubbo等。RPC还有一个特点就是能够跨语言,本文只以JAVA语言里的RPC为例。

RMI(远程方法调用)

JAVA自带的远程方法调用工具

RMI是一组用户开发分布式应用程序的API。他使用的是java序列化机制实现调用及返回值的编组于反编组。它使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议(Java Remote Method Protocol)。他可以被看做是RPCJava版本,因为传统的RPC并不能很好的应用于分布式对象系统。而Java RMI则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。他也有它的缺点,他只能通过RMI协议来进行访问无法通过HTTP协议访问,无法穿透防火墙。RMI的作用能够让在某个Java虚拟机上的对象像调用本地对象一样调用另一个java虚拟机中的对象上的方法。

Hessian(基于HTTP的远程方法调用)

Hessian:hessian是一个轻量级的remoting on http工具,使用简单的方法提供了RMI的功能,相比WebServiceHessian更简单、快捷。采用的是二进制RPC协议,因为采用了二进制协议,所以它很适合于发送二进制数据,Hessian主要作面向对象的消息通信。Hessian的使用则与RMI类似,区别在于淡化了Registry的角色,通过显示的地址调用,利用HessianProxyFactory根据配置的地址create一个代理对象,另外还要引入HessianJar包。

 

Dubbo(淘宝开源的基于TCPRPC框架)

基于Netty的高性能RPC框架,是阿里巴巴开源的,总体原理如下:

 

节点角色说明:

l Provider: 暴露服务的服务提供方。

l Consumer: 调用远程服务的服务消费方。

l Registry: 服务注册与发现的注册中心。

l Monitor: 统计服务的调用次调和调用时间的监控中心。

l Container: 服务运行容器。

调用关系说明:

1.  服务容器负责启动,加载,运行服务提供者。

2.  服务提供者在启动时,向注册中心注册自己提供的服务。

3.  服务消费者在启动时,向注册中心订阅自己所需的服务。

4.  注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

5.  服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

6.  服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

2 互联网金融带来的挑战 

2.1 大数据

互联网金融目前已经开始不断融合大数据,运用大数据可以较为准确的预测资金的流入流出,以及用户的消费行为。譬如,各种“P2P网贷”可以利用大数据来做风控建模,以此了解贷款方的还款能力、意愿以及投资者的继续投资的倾向等等,实现风险的预先性识别。

Google的技术是云计算、大数据开源化的主要推动力之一Google的三驾马车:GoogleFSMapReduceBigTable。虽然Google没有公布这三个产品的源码,但是他发布了这三个产品的详细设计论文,奠定了风靡全球的大数据算法的基础!

l 2003年,Google发布Google File System论文,阐述了Google分布式文件系统的实现方式;

l 2004Nutch创始人Doug Cutting基于GoogleGFS论文实现了分布式文件存储系统名为NDFS

l 2004年公布的 MapReduce论文,论文描述了大数据的分布式计算方式,主要思想是将任务分解然后在多台处理能力较弱的计算节点中同时处理,然后将结果合并从而完成大数据处理。

l 2005Doug Cutting又基于MapReduce,在Nutch搜索引擎实现了大规模数据集(大于1TB)的并行分析运算。

l 2006年发布Bigtable,启发了无数的NoSQL数据库,比如:CassandraHBase等等。Cassandra架构中有一半是模仿Bigtable,包括了数据模型、SSTables以及提前写日志(另一半是模仿AmazonDynamo数据库,使用点对点集群模式)。

l 2006年,Yahoo雇用了Doug CuttingDoug CuttingNDFSMapReduce升级命名为HadoopYahoo开建了一个独立的团队给Goug Cutting专门研究发展Hadoop

2006Apache基金会接纳Hadoop项目以来。Hadoop已经成为云计算软件的一个事实标准,以及开源云计算解决方案的几乎唯一选择。对于想用低成本(包括软硬件)实现云计算平台或海量数据分析平台的用户,Hadoop集群是首选的对象。

Hadoop核心组件是3个:

1. GFSGoogle File System)。一个分布式文件系统,隐藏下层负载均衡,冗余复制等细节,对上层程序提供一个统一的文件系统API接口。Google根据自己的需求对它进行了特别优化,包括:超大文件的访问,读操作比例远超过写操作,PC机极易发生故障造成节点失效等。GFS把文件分成64MB的块,分布在集群的机器上,使用Linux的文件系统存放。同时每块文件至少有3份以上的冗余。中心是一个Master节点,根据文件索引,找寻文件块。详见Google的工程师发布的GFS论文。

2. MapReduceGoogle发现大多数分布式运算可以抽象为MapReduce操作。Map是把输入Input分解成中间的Key/Value对,ReduceKey/Value合成最终输出Output。这两个函数由程序员提供给系统,下层设施把MapReduce操作分布在集群上运行,并把结果存储在GFS上。

3. BigTable。一个大型的分布式数据库,这个数据库不是关系式的数据库。像它的名字一样,就是一个巨大的表格,用来存储结构化的数据。

2.2区块链

前段时间有人高喊“比特币已死,但区块链永存”,而区块链技术的价值也正在被国际社会接受,去年9月份开始,包括高盛、摩根大通、瑞士联合银行在内的42家银行加入R3CEV区块链联盟让一直游离在主流金融行业边缘的区块链的位置正在被扶正。

但是传统银行虽然如此主动却并不算积极,笔者认为这正是行业发展倒逼传统金融机构一次小心试探,因为区块链的去中心化就是消除传统金融机构的第三方信用中介功能。区块链作为虚拟货币的生产机制,其实更加适合互联网金融,其分布式记账,即去中心化以自证信用、开放性以及信息较难篡改特性让其在互联网金融应用层技术上极具发展前景。

 参考文献

[1] George Coulouris. Jean Dollimore.Distributed Systems: Concepts and Design[M].机械工业出版社, 2008.01

[2] 肖颖,王得燕.分布式系统的应用[J].今日科苑, 2009(24)

[3] 张晋连.数据库原理及应用[M].电子工业出版社, 2004.08

[4] George Coulouris. Jean Dollimore.Distributed Systems: Concepts and Design[M].机械工业出版社, 2008.01

[5] 刘福岩,王艳春,刘美华,王伟副主编.计算机操作系统[M].兵器工业出版社, 2005.08.

[6] 肖颖,王得燕.分布式系统的应用[J].今日科苑, 2009(24)

[7] 张晋连.数据库原理及应用[M].电子工业出版社, 2004.08

[8] 姚文平.互联网金融[M].中信出版社, 2014.01

[9] 陈康,郑纬民.云计算:系统实例与研究现状.2009,20(5):1337-1348

[10] 冯登国,张敏,张妍,徐震.云计算安全研究.2011,22(1):71-83

[11] 陈康,郑纬民.云计算:系统实例与研究现状.2009,20(5):1337-1348

[12] Apache. Apache hadoop.http://hadoop.apache.org/core/

[13] Alibaba. Alibaba dubbo.http://dubbo.io/

[14] 杨步涛. 构建高并发高可用的电商平台架构实践.2013.

http://blog.csdn.net/yangbutao/article/details/12242441/

[15] 李玉杨.巨人的进击,解析互联网金融的四大发展趋势.2016.

http://www.tmtpost.com/2241511.html 

[16] 田向阳.微服务架构下的数据一致性保证.2016.

http://dwz.cn/3TVJaB

[17] 刘相.理性撕逼分布式事务.2016.

http://blog.csdn.net/suniyadadechuentian/article/details/52848921
[18] 丁浪.分库分表的几种常见形式以及可能遇到的难题.2016.

https://www.sdk.cn/news/5072

[19] 王庆友.在首席架构师手里,应用架构如此设计.2016.

http://geek.csdn.net/news/detail/73332

0 0
原创粉丝点击