3、网关和BFF

  • Post author:
  • Post category:其他


一、网关和BFF的演进

  1. v1 使用nginx负载均衡简单的微服务体系;

  2. v2 nginx直接暴露

  3. v2.5无线BFF

  4. v3 集群BFF+无线网关

  5. v4无线网关、无线BFF根据业务集群化,废弃nginx集群

    二、网关和反向代理

网关和反向代理的选择:

关于网关集群问题:需要根据公司业务大小进行选择

三、设计简单网关-faraday

1.核心思想


2.代码实现

  • 路由映射表模块

    • MappingsProvider路由映射表
      package xyz.staffjoy.faraday.core.mappings;
      
      import com.github.structlog4j.ILogger;
      import com.github.structlog4j.SLoggerFactory;
      import org.springframework.boot.autoconfigure.web.ServerProperties;
      import xyz.staffjoy.faraday.config.FaradayProperties;
      import xyz.staffjoy.faraday.config.MappingProperties;
      import xyz.staffjoy.faraday.core.http.HttpClientProvider;
      
      import javax.annotation.PostConstruct;
      import javax.servlet.http.HttpServletRequest;
      import java.util.List;
      import java.util.stream.Collectors;
      
      import static org.springframework.util.CollectionUtils.isEmpty;
      
      public abstract class MappingsProvider {
      
          private static final ILogger log = SLoggerFactory.getLogger(MappingsProvider.class);
      
          protected final ServerProperties serverProperties;
          protected final FaradayProperties faradayProperties;
          protected final MappingsValidator mappingsValidator;
          protected final HttpClientProvider httpClientProvider;
          protected List<MappingProperties> mappings;
      
          public MappingsProvider(
                  ServerProperties serverProperties,
                  FaradayProperties faradayProperties,
                  MappingsValidator mappingsValidator,
                  HttpClientProvider httpClientProvider
          ) {
              this.serverProperties = serverProperties;
              this.faradayProperties = faradayProperties;
              this.mappingsValidator = mappingsValidator;
              this.httpClientProvider = httpClientProvider;
          }
      
          public MappingProperties resolveMapping(String originHost, HttpServletRequest request) {
              if (shouldUpdateMappings(request)) {
                  updateMappings();
              }
              List<MappingProperties> resolvedMappings = mappings.stream()
                      .filter(mapping -> originHost.toLowerCase().equals(mapping.getHost().toLowerCase()))
                      .collect(Collectors.toList());
              if (isEmpty(resolvedMappings)) {
                  return null;
              }
              return resolvedMappings.get(0);
          }
      
          @PostConstruct
          protected synchronized void updateMappings() {
              List<MappingProperties> newMappings = retrieveMappings();
              mappingsValidator.validate(newMappings);
              mappings = newMappings;
              httpClientProvider.updateHttpClients(mappings);
              log.info("Destination mappings updated", mappings);
          }
      
          protected abstract boolean shouldUpdateMappings(HttpServletRequest request);
      
          protected abstract List<MappingProperties> retrieveMappings();
      }
      
      resolveMapping:根据主机头获取路由映射;
      updateMappings:更新路由表;
  • http映射表

    • 根据路由映射表获取到的路由,通过http映射表对目标服务发起调用

      package xyz.staffjoy.faraday.core.http;
      
      import org.apache.http.impl.client.CloseableHttpClient;
      import org.apache.http.impl.client.HttpClientBuilder;
      import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
      import org.springframework.web.client.RestTemplate;
      import xyz.staffjoy.faraday.config.MappingProperties;
      
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      import static java.util.stream.Collectors.toMap;
      import static org.apache.http.impl.client.HttpClientBuilder.create;
      
      public class HttpClientProvider {
          protected Map<String, RestTemplate> httpClients = new HashMap<>();
      
          public void updateHttpClients(List<MappingProperties> mappings) {
              httpClients = mappings.stream().collect(toMap(MappingProperties::getName, this::createRestTemplate));
          }
      
          public RestTemplate getHttpClient(String mappingName) {
              return httpClients.get(mappingName);
          }
      
          protected RestTemplate createRestTemplate(MappingProperties mapping) {
              CloseableHttpClient client = createHttpClient(mapping).build();
              HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client);
              requestFactory.setConnectTimeout(mapping.getTimeout().getConnect());
              requestFactory.setReadTimeout(mapping.getTimeout().getRead());
              return new RestTemplate(requestFactory);
          }
      
          protected HttpClientBuilder createHttpClient(MappingProperties mapping) {
              return create().useSystemProperties().disableRedirectHandling().disableCookieManagement();
          }
      }
      

四、大型网关扩展

  • 限流熔断:保障用户体验,保障服务不会挂断
  • 动态路由和负载均衡:当服务多时,采用动态服务发现机制,k8s内部支持
  • 基于Path的路由:通过域名映射到服务
  • 截获器链:多个截获器构成的链状
  • 日志采集和Metrics埋点:日志+日志分析;掌握后台性能状况
  • 响应流优化:响应速度大时,内核态无需拷贝到用户态,直接以流的形式提供给网关

五、主流网关概览



版权声明:本文为kk_lina原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。