1.引言
2.平台3.0整体架构设计
我们先看一下F1平台3.0整体的架构,与原有F1平台2.X osgi框架体系模式不同,微服务体系下更加讲究模块化,在功能上更深一步解耦,如下图:
新版平台做了分工更加明确的开发体系、功能体系:
模块化的前端组织形式;
基于代理的统一请求处理;
统一的开放接口-zuul;
统一的服务注册中心-eureka;
统一的配置管理-configserver;
基于oauth2的授权体系-autherserver;
基于redis缓存;
单独的数据库配置;
完整的调用链发现;
统一的日志收集;
……
3.平台四类组件
共分为四类:F1基础组件、F1微服务、F1工具包、F1微服务接口
F1基础组件:
f1-parent:负责管理平台依赖以及版本的控制,使得下层项目不需要进行繁多的依赖版本的考虑,只需要引入parent的版本即可。
f1-starter-**:该系列项目为平台启动项目,进行开发时可以根据实际功能选择性的加入到自己项目中
,也可以使用平台默认提供的f1-starter进行所有的依赖引入。
F1工具包:
根据平常的操作,总结的一套可以快速使用的工具类。
F1微服务:
平台提供的微服务,用以作为默认功能,包括:工作流、模型、文件系统、调度任务、系统配置和消息系统等一系列微服务,也是F1 3.0在微服务架构路上的先锋开拓者。
F1微服务接口:
对F1微服务提交接口,在需要通过后台请求某些微服务的功能的时候,就可以依赖对应微服务的接口,就可以通过feign、ribbon的方式对应的功能。
4.授权
授权认证基于oauth2,实现了单点登录功能。
-
外部模块发起访问请求(未授权)经过网关
-
网关判断是未授权的请求,就向授权服务器发起授权请求
-
授权服务器返回授权信息
-
网关返回认证信息到请求发起处
-
外部模块再发起请求(已授权)经过网关
-
网关判断是已授权的请求,就放行。
具体授权流程如下图:
5.服务调用
在单体式应用中,各个模块之间的调用是通过编程语言级别的方法或者函数来实现的。但是一个基于微服务的分布式应用是运行在多台机器上的(不同的进程)。一般来说,每个服务实例都是一个进程。因此,服务之间的交互必须通过进程间通信(IPC)来实现。
进程间通信方式主要包括: 管道、系统IPC(包括消息队列,信号量,共享存储)、SOCKET、httpRestfull、webService。spring cloud中是通过httpRestfull来实现的进程间通信,具体是通过eureka客户端中的ribbon对httpRestfull进行封装。
Eureka Server实现服务注册中心,通过Ribbon实现软负载均衡. Ribbon工作在服务的调用方,负载均衡分成两步,第一步先选择 Eureka Server, 它优先选择在同一个Zone且负载较少的Eureka server, 第二步从Eureka中获取到目标服务全部可用的地址,再根据用户指定的策略,从列表中选择一个地址作为最终要发请求的目标服务器。
有时候被访问的微服务出现了问题,导致请求的堆积,Eureka 提供了几种方式解决这个问题:
• 网络超时:当等待响应时,不要无限期的阻塞,而是采用超时策略。使用超时策略可以确保资源不会无限期的占用。
• 限制请求的次数:可以为客户端对某特定服务的请求设置一个访问上限。如果请求已达上限,就要立刻终止请求服务。
• 断路器模式:记录成功和失败请求的数量。如果失效率超过一个阈值,触发断路器使得后续的请求立刻失败。如果大量的请求失败,就可能是这个服务不可用,再发请求也无意义。在一个失效期后,客户端可以再试,如果成功,关闭此断路器。
调用方式:spring cloud提供了两种方式供我们使用,feign方式以及ribbon方式。
feign:预定义的服务调用
ribbon:根据服务ID动态调用服务
6.数据库访问
F1平台引入spring-boot-starter-data-jpa来实现对Hibernate的引入。
平台的f1-data模块提供:
1.功能强大的泛型Dao,实现了常用的数据存取和业务逻辑功能。2.对多数据源的支持,可以动态切换数据源。
平台的f1-starter-data模块提供了自动装配功能,自动装配datasource、泛型Dao和事务管理器。
7.缓存
为了提高网站的负载能力,需要将一些访问频率较高,且经过复杂计算或者IO资源消耗较大的操作的结果缓存起来。每次用户访问的时候,先检查该键是否存在,如果存在直接获取该元素并返回,如果不存在,则经过一系列计算并将结果缓存,再返回给用户。
平台使用redis做为缓存,通过引入spring-data-redis来访问redis中的数据。
平台的f1-starter-cache模块自动装配redisTemplate和缓存管理器。
redis是当今很流行的一个开源的NoSQL数据库。用Key-Value的形式存放数据,在大负载下的性能很优异。
对于变化频率非常快的数据来说,如果还选择传统的静态缓存方式(Memocached、File System等)展示数据,可能在缓存的存取上会有很大的开销,并不能很好的满足需要,而Redis这样基于内存的NoSQL数据库,就非常适合担任实时数据的容器。
8.即时推送
B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链接,但不容易直接完成实时的消息推送功能,如聊天室、后台信息提示、实时更新数据等功能,但通过轮询、长轮询、长连接、Flash Socket以及HTML5中定义的WebSocket能完成该功能需要。
轮询、长轮询、长连接三种方式都是http请求的方式,或多或少都会占用过多的请求和服务端资源。Flash Socket得要有Flash支持。WebSocket方式是只要浏览支持HTML5就可以实现,于是平台采用WebSocket的方式进行消息推送。
F1平台微服务通过服务间调用的方式,调用f1-websocket的功能把消息推送到前端。
当前端向f1-websocket建立连接后,有一个topicId和identityId, f1-websocket端会把topicId和identityId一样的websocket session存放到同一个set中,当向这个topicId和identityId发送消息时就调用对应set中的websocket session把消息推送到前端,当websocket session从前端关闭时会从对应的set中删除。
9.前后端开发分离
对于小型项目,前后端不分开(前端的开发调试依赖后端的数据)还可以,但随着项目的变大变复杂,大量的前端开发调试还要依赖于后端数据和启动服务器环境,会对开发效率有很大的影响。对此,我们的前端页面全部实行静态化,前端调试使用mock进行单元测试。后端服务在开发和调试时用junit和mock进行单元测试。开发完成后,前端通过nginx向微服务中心的zuul请求后端微服务,zuul对这些请求进行路由和负载均衡。
如下图,更加明确的前后端分离开发,前端有自己的开发环境,后台微服务同样,使得开发人员更加专注于开发。