SpringCloud study Notes
The study notes are compiled according to the SpringCloud tutorial of qianfeng education.
As shown in the video tutorial: www.bilibili.com/video/BV18Z…
I. Introduction to SpringCloud
1.1 Microservices Architecture
Microservices framework author: Martin Fowler
Martinfowler.com/articles/mi…
In short, the microservice architecture style is a way of developing a single application as a set of small services, each running in its own process and communicating with a lightweight mechanism (usually HTTP resource apis). These services are built around business functions and can be deployed independently by a fully automated deployment mechanism. There is little centralized management of these services, which can be written in different programming languages and use different data storage technologies.
- Microservices architecture is just a style, a style
- A complete project, split multiple modules to develop separately
- Each module runs separately in its own container
- Each module needs to communicate with each other. Http, RPC, MQ
- Each module has no dependencies and is deployed separately
- Multiple languages can be used to develop different modules
- Use MySQL data, Redis, ES to store data, or use multiple MySQL databases
Summary: Divide complex and bloated single applications into fine-grained services, and package and deploy each service separately.
1.2 introduce SpringCloud
SpringCloud is a set of technology stacks that land the microservices architecture.
Most of the technologies in the SpringCloud stack are secondary development based on Technologies from Netflix
1. SpringCloud Chinese website: www.springcloud.cc/
Eight technical points:
- Eureka – Registration and discovery of services
- Robbin – Load balancing between services
- Feign – Communication between services
- Hystrix – Thread isolation for services as well as circuit breakers
- Zuul – Service Gateway
- Stream – Enables the use of MQ
- Config – Dynamic configuration
- Sleuth – Service tracking
Registration and discovery of services -Eureka
2.1 the introduction
Eureka helps us maintain all the service information so that services can call each other.
She solved two problems:
- If the caller, IP, or port number changes, the caller needs to be maintained
- If the called builds a cluster, maintain all the callers
2.2 Eureka quick Start
2.2.1 create EurekaServer
1. Create a parent project, specify the version of SpringCloud in the parent project, and change packing to POM
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Copy the code
2, create Eureka server: create SpringBoot project, and import dependencies, add annotations in the boot class, write YML file
2.1. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code
2.2. Add annotations to start classes
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); }}Copy the code
2.3. Write yML configuration files
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://root:root@${eureka.instance.hostname}:${server.port}/eureka/
spring:
security:
user:
name: root
password: root
application:
name: EUREKA
Copy the code
2.2.2 create EurekaClient
1. Create a Maven project and change it to SpringBoot
<parent>
<artifactId>springcloudstudy</artifactId>
<groupId>com.chtgeo</groupId>
<version>0.0.1 - the SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>02-customer</artifactId>
Copy the code
2. Import dependencies
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Copy the code
3. Add annotations to the startup class
@SpringBootApplication
@EnableEurekaClient
public class CustomerApplication {
public static void main(String[] args) { SpringApplication.run(CustomerApplication.class, args); }}Copy the code
4. Write a configuration file
eureka:
client:
service-url:
defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka
spring:
application:
name: CUSTOMER
Copy the code
2.2.3 test had been
1. Create a Search module and register with Eureka
2. Use EurekaClient object to obtain service information
@Autowired
private EurekaClient eurekaClient;
Copy the code
3. Call the normal RestTemplate
@GetMapping("/customer")
public String customer(a) {
// 1. Use eurakaClient to obtain information about the SEARCH service
InstanceInfo search = eurekaClient.getNextServerFromEureka("SEARCH".false);
2. Obtain the access address
String homePageUrl = search.getHomePageUrl();
// 3. Access the vm using restTemplate
String result = restTemplate.getForObject(homePageUrl + "/search", String.class);
4 / / return
return result;
}
Copy the code
2.3 Safety of Eureka
Implement Eureka authentication
1. Import dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Copy the code
2. Write configuration classes
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/eureka/**");
super.configure(http); }}Copy the code
3. Write a configuration file
User name and password
spring:
security:
user:
name: root
password: root
Copy the code
4. Other services need to add user names and passwords when registering with Eureka
eureka:
client:
serviceUrl:
defaultZone: http://user name: password @localhost:8761/eureka/
Copy the code
2.4 High availability of Eureka
If the program works, suddenly Eureka goes down.
1. If the caller has visited the called party once, Eureka downtime will not affect the calling function.
2. If the caller has not accessed the called, the Eureka outage will cause the current function to be unavailable.
Build Eureka high availability
1. Prepare multiple Eurekas
The imL and target files are copied, and the project name in pom.xml is modified to add a module to the parent project.Copy the code
2. Register the service with multiple EureKas
eureka:
client:
service-url:
defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka
Copy the code
3. Multiple EureKas communicate with each other
eureka:
client:
registerWithEureka: true # Sign up for Eureka
fetchRegistry: true # Pull information from Eureka
serviceUrl:
defaultZone: http://root:root@localhost:8762/eureka/
Copy the code
2.5 Details of Eureka
1. When EurekaClient is started, register your registration information with EurekaServer, which will store the registration information of EurekaClient.
2. When EurekaClient invokes the service, if there is no local cache of registration information, go to EurekaServer to obtain registration information.
3. EurekaClient will connect to EurekaServer through heartbeat. (By default, EurekaClient will send a heartbeat request every 30 seconds. If you do not send a heartbeat message after 90 seconds, EurekaServer will consider you down and remove the current EurekaClient from the registry.)
eureka:
instance:
lease-renewal-interval-in-seconds: 30 # Heartbeat interval
lease-expiration-duration-in-seconds: 90 # How long have you not sent it
Copy the code
4. EurekaClient updates the local registry in EurekaServer every 30 seconds
eureka:
client:
registry-fetch-interval-seconds: 30 How often do you update the local registry cache information
Copy the code
5. Eureka’s self-protection mechanism. If the heartbeat sending rate of a service is lower than 85% within 15 minutes, EurekaServer will enable the self-protection mechanism.
- – EurekaServer will not remove services that have not received heartbeats for a long time
- EurekaServer is still available
- When the network is stable, EurekaServer starts to synchronize its information with other nodes
eureka:
server:
enable-self-preservation: true # Turn on the self-protection mechanism
Copy the code
6, CAP theorem: C- Consistency, A- Availability, P-partition tolerance. In distributed environment, only two of these three features can be satisfied, and fault tolerance of partition must be satisfied in distributed environment, and can only be balanced between AC.
CP: The consistency is guaranteed, but your system may be unavailable for a certain period of time. If you synchronize data for a long time, the loss will be great.
AP: Ensure availability, Eureka is an AP effect, highly available cluster, Eureka cluster is centrless, even if the Eureka down several will not affect the use of the system, do not need to re-elect a master, will also lead to a certain period of data inconsistency.
3. Load balancing of services -Robbin
3.1 the introduction
Robbin helps us to implement service and service load balancing. Robbin belongs to client load balancing
Client load balancing: customer customer module, pulls all information of the two Search modules to the local cache, makes a load balancing policy in Customer, and selects a certain service.
Server load balancing: in the registry, select a specified service information based on the load balancing policy you specify and return it.
3.2 Quick start of Robbin
1. Start two Search modules
2. Import two Robbin modules in Customer
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
Copy the code
3. Integrate RestTemplate and Robbin
@Bean
@LoadBalanced
public RestTemplate restTemplate(a) {
return new RestTemplate();
}
Copy the code
4. Access search from Customer
@GetMapping("/customer")
public String customer(a) {
String result = restTemplate.getForObject("http://SEARCH:8082/search", String.class);
4 / / return
return result;
}
Copy the code
3.3 Robbin Configuring load balancing policies
1. Load balancing policy
- RandomRule: a RandomRule strategy
- RoundRobbinRule: indicates a polling policy
- WeightedResponseTimeRule: The default is polling and you are automatically assigned weights based on how long the service takes
- BestAvailableRule: Allocation is based on the smallest number of concurrent requests from the called party
2. Take the form of notes
@Bean
public IRule ribbon(a) {
return new BestAvailableRule();
}
Copy the code
3. Configure file to specify load balancing policy (recommended)
SEARCH: # service name
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # Specify the class used by the load balancing policy
Copy the code
4. Calls between services -Feign
4.1 the introduction
Feign can help us with interface oriented programming, which is to call other services directly and simplify development.
4.2 Quick start of Feign
1. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Copy the code
2. Add annotations
@EnableFeignClients
Copy the code
Create an interface and map it to the Search module
@FeignClient(value = "SEARCH") // Specify the service name
public interface SearchClient {
// value: indicates the request path of the target server. Method: indicates the mapping method
@RequestMapping(value = "/search", method = RequestMethod.GET)
String search(a);
}
Copy the code
4. Test use
@Autowired
private SearchClient searchClient;
@GetMapping("/customer")
public String customer(a) {
String result = searchClient.search();
return result;
}
Copy the code
4.3 Transmission of Feign parameters
1. Precautions
- If the parameters to be passed are complex, POST is used by default.
- When passing a single parameter, it is recommended to use @pathVariable. If many parameters are passed, you can use @requestParam instead of leaving out the value attribute.
- When passing object information, use JSON and add @RequstBody
- The Client interface must use @RequestMapping
2. Prepare three interfaces under the Search module
@GetMapping("/search/{id}")
public Customer findById(@PathVariable Integer id) {
return new Customer(1."Zhang".23);
}
@GetMapping("/getCustomer")
public Customer getCustomer(@RequestParam Integer id, @RequestParam String name) {
return new Customer(id, name, 23);
}
@PostMapping("/save")
public Customer save(@RequestBody Customer customer) {
return customer;
}
Copy the code
3. Encapsulate the Controller under the Customer module
@GetMapping("/customer/{id}")
public Customer findById(@PathVariable Integer id) throws InterruptedException {
return customerService.findById(id);
}
@GetMapping("/getCustomer")
public Customer getCustomer(@RequestParam Integer id, @RequestParam String name) {
return searchClient.getCustomer(id, name);
}
@GetMapping("/save") // Automatically converts to POST request 405
public Customer save(Customer customer) {
return searchClient.save(customer);
}
Copy the code
4. Encapsulate the Client interface
@RequestMapping(value = "/search/{id}", method = RequestMethod.GET)
Customer findById(@PathVariable(value = "id") Integer id);
@RequestMapping(value = "/getCustomer", method = RequestMethod.GET)
Customer getCustomer(@RequestParam(value = "id") Integer id, @RequestParam(value = "name") String name);
@RequestMapping(value = "/save", method = RequestMethod.POST)
Customer save(@RequestBody Customer customer);
Copy the code
5, test,
4.4 Feign的Fallback
Fallback can help us use Feign to call another service, if there is a problem, the service degradation, return an error data, avoid the function of a service failure, all failure.
1. Create a POJO class to implement the Client interface.
@Component
public class SearchClientFallBack implements SearchClient {
@Override
public String search(a) {
return "Something's wrong!!";
}
@Override
public Customer findById(Integer id) {
return null;
}
@Override
public Customer getCustomer(Integer id, String name) {
return null;
}
@Override
public Customer save(Customer customer) {
return null; }}Copy the code
2, modify the Client interface annotation, add a property.
@FeignClient(value = "SEARCH",fallback = SearchClientFallBack.class)
Copy the code
3. Add a configuration file.
feign:
hystrix:
enabled: true
Copy the code
The caller has no way of knowing what the error message is
1. FallBackFactory is based on Fallback
Create a POJO class to implement FallBackFactory
@Component
public class SearchClientFallBackFactory implements FallbackFactory<SearchClient> {
@Autowired
private SearchClientFallBack searchClientFallBack;
@Override
public SearchClient create(Throwable throwable) {
throwable.printStackTrace();
returnsearchClientFallBack; }}Copy the code
3. Modify the properties of the Client interface
@FeignClient(value = "SEARCH",fallbackFactory = SearchClientFallBackFactory.class)
Copy the code
5. Service isolation and circuit breaker -Hystrix
5.1 the introduction
5.2 Implementation of downgrade mechanism
1. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
Copy the code
2. Add a note
@EnableCircuitBreaker
Copy the code
3. Write its degradation methods for an interface
@GetMapping("/customer/{id}")
@HystrixCommand(fallbackMethod = "findByIdFallBack")
public Customer findById(@PathVariable Integer id) throws InterruptedException {
int i = 1 / 0;
return searchClient.findById(id);
}
// findById degradation method, method description is consistent with the interface
public Customer findByIdFallBack(@PathVariable Integer id) {
return new Customer(-1."".0);
}
Copy the code
4. Add annotations to the interface
@HystrixCommand(fallbackMethod = "findByIdFallBack")
Copy the code
5. Test it out
5.3 Thread Isolation
If the Tomcat thread pool is used to receive user requests and the current thread is used to perform functions of other services, if a service fails, tomcat threads will accumulate in a large area and Tomcat cannot process other service functions.
1. Hystix thread pool (default) : The thread pool of Tomcat is used when receiving user requests, executing business code, and invoking other services.
Semaphores, again using Tomcat’s thread pool, help us manage Tomcat’s thread pool.
1. Hystix thread pool configuration (see the HystrixCommandProperties class to configure the name property)
- Thread isolation policy: name =
execution.isolation.strategy
, value =THREAD
|SEMAPHORE
- Timeout period: name=
circuitBreaker.enabled
,value =true|false
5.4 the breaker
5.4.1 Circuit breakers
When invoking a specified service, if the service failure rate reaches one of the thresholds you entered, change the circuit breaker from close to Open. If the specified service is accessed, use the fallback method. Within a certain period of time, the open state will again change to half open. Allow a request to be sent to my specified service and, if successful, turn to CLOSE. If it fails, the service will turn to open again and loop to half open again until the breaker returns to a close state.
5.4.2 Configuring the Monitoring interface for circuit breakers
1. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
Copy the code
2. Add annotations to the startup class
@EnableHystrixDashboard
Copy the code
3. Configure a servlet
@WebServlet("/hystrix.stream")
public class HystrixServlet extends HystrixMetricsStreamServlet {}// Add the scan servlet annotation to the startup class
@ServletComponentScan({"com.chtgeo.servlet"})
Copy the code
4, test,
Direct access: http://host:port/hystrix
Enter the mapped servlet path at the current location
5.4.3 Configuring Circuit breaker attributes
Properties of circuit breakers
To find related properties address: github.com/Netflix/Hys…
- Switch of the circuit breaker: name =
hystrix.command.default.circuitBreaker.enabled
, value =true
- Total number of requests for the failure threshold: name=
hystrix.command.default.circuitBreaker.requestVolumeThreshold
,value=20
- Total request failure rate reaches % when: name=
hystrix.command.default.circuitBreaker.errorThresholdPercentage
,value=50
- Force the service to reject the request: name=
hystrix.command.default.circuitBreaker.forceOpen
,value=false
- Force the service to accept the request: name=
hystrix.command.default.circuitBreaker.forceClosed
,value=false
Specific Configuration modes
@GetMapping("/customer/{id}")
@HystrixCommand(fallbackMethod = "findByIdFallBack", commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "70"), @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"), })
Copy the code
5.5 Request Caching
5.5.1 Introduction to Request Caching
1. The declaration cycle of the request cache is one request
The request cache is a method that caches the current thread, taking the method parameter as the key and the method return as the value
3. In a request, the target method is called once, and will always be cached.
5.5.2 Implementation of request caching
Create a Service and call the Search Service.
@Service
public class CustomerService {
@Autowired
SearchClient searchClient;
@CacheResult
@HystrixCommand(commandKey = "findById")
public Customer findById(Integer id) {
return searchClient.findById(id);
}
@CacheRemove(commandKey = "findById")
@HystrixCommand
public void clearFindById(@CacheKey Integer id) {
System.out.println("FindById cleared..."); }}Copy the code
2. Use request caching annotations
@cacheresult: helps us cache the result of the current method (must be used with @hystrixCommand) @Cacheremove: helps us to clear a cache information (based on commandKey) @cacheKey: specifies which method parameter to use as the cache identifierCopy the code
3. Write the Search module to return the result
return new Customer(1."Zhang", (int) (Math.random()*10000));
Copy the code
4, write Filter to build HystixRequestContext
@WebFilter("/*")
public class HystrixRequestContextInitFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HystrixRequestContext.initializeContext(); filterChain.doFilter(servletRequest, servletResponse); }}Copy the code
5. Modify Controller
public Customer findById(@PathVariable Integer id) throws InterruptedException {
System.out.println(customerService.findById(id).getAge());
System.out.println(customerService.findById(id).getAge());
System.out.println(customerService.findById(id));
System.out.println(customerService.findById(id));
customerService.clearFindById(id);
System.out.println(customerService.findById(id));
System.out.println(customerService.findById(id));
System.out.println(customerService.findById(id).getAge());
System.out.println(customerService.findById(id).getAge());
return customerService.findById(id);
}
Copy the code
6, test,
Vi. Service gateway -Zuul
6.1 the introduction
Problems solved:
1. The client maintains a large number of IP and port information and directly accesses specified services
2. Authentication and authorization operations need to be added to each module
3. In the iteration of the project, the services need to be split and merged, requiring a lot of changes on the client side
4. Uniformly put the safety check in ZUUL
6.2 Zuul’s Quick Start
1. Create Maven project and change it to SpringBoot project
2. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code
3. Add annotations
eureka:
client:
service-url:
defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka
spring:
application:
name: ZUUL
server:
port: 80
Copy the code
4, test,
6.3 Zuul Common Configuration Information
6.3.1 Zuul Monitoring page
1. Import dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Copy the code
2. Write a configuration file
# Check the monitoring page of Zuul (use during development, do not configure when online)
management:
endpoints:
web:
exposure:
include: "*"
Copy the code
3. Direct access
6.3.2 Ignoring Service Configuration
# zuul configuration
zuul:
* all paths configured by default will be ignored.
ignored-services: eureka
The monitoring interface is already viewable, when accessing the service, 404
ignored-patterns: /**/search/**
Copy the code
6.3.3 Customizing Service Configurations
# zuul configuration
zuul:
Key (service name: value (path))
# routes:
# search: /ss/**
# customer: /cc/**
# Specify a custom service (mode 2)
routes:
kehu: # custom name
path: /ccc/** # mapping path
serviceId: customer # service name
Copy the code
6.3.4 Grayscale Publishing
1. Add a configuration class
@Bean
public PatternServiceRouteMapper serviceRouteMapper(a) {
return new PatternServiceRouteMapper(
"(?
^.+)-(?
v.+$)"
."${version}/${name}");
}
Copy the code
2. Prepare a service with two versions
version: v1
spring:
application:
name: CUSTOMER-${version}
Copy the code
3. Modify Zuul configuration
zuul:
[root@localhost] [root@localhost] [root@localhost]
# ignored-services: "*"
Copy the code
4, test,
6.4 Zuul’s filter execution process
When a client sends a request to the Zuul service, it first passes through the PreFilter chain, forwards the request to a RoutingFilter, forwards the request to a specified service, and after the specified service responds to a result, passes through the PostFilter filter chain again, and finally passes the response to the client
6.5 Zuul filter introduction
Create a POJO class that inherits the ZuulFilter abstract class
@Component
public class TestZuulFilter extends ZuulFilter{}
Copy the code
2. Specify the current filter type
@Override
public String filterType(a) {
return FilterConstants.PRE_TYPE;
}
Copy the code
3. Specify the order in which filters are executed
@Override
public int filterOrder(a) {
return FilterConstants.PRE_DECORATION_FILTER_ORDER-1;
}
Copy the code
4. Configure whether to enable the function
@Override
public boolean shouldFilter(a) {
// Enable the current filter
return true;
}
Copy the code
5, test,
6.6 PreFilter Implements token Verification
1. Prepare access path and request parameters to pass token
http://localhost/v2/customer/version?token=123
Copy the code
2. Create AuthenticationFilter
@Component
public class AuthenticationFilter extends ZuulFilter {
@Override
public String filterType(a) {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder(a) {
return FilterConstants.PRE_DECORATION_FILTER_ORDER - 2;
}
@Override
public boolean shouldFilter(a) {
return true;
}
@Override
public Object run(a) throws ZuulException {
// 1. Obtain the Request object
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
2. Obtain the token parameter
String token = request.getParameter("token");
// 3. Compare tokens
if (token == null || !"123".equals(token)) {
// 4. The token fails to verify and responds to the data directly
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
return null; }}Copy the code
3. Write concrete logic code in Run
@Override
public Object run(a) throws ZuulException {
// 1. Obtain the Request object
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
2. Obtain the token parameter
String token = request.getParameter("token");
// 3. Compare tokens
if (token == null || !"123".equals(token)) {
// 4. The token fails to verify and responds to the data directly
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
return null;
}
Copy the code
4, test,
6.7 Zuul service has been downgraded
1. Create POJO class to implement FallbackProvider
@Component
public class ZuulFallBack implements FallbackProvider {}
Copy the code
2. Override both methods
@Override
public String getRoute(a) {
return "*"; // indicates that all problematic services go through this degradation method
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
// Logs can be processed here
System.out.println("Degraded service:" + route);
cause.printStackTrace();
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode(a) throws IOException {
// Specify a specific HttpStatus
return HttpStatus.INTERNAL_SERVER_ERROR;
}
@Override
public int getRawStatusCode(a) throws IOException {
// Return the status code
return HttpStatus.INTERNAL_SERVER_ERROR.value();
}
@Override
public String getStatusText(a) throws IOException {
// Specify an error message
return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
}
@Override
public void close(a) {}@Override
public InputStream getBody(a) throws IOException {
String msg = Current Services: + route + "There is a problem!!";
return new ByteArrayInputStream(msg.getBytes());
}
@Override
public HttpHeaders getHeaders(a) {
// Specify the response header information
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
returnheaders; }}; }Copy the code
3, test,
6.8 Zuul Dynamic Routing
1. Create a filter
@Component
public class DynamicRoutingFilter extends ZuulFilter {
@Override
public String filterType(a) {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder(a) {
// The order of execution is best placed at the end of the Pre filter
return FilterConstants.PRE_DECORATION_FILTER_ORDER + 2;
}
@Override
public boolean shouldFilter(a) {
return true;
}
@Override
public Object run(a) throws ZuulException {
// 1. Obtain Request
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
// 2. Obtain the parameter redisKey
String redisKey = request.getParameter("redisKey");
// 3
if(redisKey ! =null && redisKey.equalsIgnoreCase("customer")) {// http://localhost:8080/customer/1
context.put(FilterConstants.SERVICE_ID_KEY, "customer-v1");
context.put(FilterConstants.REQUEST_URI_KEY, "/customer/1");
}else if(redisKey ! =null && redisKey.equalsIgnoreCase("search")) {// http://localhost:8081/search/2
context.put(FilterConstants.SERVICE_ID_KEY, "search");
context.put(FilterConstants.REQUEST_URI_KEY, "/search/2");
}
return null; }}Copy the code
Write the business logic in the run method
@Override
public Object run(a) throws ZuulException {
// 1. Obtain Request
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
// 2. Obtain the parameter redisKey
String redisKey = request.getParameter("redisKey");
// 3
if(redisKey ! =null && redisKey.equalsIgnoreCase("customer")) {// http://localhost:8080/customer/1
context.put(FilterConstants.SERVICE_ID_KEY, "customer-v1");
context.put(FilterConstants.REQUEST_URI_KEY, "/customer/1");
}else if(redisKey ! =null && redisKey.equalsIgnoreCase("search")) {// http://localhost:8081/search/2
context.put(FilterConstants.SERVICE_ID_KEY, "search");
context.put(FilterConstants.REQUEST_URI_KEY, "/search/2");
}
return null;
}
Copy the code
3, test,
7. Multilingual support -Sidecar
7.1 the introduction
In the SpringCloud project, you need to access some non-java applications, third-party interfaces, and cannot access Eureka, hystrix, feign, and other components. Start a proxy microservice that communicates with non-java applications or third-party interfaces, and use the proxy microservice to access relevant components of SpringCloud.
7.2 sidecars implementation
1. Create third-party services
Create a SpringBoot project and add a ControllerCopy the code
2. Create Maven project (06-sidecar) and change it to SpringBoot project
3. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-sidecar</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
</dependency>
Copy the code
4. Add annotations
@EnableSidecar
Copy the code
5. Write a configuration file
server:
port: 81
eureka:
client:
service-url:
defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka
Specify the service name
spring:
application:
name: oter-service
# Specify the proxy's third party service
sidecar:
port: 7001
Copy the code
6. Invoke third-party services through Customer through Feign
Service message passing -Stream
8.1 the introduction
A Stream encapsulates a message queue to make it easier to manipulate MQ message queues (streams only support Kafka and RabbitMQ).
8.2 Stream Quick Start
1. Start RabbitMQ
2. Consumer-import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
Copy the code
3. Consumer-profile
spring:
# connect the RabbitMQ
rabbitmq:
host: 192.16875.139.
port: 5672
username: test
password: test
virtual-host: /test
Copy the code
4. Consumers – Listen to queues
public interface StreamClient {
@Input("myMessage")
SubscribableChannel input(a);
}
//------------------------------------
@Component
@EnableBinding(StreamClient.class)
public class StreamReceiver {
@StreamListener("myMessage")
public void msg(Object msg) {
System.out.println("Received message:"+ msg); }}Copy the code
Producer-import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
Copy the code
6. Producer-profile
spring:
# connect the RabbitMQ
rabbitmq:
host: 192.16875.139.
port: 5672
username: test
password: test
virtual-host: /test
Copy the code
7. Producers – Post messages
public interface StreamClient {
@Output("myMessage")
MessageChannel output(a);
}
//---------------------------------------
// Add annotations to the bootstrap class
@EnableBinding(StreamClient.class)
//---------------------------------------
@RestController
public class MessageController {
@Autowired
private StreamClient streamClient;
@GetMapping("/send")
public String send(a) {
String msg = "Hello Stream!!!";
boolean send = streamClient.output().send(MessageBuilder.withPayload(msg).build());
return "Message sent successfully!!"; }}Copy the code
8.3 Repeated consumption of Stream
All you need to do is add a configuration that specifies the consumer group
spring:
cloud:
stream:
bindings:
myMessage: # queue name
group: customer # Consumer Group
Copy the code
Consumer manual ACK of 8.4 Stream
1. Write the configuration
spring:
cloud:
stream:
rabbit:
bindings:
myMessage:
consumer:
acknowledgeMode: MANUAL
Copy the code
2. Modify the methods on the consumer side
@StreamListener("myMessage")
public void msg(Object msg,
@Header(name = AmqpHeaders.CHANNEL) Channel channel,
@Header(name = AmqpHeaders.DELIVERY_TAG) Long deliveryTag) throws IOException {
System.out.println("Received message:" + msg);
channel.basicAck(deliveryTag, false);
}
Copy the code
Dynamic configuration of the service -Config
9.1 the introduction
1. Configuration files are scattered in different projects, which is inconvenient to maintain
2. Security of configuration files
3. The modified configuration file does not take effect immediately
9.2 set up the Config – Server
1. Create a Maven project and change it to SpringBoot
2. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Copy the code
3. Add annotations
@SpringBootApplication
@EnableConfigServer
Copy the code
4. Write configuration files (Git operations)
spring:
application:
name: CONFIG
cloud:
config:
server:
git:
basedir: D:\basedir # local warehouse address
username: jinshengwang
password: jin6150090
uri: https://gitee.com/jinshengwang/config-resp.git
Copy the code
5. Test (http://localhost:port/{label}/{application}-{profile}.yml)
9.3 Modifying Customer Connection Config
1. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
Copy the code
2. Write a configuration file
eureka:
client:
service-url:
defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka
spring:
application:
name: CUSTOMER-${version}
cloud:
config:
discovery:
enabled: true
service-id: CONFIG
profile: dev
version: v1
# CONFIG - CUSTOMER-v1-dev.yml
Copy the code
3. Change the configuration name
Modified to bootstrap. Yml
Copy the code
4, test, release to the RabbitMQ (http://localhost:8080/send)
9.4 Dynamic Configuration
9.4.1 Implementation Principle
9.4.2 Service Connection to RabbitMQ
1. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
Copy the code
2. Write a configuration file to connect RabbitMQ information
spring:
rabbitmq:
host: 192.16875.139.
port: 5672
username: test
password: test
virtual-host: /test
Copy the code
9.4.3 Manual Refresh
1. Import dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Copy the code
2. Write a configuration file
management:
endpoints:
web:
exposure:
include: "*"
Copy the code
3. Add a Controller for Customer
@RefreshScope
public class CustomerController {
@Value("${env}")
private String env;
@GetMapping("/env")
public String env(a){
returnenv; }}Copy the code
4, test,
1. After Gitee changes the CONFIG, the latest configuration information is automatically pulled up. 2. Other modules need to be updated, manually send a request to http://ip:10000/actuator/bus-refresh, not restart the project, you can get the latest configuration information.Copy the code
9.4.4 Intranet Penetration
1. Intranet penetration software official website: natapp.cn
2. Register and log in
3. Buy a free pass
4. Download the client, create config.ini file, copy the memory, and set the authToken value
5. Start the exe file and access the Config interface using the test domain name
9.4.5 Automatic Refresh
1. Configure WebHooks in Gitee
Add a filter to Config
Add WebHooksFilter to solve the problem that Gitlab Webhook triggers configuration center /actuator/bus-refresh requests return 400 error codesCopy the code
3, test,
10. Service tracking -Sleuth
10.1 the introduction
In the whole micro-service architecture, there are many micro-services, and a request may need to call multiple micro-services to complete a function. If problems occur in this process, what are the problems of so many services and what are the causes of the problems?
1. Sleuth can obtain the link information of the entire service.
2. Integrate Zipkin to view information through graphical interface
Sleuth can store logs in a database.
10.2 Use of Sleuth
1. Import dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
Copy the code
2. Write a configuration file
logging:
level:
org.springframework.web.servlet.DispatcherServlet: DEBUG
Copy the code
3, test,
SEARH: service name 36e7... : Total link ID ECa8... : link ID of the current service True: logs will be exported persistently. If the value is false, current logs will not be exported to other systems.Copy the code
10.3 Use of Zipkin
1. Build Zipkin web project, official website: zipkin.io/
version: '3.1'
services:
zipkin:
image: Openzipkin/zipkin: 2.12
restart: always
container_name: zipkin
ports:
- 9411: 9411
Copy the code
The spring-cloud-starter-sleuth package is used to replace the spring-cloud-starter-sleuth package
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
Copy the code
3. Write a configuration file
spring:
sleuth:
sampler:
probability: 1 # What percentage of sleUTH information is output to zipkin
zipkin:
base-url: http://192.168.75.139:9411/
Copy the code
4, test,
10.4 to integrate the RabbitMQ
1. Import RabbitMQ dependencies
Spring-cloud-starter-zipkin has built-in RabbitMQ dependenciesCopy the code
2. Modify the configuration file
spring:
zipkin:
base-url: http://192.168.75.139:9411/
sender:
type: rabbit
Copy the code
3. Modify Zipkin information
version: '3.1'
services:
zipkin:
image: openzipkin/zipkin
restart: always
container_name: zipkin
ports:
- 9411: 9411
environment:
- RABBIT_ADDRESSES = 192.168.75.139
- RABBIT_PASSWORD=test
- RABBIT_USER=test
- RABBIT_VIRTUAL_HOST=/test
Copy the code
4, test,
10.5 Zipkin stores data to ES
1. Re-modify Zipkin’s YML file
version: '3.1'
services:
zipkin:
image: openzipkin/zipkin
restart: always
container_name: zipkin
ports:
- 9411: 9411
environment:
- RABBIT_ADDRESSES = 192.168.75.139
- RABBIT_PASSWORD=test
- RABBIT_USER=test
- RABBIT_VIRTUAL_HOST=/test
- STORAGE_TYPE=elasticsearch
- ES_HOSTS = http://192.168.75.139:9200
Copy the code
Note: Zipkin can’t be the latest version (I’ve retrofitted openZipkin/Zipkin :2.12) or it won’t be compatible with ES6.5.4.
Complete SpringCloud architecture diagram
Xii. Pit filling
12.1 The Eureka node is not synchronized
When Eureka is started, it must be started one by one. After Eureka1 is started, Eureka2 must be started. Otherwise, the node information is not synchronized.
12.2 Zipkin integration with ES
At first I installed the latest version of Zipkin, ES was 6.5.4, but Zipkin couldn’t connect to ES. I rolled back Zipkin to version 2.12, and I was ready to integrate.