This is the 12th day of my participation in the August More Text Challenge. For details, see: August More Text Challenge

Following on from the previous article:

“Original Fegin” opens the door to Fegin’s RPC technology. Will you use original Fegin? (on)

“Original Fegin” opens the door to Fegin’s RPC technology. Will you use original Fegin? (c)

Content abstract

In the project development, in addition to normal calls, load balancing and failover are also the focus, which is also the advantage of FEIGN + Ribbon. Based on the above two articles, we will carry out the last article, the original Fegin combines the Ribbon service to make remote service calls and realize the load balancing mechanism. It also helps you lay the foundation for learning the ribbon.

Maven rely on

<dependencies> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-core</artifactId> < version > 8.18.0 < / version > < / dependency > < the dependency > < groupId > com.net flix. Feign < / groupId > < artifactId > feign - Jackson < / artifactId > < version > 8.18.0 < / version > < / dependency > < the dependency > < the groupId > com.net flix. Feign < / groupId > < artifactId > feign - ribbon < / artifactId > < version > 8.18.0 < / version > < / dependency > <dependency> <groupId>com.netflix.archaius</groupId> <artifactId>archaius-core</artifactId> </dependency> </dependencies>Copy the code

Feign – Core and FeIGN – Ribbon are required, but feIGN – Jackson is recommended for object interaction between the service consumer and the service producer

Configuration is read

import com.netflix.config.ConfigurationManager;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.ribbon.RibbonClient;
public class AppRun {
    public static void main(String[] args) throws Exception {
        User param = new User();
        param.setUsername("test");
        RemoteService service = Feign.builder().client(RibbonClient.create())
				.encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
			    .options(new Options(1000.3500))
                .retryer(new Retryer.Default(5000.5000.3))
			    .target(RemoteService.class, "http://remote-client/gradle-web");
        /** * Call tests */
        for (int i = 1; i <= 10; i++) {
            User result = service.getOwner(param);
            System.out.println(result.getId() + ","+ result.getUsername()); }}}Copy the code
  • Declare an object param of type User that will be sent to the service production end as a parameter.

  • The emphasis is on the Ribbon characteristics of Feign objects through ribbonClient.create (). Then we set the encoder and decoder through encoder and decoder, and bind the RemoteService interface with a URL http://remote-client/gradle-web through target method.

Now let’s look at the configuration items in remote-client.properties, mainly the configuration mechanism of RemoteClient

remote-client.ribbon.MaxAutoRetries=1 remote-client.ribbon.MaxAutoRetriesNextServer=1 remote-client.ribbon.OkToRetryOnAllOperations=true remote-client.ribbon.ServerListRefreshInterval=2000 remote-client.ribbon.ConnectTimeout=3000 remote-client.ribbon.ReadTimeout=3000 Remote - client. Ribbon. ListOfServers = 127.0.0.1:8080127.00 0.1:8085 remote - client. Ribbon. EnablePrimeConnections = falseCopy the code

All keys start with remote-client, indicating that the configuration items apply to the service named remote-client. This schema corresponds to the URL address previously bound to the RemoteService interface.

Focus on remote – client. Ribbon. ListOfServers configuration items, the configuration item specifies the services produce the real address.

The URL address previously bound to the RemoteService interface is http://remote-client/gradle-web

Will be replaced by:

  • http://127.0.0.1:8080/gradle-web
  • http://127.0.0.1:8085/gradle-web

RequestLine: @requestline: @requestLine: @requestLine: @requestLine In this example, the final request address is:

  • http://127.0.0.1:8080/gradle-web/users/list
  • http://127.0.0.1:8085/gradle-web/users/list

Feign no longer needs to configure timeout and retry policies due to the ribbon. The ribbon provides a more sophisticated implementation of strategy.

In this case, the service production side is a simple springMvc, implemented as follows:

@RestController
@RequestMapping(value="users")
public class UserController {
    @RequestMapping(value="/list",method={RequestMethod.GET,RequestMethod.POST,RequestMethod.PUT})
    public User list(@RequestBody User user) throws InterruptedException{
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        user.setId(new Long(request.getLocalPort()));
        user.setUsername(user.getUsername().toUpperCase());
        returnuser; }}Copy the code

Failover is configured using the configuration item in remote-client.properties.

  • First using archaius project com.net flix. Config. ConfigurationManager remote reading profile – client. The properties, the file is located in the SRC/main/resources.

What about the load balancing policy?

import com.netflix.client.ClientFactory;
import com.netflix.client.config.IClientConfig;
import com.netflix.config.ConfigurationManager;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.ribbon.LBClient;
import feign.ribbon.LBClientFactory;
import feign.ribbon.RibbonClient;
public class AppRun {
    public static void main(String[] args) throws Exception {
        ConfigurationManager.loadPropertiesFromResources("remote-client.properties");
        User param = new User();
        param.setUsername("test");
        RibbonClient client = RibbonClient.builder().lbClientFactory(new LBClientFactory() {
            @Override
            public LBClient create(String clientName) {
                IClientConfig config = ClientFactory.getNamedConfig(clientName);
                ILoadBalancer lb = ClientFactory.getNamedLoadBalancer(clientName);
                ZoneAwareLoadBalancer zb = (ZoneAwareLoadBalancer) lb;
                zb.setRule(new RandomRule());
                return LBClient.create(lb, config);
            }
        }).build();
        RemoteService service = Feign.builder().client(client).encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder()).options(new Options(1000.3500))
                .retryer(new Retryer.Default(5000.5000.3)).target(RemoteService.class, "http://remote-client/gradle-web");
        /** * Call tests */
        for (int i = 1; i <= 10; i++) {
            User result = service.getOwner(param);
            System.out.println(result.getId() + ","+ result.getUsername()); }}}Copy the code

Other load balancing policies

 /** * Ribbon Implements load balancing policy * Uses ZoneAvoidancePredicate and AvailabilityPredicate to determine whether a server is selected. The former determines whether a zone is available for performance. * Deletes unavailable zones (all servers). AvailabilityPredicate is used to filter out servers with too many connections. *@return* /

	private IRule zoneAvoidanceRule(a) {
        return new ZoneAvoidanceRule();
    }

    /** * the Ribbon implements a load balancing policy. *@return* /
    private IRule randomRule(a) {
        return new RandomRule();
    }
Copy the code

Instead of using the ribbonClient.create () to create the default RibbonClient, Instead, the ribbonClient.Builder () is used to obtain the feign.ribbon.Builder, and then the implementation of the LBClientFactory is set up to customize the LBClient. The implementation of the load policy can be specified during the creation of the LBClient.