概述
CSE(Cloud Service Engine) Java SDK是华为推出的产品级微服务开发框架,已经在华为内部多个大型产品上得到了使用和验证。使用CSE Java SDK开发微服务,可以最大化的简化开发门槛,提升产品上线速度。同时可以获得微服务运行时高可靠性保证、运行时动态治理等一系列开箱即用的能力。
为了描述简单,本文会使用CSE指代CSE Java SDK,使用ServiceComb指代ServiceComb Java Chassis。
开发者可以通过微服务引擎华为云官网了解CSE。在CSE帮助中心可以获取更多产品信息,如有疑问,可通过CSE论坛进行咨询。
USER Story
本文帮助开发者开发一个完整的微服务应用。通过一个典型的应用场景,展现一个微服务应用需要解决那些问题,在不同的章节里面,会详细解释解决解决这些问题的技术原理和实现过程。CSE SDK主要功能是提供了完善的开箱即用的治理能力的RPC框架,完成完整的业务开发,还会涉及到集成和使用其他技术,这些内容也会加以详细解释。
这个应用场景,是通过收集了一些CSE用户的真实业务场景提取出来的。具体包括:
- 一个推荐的微服务设计方案;
- 认证鉴权;
- 使用mybatis访问数据库;
- 使用html+js提供界面服务;
- 上传文件;
- 使用网关和配置HTTPS;
在这个应用中,尽可能让服务小、每个微服务完全独立,没有代码上的依赖,服务之间通过REST接口相互访问。为了达到这个目的,可能会有些重复代码(包括配置类文件如pom.xml、数据模型类文件等)。开发者可以结合实际情况选择是否提供公共模块,来避免这种情况。在这个项目中选择的是用重复代码来换取自由度的方案。
在实际的代码中,我们还会遵循其他一些和微服务开发有关的原则,包括无状态设计等。这里的例子的目的是搭建一个商业可用的微服务,因此我们会在架构设计、方案设计上也给出一定的建议以及说明这样处理的目的。
本专题的涉及的代码均托管在github: https://github.com/huawei-microservice-demo/porter 。开发者可以clone一份供学习使用,或者作为正式项目的模板。
开始前,给应用取一个名字porter。
设计微服务
根据User Story,应用至少包含用户管理、文件管理等微服务,每个微服务都行使不一样的功能。下面是分解后设计的微服务结构:
- 网关:负责进行请求转发、用户认证以及其他内容,比如解决跨站访问、设置HTTP安全消息头等。通过设置防火墙,所有的请求都必须经过网关,这样就将内部服务与外部用户隔离起来,防止内部服务被非法访问。
- 文件管理:提供文件上传、删除等文件管理功能。
- 用户管理:提供认证、角色和权限管理等功能。
为了可靠性,这些服务都应该支持分布式集群部署。因此在业务逻辑中涉及到并发和负载均衡的场景,都需要考虑无状态设计。可以给网关配置域名或者在上层再挂一个弹性负载均衡器,实现网关的多实例部署。
微服务设计好以后,可以通过已有项目快速搭建项目架子。可以从:https://github.com/huawei-microservice-demo/porter 下载该项目。
初始的项目是一个maven项目,主要内容包括pom.xml文件、microservice.yam文件和一个Main函数。microservice.yam文件配置了微服务的基本信息和访问服务中心的地址。
开发界面(porter-website)
在技术选择上,界面完全由html/js/css等构成,不采用其他动态技术。因此只需要有一个可以支持静态页面的服务即可。在架构图中,界面的请求需要被网关转发,并且需要支持多实例部署,因此界面服务需要增加的功能是服务注册和发现。CSE提供了两种方法集成和使用J2EE:
- 运行于独立的web服务器中,如tomcat等;
- 运行于Spring Boot的Embeded Tomcat中。
为了部署简单,我们的示例选择了第二种方式。第一种方式也是很简单的,可以参考示例:https://github.com/huawei-microservice-demo/HouseApp/tree/master/customer-website 。
在Spring Boot中提供静态页面服务,核心问题是解决服务注册、发现能力。在Spring Boot的Embeded Tomcat中使用CSE的服务注册发现,需要完成如下步骤:
增加依赖关系
依赖关系定义了对于Spring Boot的依赖和CSE的依赖。
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>spring-boot-starter-transport</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
按照Spring Boot的惯例,需要声明项目的parent。尽管这个步骤不是必须的,但是不增加时需要手工配置很多编译插件,非常繁琐。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.5.RELEASE</version>
</parent>
配置微服务信息(microservice.yaml)
需要注意配置项cse.rest.address的端口与application.yml的server.port保持一致。application.yml是Spring Boot的配置文件,用于指定Embeded Tomcat的监听端口。microservice.yam的信息用于服务注册。另外也需要注意一下配置项servicecomb.rest.servlet.urlPattern,当使用@EnableServiceComb时,会加载CSE提供的REST框架org.apache.servicecomb.transport.rest.servlet. RestServlet,而且默认接管了/*的请求。在我们的场景下,仅仅需要提供web页面,不需要提供REST服务,这个配置项的含义就是将它的路径改为一个和静态页面不冲突的路径,以保证静态页面能够被正常访问。
APPLICATION_ID: porter
service_description:
name: porter-website
version: 0.0.1
cse:
rest:
address: 0.0.0.0:9093
servicecomb:
rest:
servlet:
urlPattern: /servicecomb/rest/*
增加静态页面
按照Spring Boot的惯例,静态页面需要放到源代码的resources/static目录。项目开始前,增加了如下静态页面和目录:
css
js
index.html
使用@EnableServiceComb启用CSE注册发现
@SpringBootApplication
@EnableServiceComb
public class WebsiteMain {
public static void main(final String[] args) {
SpringApplication.run(WebsiteMain.class, args);
}
}