The preface

Grab the previous article:

Gitee.com/davonding/d gitee address…

  • Learn Dubbo from Scratch – Basics – Remote Calls using juejin.cn/post/694942…
  • Learn Dubbo from scratch – Basics -SPI use juejin.cn/post/694947…
  • Dubbo- Basics – Filters and load Balancing juejin.cn/post/694972…
  • Dubbo- Basics – Thread Pools and Routing juejin.cn/post/695021…

Routing Scenarios

Imagine a scenario where a Dubbo provider is ready to go live, typically providing multiple providers to provide services online at the same time. Just as a request arrives at a provider, the provider closes it. The request should then be considered a failure. So based on this scenario, we can remove pre-published (grayscale) machines from the machine list by routing rules. And wait for a certain amount of time to complete the processing of existing requests before shutting down the service. At the same time, when starting, also need to wait for a certain period of time, so as not to restart the end, has been registered. After the startup reaches a certain time, start the flow operation again.

The implementation idea is as follows:

1. Use the path awareness function of ZooKeeper to write the IP address and application name of the current server to ZooKeeper before restarting the service. 2. The service consumer listens to the directory, reads the list of application names and machine IP addresses to be shut down, and saves them in memory. 3. When the current request comes in, determine whether the application is requested. If the application is requested to restart, remove the provider from the service list.Copy the code

Start by creating the Router module

1. Implement ZK client operation classes

Introduce the Curator framework for easy operation of Zookeeper, dependent

< the dependency > < groupId > org. Apache. Curator < / groupId > < artifactId > curator - recipes < / artifactId > < version > 4.2.0 < / version > </dependency>Copy the code

Write Zookeeper operation classes to facilitate Zookeeper processing

public class ZookeeperClients { private final CuratorFramework client; // Singleton private static ZookeeperClients zookeeperClient; Static {// Retry policy final ExponentialBackoffRetry ExponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3); / / the curator client final CuratorFramework CuratorFramework = CuratorFrameworkFactory. NewClient (127.0.0.1: "2181", exponentialBackoffRetry); zookeeperClient=new ZookeeperClients(curatorFramework); // Start the client curatorFramework.start(); } private ZookeeperClients(CuratorFramework Client) {this.client = client; } public static CuratorFramework client(){ return zookeeperClient.client; }}Copy the code

2. Implement the path listener

Implement a path manager that needs to be pre-published for caching and listening to a list of services to be published.

public class ReadyRestartInstances implements PathChildrenCacheListener { private static final Logger logger=LoggerFactory.getLogger(ReadyRestartInstances.class); private static final String PATH ="/study/dubbo/restart/instances"; //zkclient private final CuratorFramework client; Private volatile set <String> restartInstances=new HashSet<>(); private ReadyRestartInstances(CuratorFramework client) { this.client = client; } @Override public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent PathChildrenCacheEvent) throws Exception {// Queries the configuration information of all directories in the listening path. Final List<String> List = client.getChildren().forPath(PATH); Set if(collectionutils.isEmpty (list)){restartInstances= collections.emptySet (); } // The node is not null if(! CollectionUtils.isEmpty(list)) { restartInstances=new HashSet<>(list); } } public static ReadyRestartInstances create(){ final CuratorFramework client = ZookeeperClients.client(); Final Stat Stat = client.checkexists ().forpath (PATH); // Check whether the listening PATH exists. If (stat == null){client.create().creatingParenTsiFNeeded ().forPATH (PATH); } } catch (Exception e) { e.printStackTrace(); Logger. error(" error:{}", LLDB etMessage()); } final ReadyRestartInstances readyRestartInstances = new ReadyRestartInstances(client); Final PathChildrenCache PathChildrenCache = new PathChildrenCache(Client, PATH, false); / / cache object to node to join to monitor pathChildrenCache getListenable () addListener (readyRestartInstances); try { pathChildrenCache.start(); } catch (Exception e) { e.printStackTrace(); Logger. error(" failed to start path listening "); } return readyRestartInstances; Public void addRestartingInstances(String applicationName,String host) throws Exception { client.create().creatingParentsIfNeeded().forPath(PATH +"/"+buildApplicationAndInstanceString(applicationName,host)); } / / removing restart instance methods public void removeRestartingInstances (String applicationName, String host) throws the Exception { client.delete().forPath(PATH +"/"+buildApplicationAndInstanceString(applicationName,host)); Public Boolean hasRestartingInstances(String applicationName,String host){return restartInstances.contains(buildApplicationAndInstanceString(applicationName,host)); } / / returns the name _ private host String String buildApplicationAndInstanceString (String appliactionName, String host) {return appliactionName+"_"+host; }}Copy the code

3. Implement the Router interface

Interface configuration routing rules, mainly route method

public class RestartingInstanceRouter implements Router { private final ReadyRestartInstances readyRestartInstances; private final URL url; public RestartingInstanceRouter(URL url) { this.url = url; this.readyRestartInstances=ReadyRestartInstances.create(); } @Override public URL getUrl() { return null; } @Override public <T> List<Invoker<T>> route(List<Invoker<T>> list, URL url, Throws RpcException {// The server whose Invocation is in the list does not return list.stream(). Filter (I ->! readyRestartInstances.hasRestartingInstances(i.getUrl().getParameter("remote.application"),i.getUrl().getIp())).collect( Collectors.toList()); } @Override public boolean isRuntime() { return false; } @Override public boolean isForce() { return false; } @Override public int getPriority() { return 0; }}Copy the code

4. Implement the RouterFactory interface to complete the SPI configuration

The validity range @activate can also be configured here

@Activate public class RestartingInstanceRouterFactory implements RouterFactory { @Override public Router getRouter(URL url) { return new RestartingInstanceRouter(url); }}Copy the code

In the resources directory meta-inf/directory dubbo, new to org. Apache. The dubbo. RPC. Cluster. RouterFactory naming. Then configure: restartInstances = com. Study. The router. RestartingInstanceRouterFactory

5. The consumer references the router dependency

1. Implement a class that simulates service additions and deletions

public class ServerRestartMain { public static void main(String[] args) throws Exception { final ReadyRestartInstances readyRestartInstances = ReadyRestartInstances.create(); / / simulation to release new service readyRestartInstances addRestartingInstances (" dubbo - service - the provider ", "172.16.8.233"); . / delete/simulation for publishing services readyRestartInstances removeRestartingInstances (" dubbo - service - the provider ", "172.16.8.233"); }}Copy the code

2. The test

First check out ZK, there are no machines to release

Test it for normal use

Perform the new machine to be released, check zK, there is a service to be released, that is, the machine.

When tested again, there are no available services, and unpublished services are not invoked. (Since I only have one machine here, normally multiple machines will access other available machines)

Service degradation

What is service degradation

Service degradation: When the server pressure increases sharply, the service level of some services is lowered strategically based on the current service status and traffic to release server resources and ensure the normal running of core tasks.

Why service downgrades

And why use service degradation, which is to prevent an avalanche effect on distributed services, what is an avalanche? Is the butterfly effect, when a timeout occurred, please have been waiting for the service response, so under the condition of high concurrency, many request because it has been waiting for the response, until the service outage resource depletion, and after the outage can cause distributed other service calls the outage of services also can appear resources exhausted downtime, This will lead to the collapse of the entire distributed service, it is an avalanche.

1. Use the annotation @Reference

@reference (mock=”force:return null”) also supports @reference (mock=”force:return null”)

Start by setting the service invocation response time to 1000ms

    String hello=bean.sayHello("test",1000);
Copy the code

And then the response timeout (route set) is set to 1000ms. The request to view the result of the call timed out

This is when the mock is configured on the consumer caller

@reference (loadBalance = "random",mock = "return test ") private HelloDubbo HelloDubbo;Copy the code

Request again and look at the result, and you’ll see that the mock data is returned when the request fails

If mock=”force:return null” is configured this way, force return is returned.

2. Use Java dynamic configuration

I’m not going to do the demo here

RegistryFactory registryFactory = ExtensionLoader .getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry = registryfactory.getregistry (url.valueof ("zookeeper://IP: port ")); Registry. Register (URL. The valueOf (" override: / / 0.0.0.0 / com. Foo. BarService? category=configurators&dynamic=false&application=foo&mock=force:return+null"));Copy the code