微服务学习
SOA-> Dubbo
现在Spring Cloud提供了一站式微服务解决方案
1.2 微服务架构引入
1) 单体应用架构 Monolithic Architecture
pros:
- 简单,解决bug方便
cons:
- 耦合性太强
- 新增业务困难
5) 垂直架构 vertical architecture
整个模块拆成子模块部署在不同机器。
pros:
- 系统相互独立
- 分流
- 水平扩展方便
cons:
- 服务之间相互调用,如果一个ip改了,则要手动改ip
- 服务之间协议不统一
- 监控不到位
6) SOA
Service Oriented Architect
7) 微服务
拆分粒度更小。 微服务架构和SOA架构拆分粒度不同。
pros:
- 根据特定业务功能聚焦
- 团队合作一定程度解耦
cons:
- 分布式复杂难以管理
- 链路跟踪难
1.4 服务注册与发现
服务注册:提供服务的信息
服务发现:服务消费者
有一个服务注册中心。
1.7 spring cloud是什么
是一个有序框架的集合。
1.8 spring cloud解决的问题以及核心组件
解决服务注册 service discovery、发现 configuration management 、负载均衡 、熔断 circuit breakers 等问题。采用组件机制(框架)定义一系列组件。
- 注册中心 service registration and discovery
- 客户端负载均衡 load balancing
- 熔断器 circuit breakders
- 网关 routing
- 配置中心 distributed / versioned configuration
- 调用服务 service-to-service calls
- 消息驱动 distributed messaging
- 链路追踪 global locks
- leadingship election and cluster state
1.9 Spring Cloud体系结构
- 网关统一协议 integrate different parts of ms
- 消费服务者,有负载均衡、熔断器组件
- 服务提供者需要把服务注册到注册中心
- 当服务提供者需要修改配置时候,可以通过配置中心集群发消息给服务提供者,这样就避免了登录服务提供者手动一个一个修改配置,从而达到自动修改配置
1.10 Spring cloud与 Dubbo与 spring boot的关系
spring cloud首选,相比Dubbo,一站式服务,Dubbo 还需要 zookeeper。
spring cloud 相比于 spring boot,是在spring boot 基础上使用,spring boot 可以单独使用,springboot 整合了springmvc 和一些常用组件,解决了包冲突的一些问题,使得开发跟你简介。Spring Cloud是给微服务提供的架构。
2.1 一个简单的FDS应用
三个模块。
总的pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.fds.wn</groupId> <artifactId>fds-parent</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>fds-order-deliver</module> <module>fds-score-serivice</module> <module>fds-rule-service</module> <module>fds-detect-service</module> <module>fds-common</module> </modules> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent> <dependencyManagement> <dependencies> <!--spring cloud依赖管理,引入了Spring Cloud的版本--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!--web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--日志依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency> <!--测试依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--lombok工具--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.4</version> <scope>provided</scope> </dependency> <!-- Actuator可以帮助你监控和管理Spring Boot应用--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!--eureka server 需要引入Jaxb,开始--> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.2.10-b140310.1920</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version> </dependency> <!--引入Jaxb,结束--> </dependencies> </project>
1) fds-common
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.fds.wn</groupId> <artifactId>fds-parent</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>fds-common</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!--Spring Data Jpa--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies> </project>
package com.fds.wn.pojo; import lombok.Data; @Data public class Order { private int orderId; private double score; private boolean isFraud; }
2) fds-order
controller (restful api接收前端请求)
package com.fds.wn.controller; import com.fds.wn.pojo.Order; import com.fds.wn.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/orders") public class ResumeController { @Autowired private OrderService orderService; @GetMapping("/serchorder/{orderId}") public Order findOrderById(@PathVariable Integer orderId) { return orderService.findOrderById(orderId); } }
dao (连接数据库,我这里写的不全)
package com.fds.wn.dao; import com.fds.wn.pojo.Order; /** * Used to do transaction with database */ interface OrderDao { Order findOrderById(int id); }
service (处理逻辑)
package com.fds.wn.service.impl; import com.fds.wn.dao.OrderDaoImpl; import com.fds.wn.pojo.Order; import com.fds.wn.service.OrderService; import org.springframework.stereotype.Service; @Service public class OrderServiceImpl implements OrderService { public Order findOrderById(int id) { OrderDaoImpl orderDao = new OrderDaoImpl(); return orderDao.findOrderById(id); } }
package com.fds.wn.service; import com.fds.wn.pojo.Order; import org.springframework.web.bind.annotation.RestController; public interface OrderService { Order findOrderById(int id); }
3) fds-score
远程调用可以用RestTemplate
package com.fds.wn; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class CheckScoreApplication { public static void main(String[] args) { SpringApplication.run(CheckScoreApplication.class, args); } @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } }
package com.fds.wn.controller; import org.springframework.beans.factory.annotation.Autowired; import com.fds.wn.pojo.Order; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/scoreservice") public class OrderScoreController { @Autowired private RestTemplate restTemplate; @GetMapping("/checkscore/{orderId}") public Boolean checkScoreByOrderId(@PathVariable Integer orderId) { // 远程调用 RestTemplate // http 要封装很多内容 Order order = restTemplate.getForObject("http://localhost:8080/orders/serchorder/" + orderId, Order.class); if (order != null) return order.getScore() > 0.5; return false; } }
问题:
- 在服务消息中,url硬编码
- 服务提供者只有一个服务,需要自己实现负载均衡
- 不清楚服务提供者的状态
- 出现故障,没有熔断机制
- 能不能像Dubbo
- 配置文件每次需要修改
- 不能统一认证,每个服务都要登录
微服务需要解决的问题:
- 自动注册与发现
- 负载均衡
- 熔断
- 远程调用 Feign(不需要拼url调用)
- 网关拦截
- 统一认证
- 集中配置管理,配置信息实时更新
3.2 Eureka 服务注册中心
一般原理:
服务提供者 (ip, 端口,名称)-> 服务注册中心 -> 服务消费者
还可以添加一些负载均衡、熔断服务。
4.16 Feign
不需要使RestTemplate api 不用拼接url。使用Feign 非常简单,在消费者处使用。
Feign = RestTemplate + Ribbon + Hystrix
5.1 GateWay
这里是指 SpringCloud GateWay 网关。为微服务架构听一种简单有效的API路由管理方式 。可以做ip限制,限流的控制。网关转发请求到下游的微服务,叫做路由,也叫做API路由。
(下)1.1 链路追踪
动态展示服务之间的就是依赖关系的追踪
(下)1.10 统一认证主流方案
认证:验证用户的合法身份, 比如输入账号和密码。
1) 基于Session 方式
Sessionid 存在客户端的 cookie中,Session 在内存查找 sessionid 就可以。通过Session共享来实现各个组件的认证同步服务
缺点:浏览器可以,但是移动端支持比较差
2)基于token 方式
服务端不用存储认证数据,客户端可以把token存在任何地方。主流方式
缺点:token 保存在客户端,包含自信息,数据量比较大,每次请求都传递,占用带宽。token也会给CPU带来额外的负担 (需要算法来解密token)
(下)1.11 OAuth2
- 可以从第三方那里获取登录权限。(登录一个网站,可以通过qq方式登录)授权码 换token
- 密码式 password 换token
- 隐藏式
- 客户端凭证
1) 方式2开发思路
2)搭建
需要配置configure. token 需要存储
(下)1.20 JWT
如果服务很多 都需要认证 则上述方案无法用。不是一个普普通通的字符串。当令牌传递到资源服务器时候,资源服务器完成校验,不再请求认证服务了。
用户认证通过了,发给一个JWT令牌。资源服务完成校验。
json web token。加密解密. 就是一个数据格式
三部分
1) header
- alg: "HS256" 算法
- typ: "JWT"
2) payload
- sub:
- name:
- iat:
一些负载信息
3)signature
防止jwt内容被篡改。使用base64url 将前两部分进行编码
HS256(
base64url (header) + "." +
base64url (payload), secret
)