页面开发推荐使用Thymeleaf。
不要使用内嵌的Tomcat,内嵌Tomcat部署Jsp项目会偶现龟速访问的情况。
确定进行微服务架构改造之前,需要考虑以下几方面的因素: 1)团队的技术人员是否已经具备相关技术基础。 2)公司业务是否适合进行微服务化改造,并不是所有的平台都适合进行微服务化改造,比如:传统行业有很多复杂垂直的业务系统。 3)Spring Cloud生态的技术有很多,并不是每一种技术方案都需要用上,适合自己的才是最好的。
每个微服务都有自己独立的数据库,那么后台管理的联合查询怎么处理?这应该是大家会普遍遇到的一个问题,有三种处理方案。
微服务相互独立,各微服务数据库也独立,后台需要展示数据时,调用各微服务的接口来获取对应的数据,再进行数据处理后展示出来,这是标准的用法,也是最麻烦的用法。
将业务关系不是很紧密的表严格按照微服务模式来拆分,这样既可以使用微服务,也避免了数据库分散导致后台系统统计功能难以实现,是一个折中的方案。
以满足业务高并发,实时或者准实时将各微服务数据库数据同步到NoSQL数据库中,在同步的过程中进行数据清洗,用来满足后台业务系统的使用,推荐使用MongoDB、HBase等。
第一种方案适合业务较为简单的小公司;
第二种方案,适合在原有系统之上,慢慢演化为微服务架构的公司;
第三种适合大型高并发的互联网公司。
待补充
session共享有很多种方式,比如使用tomcat sesion共享机制,但我比较推荐使用redis缓存来做session共享。
@Bean RestTemplate restTemplate() { return new RestTemplate(); }
String url = "http://localhost:9002/dc";
return restTemplate.getForObject(url, String.class);
@Autowired
LoadBalancerClient loadBalancerClient;
ServiceInstance serviceInstance = loadBalancerClient.choose("SMS-SERVICE");
String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/dc";
return restTemplate.getForObject(url, String.class);
下面这种访问会出错: String url = "http://SMS-SERVICE/dc"; return restTemplate.getForObject(url, String.class);
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
这种声明只能访问 eureka中注册的service名称 ,如 String url = "http://SMS-SERVICE/dc"; return restTemplate.getForObject(url, String.class); 其它访问URL的则会出错,即第一步是从eureka中找出访问地址,再访问.
builds and works with Spring Boot 2.0.x, and is not expected to work with Spring Boot 1.5.x.
build on Spring Boot 1.5.x, and are not expected to work with Spring Boot 2.0.x.
springboot2.1.0
dubbo dubbox
Netflix的Eureka:可以选择
etcd
zookeeper
Apache的Consul
可以排除,刷新困难 `运行: consul agent -dev -ui -node=cy consul agent -dev -http-port 8080 +**解决consul在其它机器无法访问的问题: consul agent -dev -client 0.0.0.0 **
` /etc/consul.d目录下合建base-config.json:
{
"ports": {
"http": 8080
}
}
命令行:consul node:节点名 Address:节点地址 Status:alive表示节点健康 Type:server运行状态是server状态 DC:dc1表示该节点属于DataCenter1 eureka 1x开源,2x要闭源了.可以选择consul. 建议大框架使用kubernetes. consul agent常用命令解读 -data-dir 作用:指定agent储存状态的数据目录,这是所有agent都必须的,对server尤其重要,因为他们必须持久化集群的状态
-config-dir 作用:指定service的配置文件和检查定义所在的位置。目录必需为consul.d,文件内容都是json格式的数据。配置详解见官方
-config-file 作用:指定一个要装载的配置文件
-dev 作用:开发服务器模式,虽然是server模式,但不用于生产环境,因为不会有任何持久化操作,即不会有任何数据写入到磁盘
-bootstrap-expect 作用: 参数表明该服务运行时最低开始进行选举的节点数,当设置为1时,则意味允许节点为一个时也进行选举;当设置为3时,则等到3台节点同时运行consul并加入到server才能参与选举,选举完集群才能够正常工作。 一般建议服务器结点3-5个。
-node 作用:指定节点在集群中的名称,该名称在集群中必须是唯一的(默认这是机器的主机名),直接采用机器的IP
-bind 作用:指明节点的IP地址,一般是0.0.0.0或者云服务器内网地址,不能写阿里云外网地址。这是Consul侦听的地址,它必须可以被集群中的所有其他节点访问。虽然绑定地址不是绝对必要的,但最好提供一个。
-server 作用:指定节点为server,每个数据中心(DC)的server数推荐3-5个。
-client 作用:指定节点为client,指定客户端接口的绑定地址,包括:HTTP、DNS、RPC 默认是127.0.0.1,只允许回环接口访问
10.-datacenter 作用:指定机器加入到哪一个数据中心中。老版本叫-dc,-dc已经失效
说明: spring cloud config 中配置的自动刷新还是有点问题: 要实现这个功能,必须使用rabbitmq,acuator,修改配置后还需要向client/refresh发送一个post请求,才能刷新配置,比较麻烦. 另一个方式是git配置hook,维护实现上比较麻烦.
建议使用apollo.
访问地址:
说明 :
profile:dev,default,test,pro等
label:git分支,如 master,dev等,一般使用master即可.
/{application}/{profile}[/{label}]
http://localhost:1101/config-client/dev/master
http://localhost:1101/config-client/defaut/master
/{application}-{profile}.yml(properties)
http://localhost:1101/config-client-dev.yml
http://localhost:1101/config-client-dev.properties
注意:无论git仓库中存放的是properties还是yml都可以通过两种方式访问.
/{label}/{application}-{profile}.yml(properties)
http://localhost:1101/master/config-client-dev.yml
http://localhost:1101/master/config-client-default.yml
注意:如果指定的profile不存在,则返回default
namespace (命名空间)
下载: https://github.com/nobodyiam/apollo-build-scripts
mysql数据库,两个,ApolloPortalDB
和ApolloConfigDB
修改配置:demo.sh
启动服务:demo.sh start
启动测试:demo.sh client
端口:
运行各服务的statup.sh,关闭则shutdown.sh
serverport在sh文件中配置
修改/opt/settings/server.properties(Mac/Linux)或C:\opt\settings\server.properties(Windows)文件,设置env为Local:
env=Local
本地配置目录位于:
Mac/Linux: /opt/data/{appId}/config-cache
Windows: C:\opt\data{appId}\config-cache
在本地开发模式下,Apollo不会实时监测文件内容是否有变化,所以如果修改了配置,需要重启应用生效。
引入pom依赖
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-mockserver</artifactId>
<version>1.1.0</version>
</dependency>
*在test的resources下放置mock的数据
文件名格式约定为mockdata-{namespace}.properties
(1)Spring Cloud组件中的Task
(2)LTS
Hystrix:客户端容错保护,特性有服务降级、服务熔断、请求缓存、请求合并、依赖隔离。
断路器增加了稳定性和灵活性,以一个系统,提供稳定性,而系统从故障中恢复,并尽量减少此故障的对性能的影响。它可以帮助快速地拒绝对一个操作,即很可能失败,而不是等待操作超时(或者不返回)的请求,以保持系统的响应时间。如果断路器提高每次改变状态的时间的事件,该信息可以被用来监测由断路器保护系统的部件的健康状况,或以提醒管理员当断路器跳闸,以在打开状态。
Hystrix Dashboard:监控显示 仪表盘,监控集群模式和单点模式,其中集群模式需要收集器Turbine配合
Turbine: 是集群收集器,服务于Dashboard的。
ribbon+hystrix
@HystrixCommand(fallbackMethod = "fallback")
public String consumer() {
return restTemplate.getForObject("http://eureka-client/dc", String.class);
}
public String fallback() {
return "fallback";
}
注意 :fallBackMetho中的形参必须与主函数一致
feign+hystrix
@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
public interface DeptClientService
{
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List<Dept> list();
@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
public boolean add(Dept dept);
}
DeptClientServiceFallbackFactory 代码:
@Component // 不要忘记添加,不要忘记添加
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
{
@Override
public DeptClientService create(Throwable throwable)
{
return new DeptClientService() {
@Override
public Dept get(long id)
{
return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭")
.setDb_source("no this database in MySQL");
}
@Override
public List<Dept> list()
{
return null;
}
@Override
public boolean add(Dept dept)
{
return false;
}
};
}
}
文章:http://www.ityouknow.com/springcloud/2018/01/20/spring-cloud-zuul.html
Spring Cloud Zuul: API服务网关,功能有路由分发和过滤。
如果只是请求转发,zuul的性能不一定比nginx低,但是如果涉及到静态资源,还是建议在前端使用nginx做一下代理。
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。 zuul有以下功能:
Authentication
Insights
Stress Testing
Canary Testing:
Dynamic Routing:动态路由
Service Migration:服务迁移
Load Shedding:减载荷
Security安全
Static Response handling
Active/Active traffic management
网关是最后与用户交互的页面,访问地址:http://localhost:9001/sms-service-consumer/dcs
其中是sms-service-consumer 是consumer在eureka注册的服务,dcs是具体的访问地址,通过要eureka取得该服务的具体地址,可以实现用户的访问 .同时在这个层面还可以加上各种filter及权限控制及核验逻辑,服务聚合,统一的异常处理 ,等;同时使得相应的服务提供者更加纯粹.
添加Spring Retry依赖
首先在spring-cloud-zuul项目中添加Spring Retry依赖。
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
再配置文件中配置启用Zuul Retry
#是否开启重试功能
zuul.retryable=true
#对当前服务的重试次数
ribbon.MaxAutoRetries=2
#切换相同Server的次数
ribbon.MaxAutoRetriesNextServer=0
我们假设有这样一个场景,因为服务网关应对的是外部的所有请求,为了避免产生安全隐患,我们需要对请求做一定的限制,比如请求中含有Token便让请求继续往下走,如果请求不带Token就直接返回并给出提示。
首先自定义一个Filter,在run()方法中验证参数是否含有Token。
public class TokenFilter extends ZuulFilter {
private final Logger logger = LoggerFactory.getLogger(TokenFilter.class);
@Override
public String filterType() {
return "pre"; // 可以在请求被路由之前调用
}
@Override
public int filterOrder() {
return 0; // filter执行顺序,通过数字指定 ,优先级为0,数字越大,优先级越低
}
@Override
public boolean shouldFilter() {
return true;// 是否执行该过滤器,此处为true,说明需要过滤
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
logger.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString());
String token = request.getParameter("token");// 获取请求的参数
if (StringUtils.isNotBlank(token)) {
ctx.setSendZuulResponse(true); //对请求进行路由
ctx.setResponseStatusCode(200);
ctx.set("isSuccess", true);
return null;
} else {
ctx.setSendZuulResponse(false); //不对其进行路由
ctx.setResponseStatusCode(400);
ctx.setResponseBody("token is empty");
ctx.set("isSuccess", false);
return null;
}
}
}
将TokenFilter加入到请求拦截队列,在启动类中添加以下代码:
@Bean
public TokenFilter tokenFilter() {
return new TokenFilter();
}
这样就将我们自定义好的Filter加入到了请求拦截中。
当我们的后端服务出现异常的时候,我们不希望将异常抛出给最外层,期望服务可以自动进行一降级。Zuul给我们提供了这样的支持。当某个服务出现异常时,直接返回我们预设的信息。
我们通过自定义的fallback方法,并且将其指定给某个route来实现该route访问出问题的熔断处理。主要继承ZuulFallbackProvider接口来实现,ZuulFallbackProvider默认有两个方法,一个用来指明熔断拦截哪个服务,一个定制返回内容。
public interface ZuulFallbackProvider {
/**
* The route this fallback will be used for.
* @return The route the fallback will be used for.
*/
public String getRoute();
/**
* Provides a fallback response.
* @return The fallback response.
*/
public ClientHttpResponse fallbackResponse();
}
实现类通过实现getRoute方法,告诉Zuul它是负责哪个route定义的熔断。而fallbackResponse方法则是告诉 Zuul 断路出现时,它会提供一个什么返回值来处理请求。
后来Spring又扩展了此类,丰富了返回方式,在返回的内容中添加了异常信息,因此最新版本建议直接继承类FallbackProvider
。
我们以上面的spring-cloud-producer服务为例,定制它的熔断返回内容。
@Component
public class ProducerFallback implements FallbackProvider {
private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
//指定要处理的 service。
@Override
public String getRoute() {
return "spring-cloud-producer";
}
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("The service is unavailable.".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
@Override
public ClientHttpResponse fallbackResponse(Throwable cause) {
if (cause != null && cause.getCause() != null) {
String reason = cause.getCause().getMessage();
logger.info("Excption {}",reason);
}
return fallbackResponse();
}
}
当服务出现异常时,打印相关异常信息,并返回”The service is unavailable.”。
RabbitMQ
Kafka
Spring Cloud Bus : config修改完配置后各个结点都要refresh才能生效实在太麻烦,所以交给bus来通知服务节点刷新配置的。 一种最简单的方式重新一下Config Client进行重新获取,但Spring Cloud绝对不会让你这样做的,Spring Cloud Bus正是提供一种操作使得我们在不关闭服务的情况下更新我们的配置。
消费使用amqpRestTemplate非常方便.
简化研发人员对MQ使用的复杂度,弱化MQ的差异性,达到程序和MQ松耦合。 消息驱动,有Sink、Source、Processor三种通道,特性有订阅发布、消费组、消息分区。 目前为止Spring Cloud Stream只支持下面两个著名的消息中间件的自动化配置:
rabbitmq 启动:service rabbitmq-server start
spring.cloud.stream.bindings.input.destination=sms
spring.rabbitmq.host=192.168.0.37 spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest
spring.cloud.stream.bindings.input.group:只会有一个消费者会收到消息 当我们没有为应用指定消费组的时候,Spring Cloud Stream会为其分配一个独立的匿名消费组。所以,如果同一主题下所有的应用都没有指定消费组的时候,当有消息被发布之后,所有的应用都会对其进行消费,因为它们各自都属于一个独立的组中。大部分情况下,我们在创建Spring Cloud Stream应用的时候,建议最好为其指定一个消费组,以防止对消息的重复处理,除非该行为需要这样做(比如:刷新所有实例的配置等)
spring.cloud.stream.bindings.example-topic.group=aaa
当生产者将消息数据发送给多个消费者实例时,保证拥有共同特征的消息数据始终是由同一个消费者实例接收和处理。 spring.cloud.stream.bindings.input.consumer.partitioned: 通过该参数开启消费者分区功能;
spring.cloud.stream.instanceCount: 该参数指定了当前消费者的总实例数量;
spring.cloud.stream.instanceIndex: 该参数设置当前实例的索引号,从0开始,最大值为spring.cloud.stream.instanceCount参数 - 1。我们试验的时候需要启动多个实例,可以通过运行参数来为不同实例设置不同的索引值。 spring.cloud.stream.bindings.output.destination=greetings spring.cloud.stream.bindings.output.producer.partitionKeyExpression=payload spring.cloud.stream.bindings.output.producer.partitionCount=2
http://blog.csdn.net/forezp/article/details/70162074 Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案,并且兼容支持了 zipkin. 分布式服务追踪,需要搞清楚TraceID和SpanID以及抽样,如何与ELK整合。 单次请求在微服务节点中跳转无法追溯,解决任务链日志追踪问题的。
Spring Cloud Sleuth是对Zipkin的一个封装,对于Span、Trace等信息的生成、接入HTTP Request,以及向Zipkin Server发送采集信息等全部自动完成。
http://blog.didispace.com/spring-cloud-starter-dalston-8-4/ https://blog.csdn.net/forezp/article/details/70162074 在实际的应用场景中,Zipkin可以结合压力测试工具一起使用,分析系统在大压力下的可用性和性能。
从jar包和包名来看它不属于Spring Cloud的一员,但是它与Spring Cloud Sleuth的抽样日志结合的天衣无缝。乍一看它与Hystrix的Dashboard作用有重叠的部分,但是他们的侧重点完全不同。Dashboard侧重的是单个服务的统计和是否可用,Zipkin侧重的监控环节时长。简言之,Dashboard侧重故障诊断,Ziokin侧重性能优化。
针对服务化应用全链路追踪的问题,Google发表了Dapper论文,介绍了他们如何进行服务追踪分析。其基本思路是在服务调用的请求和响应中加入ID,标明上下游请求的关系。利用这些信息,可以可视化地分析服务调用链路和服务间的依赖关系.
对应Dpper的开源实现是Zipkin,支持多种语言包括JavaScript,Python,Java, Scala, Ruby, C#, Go等。
应用实现: 1.建立一个server,引用zipken-server 2.建立客户端,引入 sleuth-zipken,同时在配置中填写zipken-server中的地址 3.还可以用消息中间件实现消息收集 引入 spring-cloud-sleuth-stream 及 spring-cloud-starter-stream-rabbit 配置中增加rabbitmq的配置
Zipkin提供了可插拔数据存储方式:In-Memory、MySql、Cassandra以及Elasticsearch。接下来的测试为方便直接采用In-Memory方式进行存储,生产推荐Elasticsearch。
注意:dalson.release不支持admin server,会报错;需要使用edgeware.release.
一个云本地程序和操作模型,组成数据微服务在一个结构化的平台上。
新版本上线,然后把流量导过来,旧系统下线.只有一个版本有流量,另一个没有流量。
主要思路是在新版本在另外一套独立的资源上上线,新版本起来后将所有的流量从老版本切到新版本上来。当新版本工作正常,则删除老版本;当新版本工作有问题,则快速能切回到老版本。因此蓝绿发布看上是一种热部署的方式,目的是减少发布过程中的服务停止时间。
两个版本同时在线,观察哪个版本用户理欢迎.强调的是评估两个版本的被访问情况,评估版本的受欢迎程度,然后决策保留哪一个。
向新版本导入一部分流量,观察新版本各种表现.上线一个新版本使用实际流程测bug,稳定性、实际环境测匹配度等,类似gamma的测试。就像用金丝雀去一样,把一个新版本拿到实际环境去验证下,然后看是否能满足要求
微服务 | Spring Cloud 和 Kubernetes 哪个更好?
微服务要求或特点: 集成,扩展性,高可用,自愈
Spring Cloud 可以用来创建一个简单的基于微服务的系统的综合视角。为了构建一个能扩展到数千个服务的可扩展且有弹性的微服务系统,它就必须有一套拥有广泛的构建时和运行时能力的工具集来帮助管理和控制。使用 Spring Cloud,既能实现功能型服务(比如统计服务,账号服务以及通知服务),又能实现基础架构服务(比如日志分析,配置服务器,服务发现,认证服务等)。 单独使用 Spring Cloud 在微服务旅程上无法走得很长远,在一个完整的微服务经历中,开发者还需要考虑自动化部署,调度,资源管理,进程隔离,自愈,构建流水线等功能。在这点上,我觉得单独拿 Spring Cloud 和 Kubernetes 来比较不太公平,更公正的比较应该是 Spring Cloud + Cloud Foundry(或者 Docker Swarm)和 Kubernetes 来比较。但是那也说明,对一个完整的端到端的微服务经历,Spring Cloud 还需要补充一个应用平台,就像 Kubernetes 那样。 Kubernetes 是兼容多种语言的,因此它的服务和原语是通用的,不像 Spring Cloud 对 JVM 那样,没有针对不同的平台做优化。例如,配置是通过环境变量或者挂载文件系统传递给应用的。它没有 Spring Cloud 配置提供的那样精妙的配置更新能力。
Kubernetes 不是一个针对开发者的平台。它的目的是供有 DevOps 思想的IT人员使用。因此,Java 开发者需要学习一些新的概念,并更开放得学习新的解决问题的方式。不管使用 MiniKube 来部署一个 Kubernetes 开发实例是多么得容易,手工安装一个高可用的 Kubernetes 集群是有明显的操作成本的。
Kubernetes 仍是一个相对较新的平台(2年),它也还在活跃得开发和生长中。因此每个版本都会有许多新的特性,使得我们很难去一直跟踪。好消息是这个问题已经被正视,API 做成了可扩展且是后向兼容的。
为方便程序运行多份,可以设置端口为0,这样程序可运行多个实例 server.port=0 但这样会在服务管理上看到的是同一个实例名,可以手工设置系统实例ID: eureka.instance.instance-id=${spring.application.name}:${random.int}
## 私有云开源解决方案如下:
Kong kong是基于Nginx+Lua进行二次开发的方案, https://konghq.com/ Netflix Zuul,zuul是spring cloud的一个推荐组件,https://github.com/Netflix/zuul orange,这个开源程序是国人开发的,http://orange.sumory.com/
Amazon API Gateway,https://aws.amazon.com/cn/api-gateway/ 阿里云API网关,https://www.aliyun.com/product/apigateway/ 腾讯云API网关, https://cloud.tencent.com/product/apigateway
基于Nginx+Lua+ OpenResty的方案,可以看到Kong,orange都是基于这个方案 基于Netty、非阻塞IO模型。 通过网上搜索可以看到国内的宜人贷等一些公司是基于这种方案,是一种成熟的方案。 基于Node.js的方案。 这种方案是应用了Node.js天生的非阻塞的特性。 基于java Servlet的方案。 zuul基于的就是这种方案,这种方案的效率不高,这也是zuul总是被诟病的原因。
一款产品总有不能满足生产需求的地方,因此需求思考产品在如何进行二次开发和维护,是否方便公司团队接手维护产品。
需要评估各API网关在需求上是否能满足,如: 如果是OpenAPI平台需要使用API网关,那么需要看API网关在合作伙伴应用接入、合作伙伴门户集成、访问次数限额等OpenAPI核心需求上去思考产品是否能满足要求。如果是微服务网关,那么要从微服务的运维、监控、管理等方面去思考产品是否足够强大。
kong是基于ngnix+lua的,从公司的角度比较难于找到能去维护这种架构产品的人。 需求评估当前公司是否有这个能力去维护这个产品。 zuul因为架构的原因在高并发的情况下性能不高,同时需要去基于研究整合开源的适配zuul的监控和管理系统。 orange由于没有被大量使用,同时是国内个人在开源,在可持续性和社区资源上不够丰富,出了问题后可能不容易找到人问。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。