前言

在微服务架构体系下,随着时间的推移,难免会碰到由于前期服务粒度的划分不能完全满足后续需求的增长,造成"微"服务的二度拆分。拆分不可避免的会导致服务在整个系统中的链路发生变化,如何保证链路上游服务在无感知的情况下完成链路下游服务的拆分,动态路由可以帮助我们解决这个问题。

先介绍一下服务架构设计

一 待拆分链路(open)

二 拆分后链路

三 动态路由

基于spring cloud zuul

1.目标:实现一个通用的动态路由服务

2.参考:更深层次的探讨,请进 传送门

3.功能: 在zuul-gateway-demo的基础上,简化了路由配置表;新增路由刷新策略保证细粒度的path优先路由;自动刷新频率的配置化;

四 dynamic-route

1.项目依赖

org.springframework.boot

spring-boot-starter

org.springframework.boot

spring-boot-starter-actuator

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-test

compile

org.mybatis.spring.boot

mybatis-spring-boot-starter

1.1.1

mysql

mysql-connector-java

${mysql.version}

com.alibaba

druid

${alibaba.druid.version}

org.springframework.cloud

spring-cloud-starter-zuul

${spring.cloud.version}

2 配置文件

application.yml

zuul:

host:

socket-timeout-millis: 150000

connect-timeout-millis: 150000

max-total-connections: 200 # 路由最大连接数

max-per-route-connections: 100 #每个路由并发数

ribbon:

eureka:

enabled: false #不使用注册中心

# 路由自动刷新频率(分钟)

ebtce:

routeRefresh: 15

3 服务启动

启动类 :DynamicRouteApplication

//注入ZuulAutoFilter对象

@Bean

public ZuulAutoFilter zuulAutoFilter(){

return new ZuulAutoFilter();

}

@Autowired

private ZuulRouteVoService zuulRouteVoService;

// 注入监听线程对象

@Autowired

private MonitorThread monitorThread;

@Autowired

public void setInitialize(){

//读取路由表,信息放入一个Map对象中

zuulRouteVoService.initZuulRouteVoMap();

// 设置为守护线程

monitorThread.setDaemon(true);

monitorThread.start();

}

public static void main(String[] args) {

// 启动服务

SpringApplication.run(DynamicRouteApplication.class, args);

// 控制监听线程的状态: 等待(0) 启动(1) 退出(-1)

MonitorThreadControl.setState(1);

}

4 zuul 路由表生成

自定义路由配置类:CustomZuulConfig

@Bean

public CustomRouteLocator routeLocator(){

CustomRouteLocator routeLocator = new CustomRouteLocator(serverProperties().getServletPrefix(), zuulProperties());

return routeLocator;

}

路由发现:CustomRouteLocator

@Override

protected Map locateRoutes(){

// 加载配置信息

LinkedHashMap routeLinkedHashMap = ZuulRouteVoService.ZUUL_ROUTE_VO_MAP;

//优化一下配置

LinkedHashMap values = new LinkedHashMap<>();

log.info("========= dynamic route info ========== ");

for(Map.Entry entry : routeLinkedHashMap.entrySet()){

String path = entry.getKey();

if(!path.startsWith("/")){

path = "/" + path;

}

if(StringUtils.hasText(this.properties.getPrefix())){

path = this.properties.getPrefix();

if(!path.startsWith("/")){

path = "/" + path;

}

}

ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();

BeanUtils.copyProperties(entry.getValue(), zuulRoute);

values.put(path, zuulRoute);

log.info(JSON.toJSONString(zuulRoute));

}

// 路由信息装配完成后,清除临时存放路由信息的Map对象

ZuulRouteVoService.clearRouteMap();

return values;

}

在这里我们发现,zuul把路由信息写到了一个LinkedHashMap对象中,路径匹配时将循环LinkedHashMap对象,发现符合条件的路径表达式即将对其进行路由,先匹配先得。为保证细粒度的路径优先匹配,保证LinkedHashMap对象初始化时粒度细的表达式在前即可。

SELECT CONCAT(id, '') as id, host, path from dynamic_route where is_read = 1 ORDER BY path DESC

5 动态刷新

时间刷新路由:RefreshRouteService

// 1 事件触发路由刷新

public void refreshRoute(){

// 读取路由表信息

zuulRouteVoService.initZuulRouteVoMap();

//有需要刷新的路由才触发刷新,若路径已存在,刷新将被重写

if(!ZuulRouteVoService.ZUUL_ROUTE_VO_MAP.isEmpty()){

RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);

publisher.publishEvent(routesRefreshedEvent);

log.info("== dynamic route refresh success! ==");

}else{

log.info("== routing information is not updated ==");

}

}

// 2. 刷新事件监听线程

@Override

public void run(){

while (true){

int state = MonitorThreadControl.getState();

if(state == 0)

continue;

if(state < 0){

log.warn("============ MonitorThread EXIT ===============");

return;

}

try {

// ensure that the last route refresh is completed

if(ZuulRouteVoService.ZUUL_ROUTE_VO_MAP.isEmpty()){

refreshRouteService.refreshRoute();

}

}catch (Exception e){

log.error("", e);

}

try {

Thread.sleep(refreshTime * (60 * 1000));

} catch (InterruptedException e) {

log.error("", e);

}

}

}

6 路由数据模型

CREATE TABLE dynamic_route (

id int(10) unsigned NOT NULL AUTO_INCREMENT,

host varchar(100) NOT NULL,

path varchar(256) NOT NULL,

is_read tinyint(1) NOT NULL DEFAULT '0' COMMENT '1:路由 0:不路由',

PRIMARY KEY (id),

UNIQUE KEY idx_path (path)

) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

id:路由服务id

host:对应路由url

path:路由路径表达式

is_read:是否读取/路由,控制路径的路由状态

五 源码获取

后记

先取后予,欢迎大家讨论和补充!

zuul 动态路由mysql_zuul 动态路由 - typistw的个人空间 - OSCHINA - 中文开源技术交流社区...相关推荐

  1. linux内核等价多路径路由,高级路由 - 我是*李世民*的个人空间 - OSCHINA - 中文开源技术交流社区...

    策略路由背后的概念 Linux内核在默认情况下使用两张路由表:一张表用于本地路由,另一张可以由管理员来配置.如果内核编译支持策略路由,那么可以有多大255张不同的.相互独立的路由表.策略路由背后的主要 ...

  2. Linux黑洞路由命令,配置黑洞路由 - osc_ywuazj5t的个人空间 - OSCHINA - 中文开源技术交流社区...

    拓扑图 在R1上配置一条静态路由:ip route-static  192.168.0.0   16     10.1.1.2:在R2上配置一条默认静态路由:ip route-static 0.0.0 ...

  3. php 随机字节集,易语言字节集动态加密 - osc_zsm40sb6的个人空间 - OSCHINA - 中文开源技术交流社区...

    原理很简单: 字节集1(n位随机字节集) 字节集2(m位随机字节集) 被加密字节集=字节集1+被加密字节集+字节集2 被加密字后的字节集=加密(被加密字节集,密码) 解密后的字节集=解密(被解密字节集 ...

  4. php 10的次方,动态 - 1的10次方 - OSCHINA - 中文开源技术交流社区

    你们都说得对,可是下面这个代码怎么优化呢? public String(int[] codePoints, int offset, int count) { if (offset < 0) { ...

  5. Zuul动态路由及动态Filter实现

    一, Zuul动态路由实现 动态路由需要达到可持久化配置,动态刷新的效果.不仅要能满足从spring的配置文件properties加载路由信息,还需要从Redis加载我们的配置.另外一点是,路由信息在 ...

  6. nodejs之express路由与动态路由

    1.快速创建express项目步骤 /*** 1.cd 到项目里面* 2.npm init --yes 创建package.json文件* 3.安装express* npm install expre ...

  7. 【计算机网络】网络层 : 路由算法 ( 路由算法分类 | 静态路由算法 | 动态路由算法 | 全局性动态路由算法 | 分散性动态路由算法 | 分层次路由选择协议 )

    文章目录 一.路由算法 二.路由算法 分类 三.静态路由算法 四.动态路由算法 五.动态路由算法 分类 六.分层次的路由选择协议 一.路由算法 路由算法 : 选择数传输的 "最佳路由&quo ...

  8. router vue 动态改变url_Vue教程(路由router-基本使用)

    本文开始我们来给大家介绍在Vue中非常重要的一个内容,就是路由Router 什么是路由 后端路由:对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源: 前端路由:对于 ...

  9. 动态导航与动态路由绑定

    动态导航与动态路由绑定 引言 1.导航数据的获取 2.进行导航菜单和路由动态绑定. 2.1动态导航 2.2动态路由绑定 3.问题及解决方法 引言 正常的后台管理系统会分不同的用户,不同的用户会对应不同 ...

最新文章

  1. 和我一起作Tess的windbg lab - Lab3, Memory
  2. 通过 PSO实现TSP问题优化
  3. git add -u与-A .三者的区别
  4. Python基础day03【字符串(定义、输入输出、常用方法)、列表(定义、基本使用、增删改查、嵌套)、元组】
  5. CompletableFuture多任务组合
  6. 前端面试题之http/HTML/浏览器(一)
  7. Beamer演示时不能正常显示底栏的问题及解决
  8. Windows Server 2012 如何将计算机图标添加到桌面
  9. 一步步实现koa核心代码
  10. JQuery实用技巧--学会你也是大神(1)——插件的制作技巧
  11. UE源码版本下载编译全流程
  12. 如何把直播嵌入微信公众账号
  13. 【LaTex 中英文样式加粗】自由选择中英文字体样式,中英文字体粗黑程度设置
  14. 汉字编码(【Unicode】 【UTF-8】 【Unicode与UTF-8之间的转换】 【汉字 Unicode 编码范围】【中文标点Unicode码】【GBK编码】【批量获取汉字UNICODE码】)
  15. 【论文阅读/翻译笔记】Deep Snake for Real-Time Instance Segmentation
  16. Day17 静态页面 导航及图片结构与样式
  17. 广义预测控制(GPC,含公式推导和仿真截图)
  18. SQL的INSERT INTO和INSERT INTO SELECT语句
  19. CCNP路由实验之十一 IPv6 (8月5号账号被盗,乱发博文深表抱歉,感谢客服帮忙取回密码)
  20. mp4怎么转换成mp3

热门文章

  1. opencv-python视频处理之白闪效果
  2. Oracle XTTS跨平台数据库迁移(从Unix迁移数据库到Linux)_Oracle数据库迁移项
  3. MySQL主主双机负载均衡
  4. nginx代理多个flask
  5. XamarinForms教程构建XamarinForms开发环境
  6. 与应用程序松耦合的报表开发组织
  7. Apache日志配置参数说明
  8. 基于Springboot实现的固废物管理系统
  9. 机器学习基础专题:线性判别器
  10. [git]一个本地仓库,多个远程仓库