Spring cloud learning notes

Keywords: Spring Redis Nginx git

SpringCloud

1, Service registration and discovery

Eureka(AP)
  • Service registration is relatively fast, because there is no need to wait for the registration information to replicate to other nodes, and there is no guarantee that the registration information will replicate successfully;
  • When the data is inconsistent, although the registration information on A and B is not the same, each Eureka node can still provide external services normally. This time, if request A fails to find the service information, request B can find it. This guarantees availability at the expense of consistency.
Nacos
/**
 *1 - how to use Nacos as configuration center to manage configuration
 *1. Dependence
 *          <dependency> cloud</grouId>
 *              <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 *          </dependency>
 *2. Create a bootstrap.properties :
 *          spring.application.name=gulimall-coupon
 *          spring.cloud.nacos.config.server-addr=127.0.0.1:8848
 *3. You need to add a (Data Id / data set) normal to the configuration center by default- coupon.properties (application name. properties)
 *4. Dynamic acquisition configuration
 *RefreshScope: get and refresh the configuration dynamically
 *@ Value("${name of configuration item}"): get configuration
 *If the same item is configured in the nacos configuration center and the local configuration file -- the configuration of nacos configuration center is preferred
 *2 - details
 *1. Namespace: configure isolation:
 *Default: public (reserved space): all new configurations are in the public space by default;
 *1. Development, test and production: use namespace to realize environment isolation
 *Note: in bootstrap.properties Which namespace is required for configuration
 *             spring.cloud.nacos . config.namespace=XXXXXXXXXXXXXXXXXXXXXXXXXXX (configuration management ID)
 *2. Each microservice is configured separately from each other. Each microservice creates its own namespace and only loads all configurations under its own namespace
 *2. Configuration set: the set of all configurations
 *3. Configuration set ID:
 *Data ID -- similar file name
 *4. Configuration group:
 *All configuration sets by default belong to: DEFAULT_GROUP;----1111,618,1212
 *Configure configuration groups: spring.cloud.nacos.config.group=1111 ---Configure grouping
 *
 *Each microservice creates its own namespace and uses configuration grouping to distinguish environment - dev\test\prod
 *3 - load multiple configuration sets at the same time
 *1. Any configuration information of microservice can be placed in the configuration center in any configuration file
 *2. Only in bootstrap.properties Describe which configuration files in the configuration center can be loaded
 *  3.@Value,@ConfigurationProperties
 *In the past, any method of SpringBoot to get the value from the configuration file could use
 *The configuration center has the priority to use the configuration center
 */
Conul(CP)
  • Service registration is a little slower than Eureka, because Consul's reft protocol requires that more than half of the nodes write successfully before the registration is successful;
  • When the Leader passes, the entire Consul is not available during the re-election. Strong consistency is guaranteed but cocoa use is sacrificed.
##Launch consumer in developer mode/ localhost:8500
consul agent -dev -client=0.0.0.0
<!--springcloud Provided set in consul Service discovery for-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul</artifactId>
</dependency>
<!--actuator Health examination of-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-actuator</artifactId>
</dependency>
#Consumer service registration configuration
cloud:
	consul:
        host: 127.0.0.1 #Host address of consumer
        post: 8500	#Port number of the server
        discovery:
            #Need to register
            register: true
            #Registered instance ID (unique flag)
            instance-id: ${spring.application.name}-1
            #Name of the service
            service-name: ${spring.application.name}
            #Request port for service
            port: ${server.port}
            #Specify to enable ip address registration
            prefer-ip-address: true
            #Request ip of current service
            ip-address: ${spring.cloud.client.ip-addrss}
Zookeeper

2, Remote call

RestTemplate
Feign
  • Feign is a declarative and templated HTTP client developed by Netfix
  • Feign comes with Ribbon load balancing (you can modify the load balancing policy in the way of Ribbon)
1. Import dependency
<!--SpringCloud Integrated openFeign-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. Configure call interface
/**
 * Created with IntelliJ IDEA
 * User: GHYANG
 * Date: 2020-06-13
 * Description:Declare the name of the microservice to be called
 */
@FeignClient(name="service-product")
public interface ProductFeignClient{
    /**
    *Configure the microservice interface to be called (directly copy the controller header information)
    */
    @RequestMapping(value="/product/{id}",method=RequestMethod.GET)
    public Product findById(@PathVariable("id") Long id);
}
3. Activate Feign on the startup class

@EnableFeignClients

4. Call remote microservice through automatic interface
//Inject feign instance
@Autowired
ProductFeignClient productFeignClient;
//Called in method body
productFeignClient.findById();
5. Other configurations
#Configure the output of the fegin log  
#NONE: do not output log
#BASIC: applicable to production environment tracking problems
#HEADERS: record the request and corresponding header information on the basis of BASIC
#FULL: record all
feign:
	client:
		config:
			service-product: #Service name to call
				loggerLevel: FULL

3, Caching mechanism

Redis+Reidsson
  • Cache penetration: empty result cache

  • Cache avalanche: set random expiration time

  • Cache breakdown: add lock

    //As long as it is the same lock, all threads that need the lock can be locked
    //1-synchronized (this): all components of spring boot are singleton in the container
    //1 - after getting the lock, we should go to the cache again to confirm it. If not, we need to continue the query
    //2 - local lock: synchronized, JUC (lock). In the distributed situation, if you want to lock all, you must use the distributed lock, and each service of the local lock will execute the business once;

//Use map to simulate local cache
private Map<String,Object> cache = new HashMap<>();
//Simulation mode
Map<String, List<Catelog2Vo>> catalogJson = (Map<String, List<Catelog2Vo>>) cache.get("catalogJson");
if(cache.get("catalogJson") == null){
    //Cache is empty
   	//Call business and cache
    cache.put("catalogJson",parent_cid);
}
	return catalogJson;
//Using Redisson
	@ResponseBody
    @GetMapping("/hello")
    public String hello(){
        //1 - obtain a lock as long as the lock name is the same, so as to realize distributed
        RLock my_lock = redisson.getLock("my_lock");
        //2-locking
        my_lock.lock();//Blocking wait, the default lock is 30s
        //2 -- automatic renewal of lock. If the business is too long, a new 30s will be automatically added to the lock during operation. There is no need to worry about the long business time, and the lock will automatically expire and be deleted
        //3 -- as long as the lock business is completed, the current lock will not be renewed, and the lock will not be unlocked manually in time. By default, the lock will be automatically deleted after 30s
//        My_ lock.lock (10,  TimeUnit.SECONDS ); / / 10 seconds automatic unlocking. The automatic unlocking time should be greater than the execution time of the business
        //Question: my_lock.lock(10, TimeUnit.SECONDS : will not renew automatically after the lock time
        /**
         * 1-If we pass the lock timeout, we will send it to redis to execute the script to occupy the lock. The default timeout is the time we specify
         * 2-If we don't specify a lock timeout, use 30 * 1000 {lockwatchdog timeout's default time}
         *  As long as the lock is occupied successfully, a timing task will be started {reset the expiration time of the lock, and the new expiration time is the default time of the watchdog}
         *  internalLockLeaseTime{Watchdog time} / 3 -- > 10s no interval of 10s automatic renewal, renewal of 30s
         *
         *  Best practice:
         *  Use my_ lock.lock (10,  TimeUnit.SECONDS ); the whole renewal operation is omitted, manual unlocking and watchdog mechanism is not used
         */
        try {
            System.out.println("Lock successfully-Conduct business"+Thread.currentThread().getId());
            Thread.sleep(20000);
        }catch (Exception e){

        }finally {
            //3 - if the unlocking code is not running, will the redisson deadlock
            System.out.println("Release lock"+Thread.currentThread().getId());
            my_lock.unlock();
        }
        return "hello";
    }
  • redis read / write lock:

  • Read / write lock - ensure to read the latest data. During modification, the write lock is an exclusive lock (exclusive lock, exclusive lock), and the read lock is a shared lock

  • You have to wait until the write lock is released
  • Read lock + read lock: it is equivalent to no lock, concurrent read. It will only be recorded in redis. All current read locks will be locked successfully at the same time
  • Write lock + read lock: wait for the write lock to release
  • Write lock + write lock: blocking mode
  • Read lock + write lock: there is a read lock. Writing also has to wait
  • As long as there is writing, we must wait

4, Load balancing

Ribbon
1. Service call
  • eureka integrates ribbon internally (spinning cloud also integrates ribbon internally for Consul, the same usage)
  • When creating RestTemplate, declare @ LoadBalanced
  • Use restTemplate to call remote service: no need to splice the URL of microservice and replace the IP address with the service name to be requested
2. Load balancing

Load balancing strategy: polling (default), random, Retry, weight

3. Retry mechanism

Introducing spring's retry dependency

<dependency>
	<groupId>org.springframework.retry</groupId>
    <artfactId>spring-retry</artfactId>
</dependency>

Retry configuration of ribbon

service-product:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    ConnectTimeout: 250 # Connection timeout of Ribbon
    ReadTimeout: 1000 # Data read timeout of Ribbon
    OkToRetryOnAllOperations: true # Retry all operations
    MaxAutoRetriesNextServer: 1 # Number of retries to switch instances
    MaxAutoRetries: 1 # Number of retries to the current instance
Nginx F5
  • nginx is a high-performance HTTP and reverse proxy server, which is used as HTTP soft load balancer by many websites. nginx can also be used as a static resource server
  • Load balancing algorithm: polling, weight, ip binding

#Polling configuration
upstream product{
	service 127.0.0.1:8002; #Server 1
	service 127.0.0.1:8081; #Server 2
}

#Extension: the following is static resource configuration
server{
	listen 80; #Port number monitored
	server_name gulimall.com #Monitored domain name
	
	location /static/{ #Matching url
		root /usr/share/nginx/html; #Match the actual resource path accessed successfully
	}
}

#Extension: the following are reverse agents
server{
	listen 80; #Listen to port 8080
	server_name gulimall.com #Monitored domain name
	
	location /{ #Intercept the request heard by the supervisor
		proxy_pass http://gulimall; #The request is forwarded to the system gateway where the gulial is the same as the server in the upstream below
	}
}
#upstream xxx: indicates that the load balancing server is the upstream server	
upstream gulimall{
	server 192.168.252.1:88 #Path of actual request
}
#Weight configuration
#upstream xxx: indicates that the load balancing server is the upstream server	
upstream gulimall{
	server 192.168.252.1:88 weight=2; #Actual gateway and weight value
	server 192.168.252.1:89 weight=3; #Actual gateway 2 and weight value
}
#ip binding configuration
#upstream xxx: indicates that the load balancing server is the upstream server	
#Matching principle: according to the IP address of the client, Through the hash function calculation, a numerical value is obtained, which is used to model the size of the server list. The result is the serial number of the server to be accessed by the customer service end. The source address hash method is used for load balancing. For the client with the same IP address, when the back-end server list is unchanged, it will map to a back-end server for access each time.
upstream gulimall{
	server 192.168.252.1:88; #Actual gateway
	server 192.168.252.1:89; #Actual gateway 2
	ip_hash;
}
  • F5 load balancer is the global leader in application delivery network

5, Service fuse

  • Avalanche effect: there is a strong dependence between services, and faults will spread, causing chain reaction, which will have disastrous consequences for the whole microservice system.

  • Service isolation: the system is divided into several service modules according to certain principles. Each module is relatively independent without strong dependence.

  • Fusing degradation: when the downstream service slows down or fails due to excessive access pressure, the upstream service can temporarily cut off the call of the downstream service in order to protect the availability of the system.

  • Service flow restriction: flow restriction can be considered as a kind of service degradation. Flow restriction is to limit the input and output flow of the system to achieve the purpose of protecting the system. Such as postponement, rejection and partial rejection.

Hystrix
1. Introduction

It is a delay and fault-tolerant library open-source by Netfix, which is used to isolate access to remote systems, services or third-party libraries to prevent cascading failures, so as to improve system availability and fault tolerance.

2. Delay and fault tolerance

Package request, trip mechanism, resource isolation, monitoring, fallback mechanism, self repair

3. Introduce the Hystrix dependency (it has been inherited in feign)
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netfix-hystrix
    </artifactId>
</dependency>
4. Configure to enable Hystrix
feign:
	hystrix:
		enabled: true
5. Customize an interface degradation logic
/**
 * Created with IntelliJ IDEA
 * User: GHYANG
 * Date: 2020-06-13
 * Description:
 */
@Component
public class ProductFeignClientCallBack implements PeoductFeignClient{
    /**
     * Fuse degradation method
     * @param id
     * @return
     */
    @Override
    public Product findById(Long id) {
        System.out.println("feign Call trigger fuse degradation method");
        return null;
    }
}
6. Add degradation method support to the interface
@FeignClient(name = "service-product",fallback = ProductFeignClientCallBack.class)
7. Configure timeout
hystrix:
	command:
		default:
			execution:
				isolation:
					thread:
						timeoutInmilliseconds: 3000
#The default connection timeout is 1s. If no data is returned in 1s, the degradation logic will be triggered automatically
8. Use the monitoring function
<!--introduce hystrix Monitoring dependency of-->
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netfix-hystrix</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netfix-hystrix-dashboard</artifactId>
</dependency>
#1 -- expose the endpoints monitored by all actors
management:
	endpoints:
		web:
			exposure:
				include: '*'
#2 -- visit localhost: port / actor on the page/ hystrix.stream
#3 -- activate the web monitoring platform @ EnableHystrixDashboard on the startup class
Alibaba Sentinel
  • Rich application scenarios, complete real-time monitoring, extensive open source ecology, and perfect SPI extension points
1. Management console
 java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar xxxxxx.jar 
#localhost:8080 sentiel--sentiel
2. Give the service to the console management
<!--Parent project introduction Alibaba Realized SpringCloud-->
<dependency>
	<grupId>com.alibaba.cloud</grupId>
    <artifactId>spring-cloud-alibaba-dependecies</artifactId>
    <version>2.1.0.RELEASE</ version>
    <type>pom</type>
    <scope>pom</scope>
</dependency>

<!--Sub project introduction sentinel-->
<dependency>
	<grupId>com.alibaba.cloud</grupId>
    <artifactId>spring-cloud-starter-sentinel</artifactId>
</dependency>
spring:
	cloud:
		sentinel:
			transport:
				dashboard: localhost:8080 
#The request address of the sentinel console
3. Define degradation logic
/**
*	blockHandler:Declare the downgrade method called when the fuse is blown
*	fallback:Declare the degradation method to be executed when the exception is executed
*	value:Custom resource name (default is current full class name. Method name)
*	The specific fuse configuration needs to be configured in real time on the sentinel console
*/
@SentinelResource(blockHandler = "orderBlockHandler",fallback = "orderFallback")


4. Load local configuration
spring:
	cloud:
		sentinel:
			datasource:
				ds1:
					file:
						file: classpath: XXXX.json #Local xxx.json file
						data-type:	json
						rule-type:	flow
//Local json file configuration
{
    {
    	"resource":"orderFindById",
    	"controlBahavior":0,
    	"count":1,
    	"grade":1,
    	"limitApp":"default",
    	"strategy":0
	}
}

6, Service gateway

Zuul 1.0 gateway
1. Introduction
2. Build Zuul gateway server
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netfix-eureka-client</artifactId>
</dependency>
3. Routing
##Method 1: route configuration -- direct configuration
zuul:
	routes:
		##Configure product service mapping
		product-service: XXX #Routing id, arbitrary
			path: /product-service/** #Map path
			url: http://127.0.0.1:9001 #The actual microservice url address corresponding to the mapping path
##Method 2: route configuration -- configure according to service
#This method needs to cooperate with eureka registry configuration
#Where serviceId is the service name registered in the registry
zuul:
	routes:
		##Configure product service mapping
		product-service: XXX #Routing id, arbitrary
			path: /product-service/** #Map path
			serviceId: service-product
##Method 3: route configuration -- if the route id is consistent with the corresponding microservice serviceId (this method is used with Eureka)
zuul:
	routes:
		service-product: /product-service/**
##Method 4: route default configuration - if the current microservice name service product can directly use the default path / service product / * * (this method is used with Eureka)
4. Filter
//Custom filter -- Take authentication as an example
@Component
public class LoginFilter entends ZuulFilter{
    /**
    * Define filter type
    * pre: Filters executed before forwarding to microservices -- mostly for authentication
    * routing: Filters executed when routing requests
    * post: Filter executed after executing microservice to get return value
    * error: Filter to execute when an exception is thrown throughout the stage
    */
    public String filterType(){
        return "pre";
    }
    
    /**
    *	Specify the filter execution order
    *		The smaller the return value, the higher the execution order
    */
   	public int filterOrder(){
        return 1;
    }
    
    /**
    *	Whether the current filter is effective*/
    public boolean showFilter(){
        return true;
    }
    
    //Execute business logic in filter
    /**
    *	Case identification:
    *	1-All requests need to carry a parameter: access token
    *	2-Get request request
    *	3-Obtain the parameter access token through request
    *	4-Judge whether the token is empty
    */
    public Object run() throws ZuulException{
        System.out.println("Run Filter");
        //1 - get the context object RequestContext provided by zuul
        RequestContext ctx = RequestContext.getCurrentContext();
        //2 - get request from RequestContext
        HttpServletRequest request = ctx.getRequest();
        //3-get the request parameter access token
        String token = request.getParameter("access-token");
        //4-judgment
        if(token == null){
            //Intercept request return authentication failed
            ctx.setSendZuulResponse(false);//Intercept request
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        //If the token is not empty, return null to continue
        return null;
    }
}
SpringCloud Gateway
1. Routing configuration
<!--springcloud Gateway Inside is through netty + webflux realization
webflux Implementation and springmvc There is a conflict-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
#Method 1: direct configuration
spring:
	cloud:
		gateway:
			routes:
				#Configure route: route id/url / assertion
				- id: product-service
				  url: http://127.0.0.1:9001 #Target microservice request address
				  predicates:
				  	-Path=/product/**    
#Method 1: according to the microservice configuration
spring:
	cloud:
		gateway:
			routes:
				#Configure route: route id/url / assertion
				- id: product-service
				  url: lb://service-product #lb: / / pull the request path from the registry according to the microservice name
				  predicates:
				  	-Path=/product/**    
spring:
	cloud:
		gateway:
			routes:
				#Configure route: route id/url / assertion
				- id: product-service
				  url: lb://service-product #lb: / / pull the request path from the registry according to the microservice name
				  predicates:
				  -Path=/product/**   
				  filters:
				  - RewritePath=/product-service/(?<segment>.*),/$\{segment} #Path rewriting filter, the $character needs to be escaped in yaml
			 discovery:
				locator:
					enabled: true #Turn on auto forwarding by service name
					lower-case-service-id: true #The microservice name is presented in lowercase
2. Filter
/**
 * Created with IntelliJ IDEA
 * User: GHYANG
 * Date: 2020-06-14
 * Description:Customize a global filter to implement the GlobalFilter ordered interface
 */
@Component
public class LoginFilter implements GlobalFilter, Ordered {

    /**
     * Specifies the execution order of the filter. The smaller the return value, the higher the execution priority
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * Execute business logic in filter
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("Custom global filter executed");
        //Filter chain next
        return chain.filter(exchange);
    }
}
3. Unified authentication
/**
     * Execute business logic in filter
     *  Judge the access token of the request parameter
     *      If this parameter exists: it means that the authentication is successful
     *      If this parameter does not exist: authentication failed
     *   ServerWebExchange: Equivalent to request and corresponding context (similar to RequestContext in zuul)
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("Custom global filter executed");
        //Get request parameters
        String token = exchange.getRequest().getQueryParams().getFirst("access-token");
        //judge
        if(token == null){
            System.out.println("Fail");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete(); //Intercept request
        }
        //Filter chain next
        return chain.filter(exchange);
    }
4. Gateway current limiting
  • Current limiting based on filter
    • Current limiting combined with redis
<!--Monitoring dependency-->
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--redis rely on-->
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
spring:
	redis:
		host: localhost
		pool: 6379
		database: 0
	cloud:
		gateway:
			routes:
				#Configure route: route id/url / assertion
				- id: product-service
				  url: lb://service-product #lb: / / pull the request path from the registry according to the microservice name
				  predicates:
				  -Path=/product-service/**   
				  filters:
				  - name: RequestRateLimiter
				  	args:
				  	#Get objects from containers using spiel
				  	key-resolver: '#{@pathKeyResolver}'
				  	#Average rate of token bucket population per second
				  	redis-rate-limiter.replenishRate: 1
				  	#Upper limit of token bucket
				  	redis-rate-limiter.bursCamacity: 3
				  - RewritePath=/product-service/(?<segment>.*),/$\{segment}
				  
#RequestRateLimiter: use the current limiting filter provided by spring cloud gateway
	#Parameter replenisrate: rate of population into token bucket
	#Parameter burstCapacity: capacity in token
@Configuration
public class KeyResolverConfiguration {
	/**
	 * Write flow restriction rules based on request path
	 * The method name is the same as the key resolver in the configuration file: '{@ pathkeyresolver}'
	 */
	 @Bean
	public KeyResolver pathKeyResolver() {
		//Customized KeyResolver
		return new KeyResolver() {
			/**
			 * ServerWebExchange :
			 *      Context parameters
			 */
			public Mono<String> resolve(ServerWebExchange exchange) {
				return Mono.just( exchange.getRequest().getPath().toString());
			}
		};
	}

	/**
	 * Current limiting based on request parameters
	 *  Request ABC? Userid = 1
	 * The method name is the same as the key resolver in the configuration file: '{@ pathkeyresolver}'
	 */
	@Bean
	public KeyResolver userKeyResolver() {
		return exchange -> Mono.just(
				exchange.getRequest().getQueryParams().getFirst("userId")
				//exchange.getRequest().getHeaders().getFirst("X-Forwarded-For") current limiting based on request ip
		);
	}
}
  • Current limiting set in Sentinel
<!--sentinel Current limiting-->
<dependency>
	<groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gatewat-adapter</artifactId>
</dependency>
/**
 * sentinel Current limiting configuration
 */
//@Configuration
public class GatewayConfiguration {

	private final List<ViewResolver> viewResolvers;
	private final ServerCodecConfigurer serverCodecConfigurer;
	public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
	                            ServerCodecConfigurer serverCodecConfigurer) {
		this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
		this.serverCodecConfigurer = serverCodecConfigurer;
	}

	/**
	 * Configure the flow limiting exception handler: SentinelGatewayBlockExceptionHandler
	 */
	@Bean
	@Order(Ordered.HIGHEST_PRECEDENCE)
	public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
		return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
	}

	/**
	 * Configure flow limiting filter
	 */
	@Bean
	@Order(Ordered.HIGHEST_PRECEDENCE)
	public GlobalFilter sentinelGatewayFilter() {
		return new SentinelGatewayFilter();
	}

	/**
	 * Configure initialized current limiting parameters
	 *  Flow restriction rules for specifying resources
	 *      1.Resource name (routing ID) - Product Service
	 *      2.Configure statistics time -- setIntervalSec
	 *      3.Configure current limit threshold -- setCount
	 */
	@PostConstruct
	public void initGatewayRules() {
		Set<GatewayFlowRule> rules = new HashSet<>();
//		rules.add(new GatewayFlowRule("product-service")
//				.setCount(1)
//				.setIntervalSec(1)
//		);
		rules.add(new GatewayFlowRule("product_api")
			.setCount(1).setIntervalSec(1)
		);
		GatewayRuleManager.loadRules(rules);
	}

	/**
	 * Custom API current limiting group
	 *      1.Define groups
	 *      2.Configure current limit rules for groups
	 */
	@PostConstruct
	private void initCustomizedApis() {
		Set<ApiDefinition> definitions = new HashSet<>();
		ApiDefinition api1 = new ApiDefinition("product_api")
				.setPredicateItems(new HashSet<ApiPredicateItem>() {{
					add(new ApiPathPredicateItem().setPattern("/product-service/product/**"). //All URLs opened with / product service / product /
							setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
				}});
		ApiDefinition api2 = new ApiDefinition("order_api")
				.setPredicateItems(new HashSet<ApiPredicateItem>() {{
					add(new ApiPathPredicateItem().setPattern("/order-service/order")); //perfect match/order-service/order url of
				}});
		definitions.add(api1);
		definitions.add(api2);
		GatewayApiDefinitionManager.loadApiDefinitions(definitions);
	}

	/**
	 * Custom current limiting processor
	 * Processor executed when current limiting is triggered
	 */
	@PostConstruct
	public void initBlockHandlers() {
		BlockRequestHandler blockHandler = new BlockRequestHandler() {
			public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
				Map map = new HashMap();
				map.put("code",001);
				map.put("message","sorry,Current limit");
				return ServerResponse.status(HttpStatus.OK)
						.contentType(MediaType.APPLICATION_JSON_UTF8)
						.body(BodyInserters.fromObject(map));
			}
		};
		GatewayCallbackManager.setBlockHandler(blockHandler);
	}
}
spring:
	cloud:
		gateway:
			routes:
				#Configure route: route id/url / assertion
				- id: product-service
				  url: lb://service-product #lb: / / pull the request path from the registry according to the microservice name
				  predicates:
				  -Path=/product/**   
				  filters:
				  - RewritePath=/product-service/(?<segment>.*),/$\{segment} #Path rewriting filter, the $character needs to be escaped in yaml
			 discovery:
				locator:
					enabled: true #Turn on auto forwarding by service name
					lower-case-service-id: true #The microservice name is presented in lowercase
5. High availability of gateway
  • High availability HA is one of the factors that must be considered in the design of distributed system architecture. It usually means to reduce the time that the system cannot provide services through design.
  • Build gateway cluster with nginx
Nginx analog gateway
<!--stay nginx.conf Configure reverse proxy-->
<!--Route to order service-->
location /api-product{
	proxy_pass http://127.0.0.1:9002;
}

<!--Routing to Commodity Services-->
location /api-order{
	proxy_pass http://127.0.0.1:9002;
}

7, Link tracking

Sleuth
<!--sleuth Link tracking-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
logging:
	level:
		root: INFO
		org.springframework.web.servlet.DispatcherServlet: DEBUG
		org.springframework.cloud.sleuth: DEBUG
Zipkin
  • Zipkin is an open source project, which is dedicated to collecting service timing data to solve the delay problem of microservice architecture, including data collection, storage, search and presentation.
  • Usage:
    • download Zipkin.jar Package and open

    • localhost:9411/Zipkin/

    • <dependency>
      <groupId>org.srpingframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zipkin</artifactId>
      </dependency>
      
    • spring:
      	zipkin:
      		base-url: http://127.0.0.1:9411/ #server's request address
      		sender:
      			type: web #The transmission mode of data has been sent to the server in the form of http
      	sleuth:
      		sampler:
      			probability: 1 #Sampling ratio (1 for full sampling)
      
  • Data persistence
    • Zipkin database table officially provided

    • #Database mount
      java -jar xxxx.jar --STORAGE_TYPE:mysql --MYSQL_HOST:127.0.0.1 --MYSQL_TOP_PORT:3306 --MYSQL_USER:root --MYSQL_PASS=xxx --MYSQL_DB=zipkin
      
  • Using message oriented middleware to optimize
  • Asynchronous data collection using rabbitMQ

    • Prepare rabbitMQ server
    • Modify the zipkin client to send the message in the form of rabbit to the mq server
    • Modify the zipkin server to pull messages from rabbit

8, Spring cloud stream

  • In the actual enterprise development, message middleware is one of the most important components. Message middleware is mainly used to solve application decoupling, asynchronous message, traffic cutting edge and other problems, to achieve high performance, high availability, high scalability and final consistency architecture. Different middleware has different implementation methods and internal structures. When the message middleware in the early stage of the project changes with the middleware in the later stage, spring cloud stream can provide a decoupling method.
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-bindeer-rabbit</artifactId>
</dependency>
#Message producer configuration
spring:
    cloud:
        stream:
            bindings:
                output:
                    destination: itcast-default #Specify the destination to send the message to
            binders: #Binder configuration
                defaultRabbit:
                    type: rabbit #rabbit Middleware

#Message consumer configuration
spring:
	cloud:
		stream:
			bindings:
				input: #The built-in channel for getting messages, and getting messages from itcast default
					destination: itcast-default
			binders:
				defaultRabbit:
					type: rabbit

9, Configuration center

SpringCloud config
  • Spring cloud config project is a configuration management solution for distributed system, which includes two parts: client and server. Server provides the storage of configuration files and provides the content of configuration files in the form of interface. Client obtains data through the interface and initializes its own application based on the data.
  • File naming rules:
    • {application}-{profile}.yml
    • {application}-{profile}.properties
    • {application} is the application name profile, which refers to the development environment (used to distinguish development environment, test environment, production environment, etc.)
<!--Configuration center dependency-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--Sub pull configuration services-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
    • Activate configuration: @ EnableConfigServer
 server:
 	port: 10000 #Service port
 spring:
 	application:
 		name: config-server #Specify service name
 	cloud:
 		config:
 			server:
 				git:
 					uri: https://xxxxxxxx.git #git address
    • Get configuration information: localhost:10000/product-dev.yml —product- dev.yml yaml file created on git
#You need to create a configuration center to create a xxx.yaml file 
spring:
	cloud:
		config:
			name: product #The application name needs to correspond to the first half of the configuration file name in git
			profile: dev #development environment 
			label: master #Branches in git
			uri: http://localhost:10000 #Request address of config server
			
#Turn on dynamic refresh request path endpoint
managment:
	endpoints:
		web:
			exposure:
				include: refresh
    • On the class requiring dynamic refresh @ RefreshScope
    • Access in postman when remote configuration changes http://localhost : 9002 / Actor / bus refresh enables data update to avoid server restart
  • When the number of microservices is large, the remote configuration needs to send update access to postman every time it changes, which will increase the workload. There are corresponding solutions in spring cloud. Spring cloud bus connects distributed nodes with lightweight message agents, which can easily build a message bus to cooperate with Spring CloudConfig realizes the dynamic update of microservice application configuration information.
Apollo
  • Apollo P is an open-source configuration management center, which can centralize the configuration of different environments and clusters of applications. After the configuration is modified, it can be pushed to the application end in real time, and has the characteristics of standard permissions, process governance, etc.
  • Construction route:
    • Download apollo related jar package and sql file
    • Extract the downloaded zip package in linux environment and change demo.sh Database connection information in
<!--Apollo Client dependency-->
<dependency>
	<groupId>com.ctrip.framework.apollp</groupId>
    <artifactId>apollo-client</artifactId>
</dependency>
apollo:
	bootstrap: #Open apllo
		enbaled: true
	meta: http://192.168.74.101:8080 
app:
	id: test01 #Specify AppId of apollo configuration center

10, Message bus

  • Message bus: in the microservice architecture, a lightweight message broker is usually used to build a common message subject to connect each microservice instance. The messages it broadcasts will be monitored and consumed by all microservice instances in the registry, also known as message bus
Configuration center integrated message bus
<!--Message bus dependency-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-bus</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
#Configure message middleware rabbit
rabbit:
	host: 127.0.0.1
	port: 5672
	username: guest
	passwort: guest	

11, Supplement

bootstrap.yml : used to execute when the program is booted, and used to read the configuration information earlier. For example, you can use bootstrap.yml to configure application.yml Parameters used in
 application.yml : application specific configuration information, which can be used to configure common parameters to be used in subsequent modules
 Loading order: bootstrap.yml  Prior to application.yml

The above are personal study notes. Some of them may not be precise or wrong. I am a pure white. Welcome to point out

Posted by taya on Sun, 14 Jun 2020 22:00:02 -0700