分布式篇:网关

网关的核心功能

动态路由

灰度发布

授权认证

性能监控

系统日志

数据缓存

限流熔断

目前业内的技术方案

Zuul
基于Java开发,核心网关功能都比较简单,但是比如灰度发布、限流、动态路由之类的,很多都要自己做二次开发
高并发能力不强,部署到一些机器上去,还要基于Tomcat来部署,Spring Boot用Tomcat把网关系统跑起来;Java语言开发,可以直接把控源码,可以做二次开发封装各种需要的功能

Kong
依托于Nginx实现,OpenResty,lua实现的模块,现成的一些插件,可以直接使用

Nginx+lua、自研网关
Nginx抗高并发的能力很强,少数几台机器部署一下,就可以抗很高的并发

动态路由

一般新增 修改 网关需要重启服务让网关生效,那会很麻烦,生产环境绝对不能这么做

可以基于二次开发,重写刷新网关路由配置

可以简单弄一个web项目

对配置的网关弄一个增删改查的功能

如果开发某个服务之后,可以在这个功能里面配置一下

表设计

CREATE TABLE `gateway_api_route` (
   `id` varchar(50) NOT NULL,
   `path` varchar(255) NOT NULL,
   `service_id` varchar(50) DEFAULT NULL,
   `url` varchar(255) DEFAULT NULL,
   `retryable` tinyint(1) DEFAULT NULL,
   `enabled` tinyint(1) NOT NULL,
   `strip_prefix` int(11) DEFAULT NULL,
   `api_name` varchar(255) DEFAULT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8

INSERT INTO gateway_api_route (id, path, service_id, retryable, strip_prefix, url, enabled) VALUES ('order-service', '/order/**', 'order-service',0,1, NULL, 1);

核心代码
@Configuration
public class DynamicRouteConfiguration {
 
    @Autowired
    private ZuulProperties zuulProperties;
    @Autowired
    private ServerProperties server;
    @Autowired
    private JdbcTemplate jdbcTemplate;
 
    @Bean
    public DynamicRouteLocator routeLocator() {
    	DynamicRouteLocator routeLocator = new DynamicRouteLocator(
    			this.server.getServletPrefix(), this.zuulProperties);
        routeLocator.setJdbcTemplate(jdbcTemplate);
        return routeLocator;
    }
 
}
----
public class DynamicRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
 
    private JdbcTemplate jdbcTemplate;
    private ZuulProperties properties;
 
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    public DynamicRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties = properties;
    }
    
    @Override
    public void refresh() {
        doRefresh();
    }
    
    @Override
    protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<>();
        // 加载application.yml中的路由表
        routesMap.putAll(super.locateRoutes());
        // 加载db中的路由表
        routesMap.putAll(locateRoutesFromDB());
        
        // 统一处理一下路由path的格式
        LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (StringUtils.hasText(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        
        System.out.println("路由表:" + values); 
        
        return values;
    }
 
    private Map<String, ZuulProperties.ZuulRoute> locateRoutesFromDB() {
        Map<String, ZuulProperties.ZuulRoute> routes = new LinkedHashMap<>();
        
        List<GatewayApiRoute> results = jdbcTemplate.query(
        		"select * from gateway_api_route where enabled = true ", 
        		new BeanPropertyRowMapper<>(GatewayApiRoute.class));
        
        for (GatewayApiRoute result : results) {
            if (StringUtils.isEmpty(result.getPath()) ) {
                continue;
            }
            if (StringUtils.isEmpty(result.getServiceId()) && StringUtils.isEmpty(result.getUrl())) {
                continue;
            }
            ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
            try {
                BeanUtils.copyProperties(result, zuulRoute);
            } catch (Exception e) { 
            	e.printStackTrace();
            }
            routes.put(zuulRoute.getPath(), zuulRoute);
        }
        
        return routes;
    }
 
}

---
public class GatewayApiRoute {
 
	private String id;
	private String path;
	private String serviceId;
	private String url;
	private boolean stripPrefix = true;
	private Boolean retryable;
	private Boolean enabled;
}
---
@Component
@Configuration      
@EnableScheduling   
public class RefreshRouteTask {
	
	@Autowired
    private ApplicationEventPublisher publisher;
    @Autowired
    private RouteLocator routeLocator;
	
    @Scheduled(fixedRate = 5000) 
    private void refreshRoute() {
        System.out.println("定时刷新路由表");  
        RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
        publisher.publishEvent(routesRefreshedEvent);
    }
    
}
---

@SpringBootApplication
@EnableZuulProxy
public class ZuulGatewayApplication {

	public static void main(String[] args) {
		SpringApplication.run(ZuulGatewayApplication.class, args);
	}

}
如果网关需要抗每秒10万的高并发访问,你应该怎么对网关进行生产优化

eureka:每台机器都是对等的,都会有高并发请求,有瓶颈

zookeeper:服务上下线,全量通知其他服务,网络带宽被打满,有瓶颈

可以自研分布式服务注册中心:分片存储服务注册表,横向扩容,每台机器均摊高并发请求,各个服务主动拉取,避免反向通知网卡被打满

在这里插入图片描述


版权声明:本文为qq_33746789原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>