Pring Cloud is a full-service framework for implementing microservices based on spring boot. He provides components such as configuration management, service discovery, circuit breakers, intelligent routing, micro-proxies, control buses, global locks, decision-making campaigns, distributed sessions, and cluster state management required for micro-service development. Most importantly, working with the Spring boot framework will make it very convenient for you to develop a cloud service for your microservices architecture.
Spring cloud contains a very large number of sub-frameworks, of which spring cloud Netflix is a framework that was developed by Netflix and later incorporated into the Spring Cloud family, which mainly provides modules such as service discovery, circuit breakers and monitoring, intelligent routing, Client load balancing, and so on.
The spring cloud Netflix project is not long enough to be incorporated into the spring cloud family or 2 years ago, so there is less documentation available, and there is a Chinese community in the country, in addition to official documentation. However, if you are just beginning to touch this and want to use it to build a micro-service application architecture, there will always be a sense of how to start. Therefore, this article is to look at the overall framework of the various components, what is the use of, how to interact. Finally, the actual experience, introduce the possible problems, as well as some problems, the use of what kind of solution.
Micro-Service Architecture
First, let's look at the features or usage scenarios that a generic microservices architecture requires:
- We split the entire system into several subsystems based on the business.
- Each subsystem can deploy multiple applications, using load balancing across multiple applications.
- A service registry is required, all services are registered in the registry, and load balancing is achieved by using a certain policy through the services registered in the registry.
- All clients access the backend service through the same gateway address, and through the routing configuration, the gateway determines which service the URL request is handled by. Load balancing is also used when the request is forwarded to the service.
- Services sometimes also require mutual access. For example, there is a user module, the other services in the processing of some business, to obtain user data of customer service.
- A circuit breaker is required to handle time-outs and errors in the service invocation in a timely manner, preventing the overall system from being paralysed by one of the service's problems.
- A monitoring function is also required to monitor the time spent on each service invocation.
Spring Cloud Netflix components and deployment
The Spring Cloud Netflix framework just meets all of the above requirements, and most importantly, it's very simple to use. The components that Spring Cloud Netflix contains and its main features are as follows:
- Eureka, service registration and discovery, it provides a service registry, service discovery client, and a convenient interface for viewing all registered services. All services use Eureka's Service discovery client to register themselves with the Eureka server.
- Zuul, gateways, all clients request access to the backend services through this gateway. He can use a certain routing configuration to determine which service a URL is handled by. and obtain the registered service from Eureka to forward the request.
- Ribbon, load Balancing, when a Zuul gateway sends a request to an application of a service, if a service launches multiple instances, it is sent to a service instance through the Ribbon through a certain load balancing policy.
- Feign, service clients, and services can use Resttemplate or feign client access if they need to access each other. It uses the Ribbon by default to achieve load balancing.
- Hystrix, monitoring and circuit breakers. We only need to add the hystrix tag on the service interface, we can realize the monitoring of this interface and the circuit breaker function.
- Hystrix Dashboard, monitoring panel, he provides an interface to monitor the time spent by service calls on various services.
- Turbine, monitoring aggregation, using hystrix monitoring, we need to open the monitoring information for each service instance to view. Turbine can help us aggregate the monitoring information of all service instances into one place and view them uniformly. So you do not need to open a page by view.
Here is the group architecture diagram for the service architecture implemented using the sub-framework described above:
In, there are several places to be explained:
- Zuul Network Sekiya registered in the registration center, it also as a service to unified view.
- Load balancing is not a standalone component that runs on gateways, service invocations, and so on, and whenever a service needs to be accessed, the Ribbon is used to get an instance of the service removed. The ribbon obtains a list of services and instances from the Eureka registry, rather than from the registry when each request is sent.
- We can use Resttemplate for inter-service calls, or we can configure Feignclient to use, regardless of the way, the Ribbon load balancer is used by default as long as the service registration is used. (Resttemplate needs to be added
@LoadBalanced
)
- Each service can turn on the monitoring function, the monitoring service will provide a servlet interface
/hystrix.stream
, if you need to monitor the operation of a method of the service statistics, add a label on this method @HystrixCommand
.
- To view the monitoring information, enter the monitoring URL for the service on the Hystrix dashboard:
http://serviceIp:port/hystrix.stream
You can view the running monitoring information graphically.
- If you want to aggregate the monitoring information for all services together, you need to use turbine to aggregate the monitoring information for the services you need.
We can also see how the architecture is deployed:
- Deploy a single gateway application independently
- The service registry and monitoring can be configured in one application or 2 applications.
- Service registries can also be deployed in multiple areas
zone
to differentiate between them for high availability.
- Each service deploys one or more instances, depending on the load and the need for high availability.
Spring Cloud Netflix Component development
As mentioned above, the development of the spring Cloud Netflix-based microservices is very simple, generally we are working with spring boot, if you want to use in your original Java Web application can also be added by the relevant configuration to practice.
For more information on development, you can refer to the Spring Cloud Chinese community article, which details the development of each component. Here, just look at the service registration and Monitoring module development, as well as the development of service calls, others can directly refer to the above series of articles.
Development of registration and monitoring Center
This is very simple, just one of the following classes:
// 省略import@SpringBootApplication@EnableEurekaServer@EnableHystrixDashboardpublic class ApplicationRegistry { public static void main(String[] args) { new SpringApplicationBuilder(Application.class).web(true).run(args); }}
Here's a description of the spring boot tag @SpringBootApplication
. The current application is a spring boot application. This allows me to start the application directly in the IDE using the main function, or it can be packaged and started with the command line. Of course, you can also start a packaged war package with a server such as Tomcat.
Using the label @EnableEurekaServer
, you can start the components of the Eureka Service registry during the startup process. It listens on a port, which is 8761 by default, to receive service registration. and provide a Web page, open later, you can see the registered services.
Adding @EnableHystrixDashboard
will provide a monitoring page where we can enter the address of the service to be monitored to see the invocation of the Hystrix
monitoring-enabled interface.
Of course, in order to use the above components, we need to add the corresponding dependencies in the Maven Pom file, such as Use spring-boot-starter-parent
, dependency spring-cloud-starter-eureka-server
and spring-cloud-starter-hystrix-dashboard
so on.
Inter-service Call
In the various documents on the Internet, there is no clear explanation of the call between services, so here is a special explanation of how this is developed.
There are two ways to make a service call, RestTemplate
and FeignClient
. Whatever the way, he is invoking the service's HTTP interface through the rest interface, and the parameters and results are serialized and deserialized by Jackson by default. Because of the interface defined by spring MVC's Restcontroller, the returned data is serialized into JSON data via Jackson.
Resttemplate
In this way, you only need to define a resttemplate bean, set to LoadBalanced
:
@Configurationpublic class SomeCloudConfiguration { @LoadBalanced @Bean RestTemplate restTemplate() { return new RestTemplate(); }}
So we can inject this bean into the place where we need it:
public class SomeServiceClass { @Autowired private RestTemplate restTemplate; public String getUserById(Long userId) { UserDTO results = restTemplate.getForObject("http://users/getUserDetail/" + userId, UserDTO.class); return results; }}
In users
this case, the service Id,ribbon obtains an instance of the service from the list of service instances, sends the request, and obtains the result. UserDTO
the object requires a serial number, and its inverse sequence number is automatically completed.
Feignclient
In addition to the above way, we can also use FeignClient
. Or look directly at the code:
@FeignClient(value = "users", path = "/users")public interface UserCompositeService { @RequestMapping(value = "/getUserDetail/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) UserDTO getUserById(@PathVariable Long id);}
We only need to use the @FeignClient
definition of an excuse, Spring Cloud feign will help us to generate an implementation of it from the corresponding users service to get the data.
Where @FeignClient(value = "users", path = "/users/getUserDetail")
the value inside is the service Id,path is the path prefix for this set of interfaces.
In the following method definition, it is like setting up Spring MVC's interface, and for this method, it corresponds to the URL /users/getUserDetail/{id}
.
Then, when it is used, it is injected into the same way as a generic service:
public class SomeOtherServiceClass { @Autowired private UserCompositeService userService; public void doSomething() { // ..... UserDTO results = userService.getUserById(userId); // other operation... }}
Problems encountered
Because the spring cloud has less documentation, the architecture of the microservices is relatively complex, and there are a number of problems to be encountered in the development, some of which is how to better use the framework to build the architecture, and some of the problems are how to configure them. Here are some of the things I have to offer when building a microservices architecture.
Request Timeout Issue
The default timeout for the Zuul gateway is very short, in order to ensure that the service can be quickly responded to when it is invoked. However, we will have some business methods that run longer, especially on test servers. At this time, you need to adjust the timeout. There are several places for this timeout:
- Load balancer Ribbon, Load balancer has a timeout setting, including link time and read time
- The Hystrix circuit Breaker also has a timeout setting that needs to be returned at the appropriate time, rather than waiting on a request.
The corresponding configuration is as follows:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds = 30000ribbon: ReadTimeout: 30000 ConnectTimeout: 15000
Problem with Service ID
The ID of the service, which is the service name, can be set by APPLICATION.YML or bootstrap.yml:
spring: application: name: users
Problems with managing paths
The Spring boot app defaults to open some managed interfaces, such as /info
, /health
and metrics monitoring interfaces /metrics
. If you use the default path, there is no problem using hystrix monitoring, the service Registry's listening service status, but if you want to use a different path, for example, /management/info
/management/health
it involves a lot of places, and each version may have some more or less problems, The problems you encounter will be different. The problems I have encountered are:
Registered successfully but could not find the service
First, the registration succeeds, and you can see the individual services on the Eureka Server page. However, when you call through the gateway, you are always prompted that the service cannot be found. At this point it may be necessary to configure the following in the application.yml of each service:
eureka: instance: nonSecurePort: ${server.port} appname: ${spring.application.name} statusPageUrlPath: ${management.context-path}/info healthCheckUrlPath: ${management.context-path}/health
To put it simply, this is to tell the Eureka server when registering, what the port of the service is, and what the path is to listen to the state. This is because we use a different management interface path, and the Eureka server does not use the corresponding path. If everything works, you can click on a registered service on the Eureka server and you should be able to open an info page. He may be blank, but at least the Eureka server can know that the service is functioning properly through this.
This issue is not available in all versions, but only in some spring cloud versions.
Hystrix monitoring with managed paths set
I just said Hystrix. The path to the monitor is http://serviceIp:port/hystrix.stream
that if you set the path to the management interface, the monitoring path will also become:
http://serviceIp:port/${management.context-path}/hystrix.stream
If you want to use turbine aggregation again, turbine will not be found because it defaults to the server address and port on the Eureka server and adds/hystrix.stream later. At this point, you will need to set turbine:
turbine: aggregator: clusterConfig: USER appConfig: USER instanceUrlSuffix: USER: /user/hystrix.stream
Managing the security of a path
For micro-service deployment of several machines, you can open a firewall to control who can access the management interface, but, even so, for security, and so on, I generally will also use the management side interface with spring security to protect. As a result, the monitoring interface cannot be accessed directly.
Permission validation for inter-service calls
In general, our API interface requires some kind of authorization to access, after the successful login, and then through tokens or cookies and other means to invoke the interface. With the spring Cloud netfix Framework, when logging in, the login request is forwarded to the appropriate user service, and after successful landing, a cookie or header token will be set. The client then requests the verification information from the Zuul gateway to the appropriate service. When the Zuul gateway forwards the request to the backend service, it will send some headers to the server by default, such as: Cookie, Set-cookie, Authorization. In this way, the related headers of the client request can be passed to the server, and the cookie set by the server can also be uploaded to the client. However, if you want to prohibit certain headers from being transmitted to the server, you can disable it in the APPLICATION.YML configuration of the Zuul gateway in the following way:
zuul: routes: users: path: /users/** sensitiveHeaders: Cookie,Set-Cookie,Authorization serviceId: user
Just said that one of our services sometimes needs to invoke another service, when this request is not initiated by the client, and the header of his request will not have any authentication information. At this time, either, through the firewall and other settings, to ensure that the interface between service calls, only a few address access, or in some way set the header.
At the same time, if you want to get this request in a service is really IP, (because the request is forwarded through the gateway, you directly through request to obtain IP is the gateway IP), can be obtained from the header X-Forwarded-Host
. If you want to disable this header, you can also:
zuul.addProxyHeaders = false
If you are using a RestTemplate
method called, you can add a header to the request Options
.
It can also be set by the following interceptor, which RestTemplate
can work in both ways and ways FeignClient
:
@Beanpublic RequestInterceptor requestInterceptor() { return new RequestInterceptor() { @Override public void apply(RequestTemplate template) { String authToken = getToken(); template.header(AUTH_TOKEN_HEADER, authToken); } };}
Spring Cloud Netflix overview and architecture design