微服务分布式协作框架tridenter使用介绍

tridenter是一款基于SpringBoot框架开发的微服务分布式协作框架,它可以使多个独立的SpringBoot应用轻松快捷地组成一个集群,而不依赖外部的注册中心(比如SpringCloud Eureka等)。
tridenter框架首先提供了丰富的分布式应用集群管理API和工具,同时也提供了一套完整的微服务治理功能

tridenter的特性:

  1. 采用去中心化的思想管理集群
  2. 支持集群间的消息多播和单播
  3. 支持各种负载均衡策略
  4. 支持多种Leader选举算法
  5. 提供进程池/调度进程池的实现
  6. 内置微服务注册中心
  7. 内置多种微服务间调用的限流降级策略
  8. 内置微服务Rest客户端
  9. 内置HTTP服务网关
  10. 集群状态监控和告警
  11. 分布式事务管理

集群中的消息多播是tridenter非常重要的功能,tridenter底层是通过Redis(PubSub)实现多播功能从而实现应用的相互发现的,进而组成应用集群的。集群中的每个成员都支持消息多播和单播的能力。
利用tridenter支持消息单播的能力,tridenter提供了Leader选举算法接口,内置了两种Leader选举算法,快速Leader选举算法(基于Redis队列)和一致性选举算法(基于Paxos算法)
同时,利用tridenter支持消息单播的能力,tridenter提供了进程池,实现了跨进程的方法调用和方法分片的能力
另一方面,tridenter本身也提供了微服务治理的基本功能:
tridenter自带注册中心,而利用消息多播的原理,应用是相互发现,相互注册的,所以集群中的每个成员都有一份全量的成员列表,即每个应用都是注册中心,体现了去中心化的设计思想。每个成员通过命名服务,实现了应用之间HTTP接口互相调用的能力,并提供了相关各种注解和Restful配置将服务发布方和消费方解耦
tridenter自带网关功能,可以将应用独立发布成网关服务,可代理分发HTTP请求和下载任务(暂不支持上传)
tridenter还内置了多种负载均衡算法和限流降级策略,用户也可以自定义负载均衡算法或降级策略
tridenter实现了spring actuator的健康检查接口,除了监控集群状态,还自带接口的统计分析等功能,初步实现了接口的统一管理和监控
所以,基于tridenter框架,我们也可以搭建一套类似于Spring Cloud的微服务体系

tridenter采用了去中心化的设计思想,即开发人员不需要知道当前哪个是主节点,哪些节点是从节点,更不应该显式地定义某个应用为主节点,这是由tridenter采用的Leader选举算法决定的,默认的选举算法是快速选举算法。根据选举算法,集群内的任意一个应用节点都有可能成为主节点,默认第一个启动的应用就是主节点,但是如果采用的是一致性选举算法,可能就会不一样。根据作者描述,一致性选举算法目前不稳定,推荐在应用中使用快速选举算法。

Maven:

        <dependency>
            <groupId>com.github.paganini2008.atlantis</groupId>
            <artifactId>tridenter-spring-boot-starter</artifactId>
            <version>1.0-RC3</version>
        </dependency>

tridenter的基本功能就是让不同的Spring Boot应用变成集群模式,所以配置的时候,我们要在application.properties 定义两个系统变量,否则会报错

spring.application.name=chaconne-management  # 服务名称
spring.application.cluster.name=chaconne-management-cluster  #集群名称

启动之后,如果在Console看到以下信息则表示集群配置生效

2021-06-05 18:20:11 [INFO ] io.undertow - starting server: Undertow - 2.0.29.Final
2021-06-05 18:20:11 [INFO ] org.xnio - XNIO version 3.3.8.Final
2021-06-05 18:20:11 [INFO ] org.xnio.nio - XNIO NIO Implementation Version 3.3.8.Final
2021-06-05 18:20:11 [INFO ] i.a.f.t.m.ApplicationMulticastGroup - Registered candidate: {applicationContextPath: http://192.168.159.1:6543, applicationName: chaconne-management, clusterName: chaconne-management-cluster, id: fafdc9ada3a5d1de3836b1a0ba4ef174, leader: false, startTime: 1622888405582, weight: 1}, Proportion: 1/1
2021-06-05 18:20:11 [INFO ] i.a.f.t.m.ApplicationRegistryCenter - Register application: [{applicationContextPath: http://192.168.159.1:6543, applicationName: chaconne-management, clusterName: chaconne-management-cluster, id: fafdc9ada3a5d1de3836b1a0ba4ef174, leader: false, startTime: 1622888405582, weight: 1}] to ApplicationRegistryCenter
2021-06-05 18:20:11 [INFO ] i.a.f.c.SerialDependencyListener - SerialDependencyHandler initialize successfully.
2021-06-05 18:20:11 [INFO ] i.a.f.t.e.ApplicationLeaderElection - This is the leader of application cluster 'chaconne-management-cluster'. Current application event type is 'indi.atlantis.framework.tridenter.election.ApplicationClusterLeaderEvent'
2021-06-05 18:20:11 [INFO ] i.a.f.t.e.ApplicationLeaderElection - Current leader: {applicationContextPath: http://192.168.159.1:6543, applicationName: chaconne-management, clusterName: chaconne-management-cluster, id: fafdc9ada3a5d1de3836b1a0ba4ef174, leader: true, startTime: 1622888405582, weight: 1}
2021-06-05 18:20:11 [INFO ] o.s.b.w.e.u.UndertowServletWebServer - Undertow started on port(s) 6543 (http) with context path ''
2021-06-05 18:20:12 [INFO ] i.a.f.c.m.ChaconneManagementMain - Started ChaconneManagementMain in 12.134 seconds (JVM running for 12.829)

首先:

2021-06-05 18:20:11 [INFO ] i.a.f.t.m.ApplicationMulticastGroup - Registered candidate: {applicationContextPath: http://192.168.159.1:6543, applicationName: chaconne-management, clusterName: chaconne-management-cluster, id: fafdc9ada3a5d1de3836b1a0ba4ef174, leader: false, startTime: 1622888405582, weight: 1}, Proportion: 1/1
2021-06-05 18:20:11 [INFO ] i.a.f.t.m.ApplicationRegistryCenter - Register application: [{applicationContextPath: http://192.168.159.1:6543, applicationName: chaconne-management, clusterName: chaconne-management-cluster, id: fafdc9ada3a5d1de3836b1a0ba4ef174, leader: false, startTime: 1622888405582, weight: 1}] to ApplicationRegistryCenter

这两行日志分别表示成功注册消息多播组和应用注册中心

2021-06-05 18:20:11 [INFO ] i.a.f.t.e.ApplicationLeaderElection - This is the leader of application cluster 'chaconne-management-cluster'. Current application event type is 'indi.atlantis.framework.tridenter.election.ApplicationClusterLeaderEvent'
2021-06-05 18:20:11 [INFO ] i.a.f.t.e.ApplicationLeaderElection - Current leader: {applicationContextPath: http://192.168.159.1:6543, applicationName: chaconne-management, clusterName: chaconne-management-cluster, id: fafdc9ada3a5d1de3836b1a0ba4ef174, leader: true, startTime: 1622888405582, weight: 1}

这两行日志分别表示利用ApplicationLeaderElection选举算法选出当前的应用是leader,(快速选举算法默认将第一个启动的应用作为Leader, 有点类似Jgroups)

tridenter-spring-boot-starter是一个基础型的框架,提供了各种分布式能力,下面介绍一下几种能力:

进程池

多个同名应用(${spring.application.name})可以组建成一个进程池,就像线程池分配不同的线程调用某个方法一样,进程池可以进行跨应用的方法调用,前提是这个方法是存在的

示例代码:

    @MultiProcessing(value = "calc", defaultValue = "11")
    public int calc(int a, int b) {
        if (a % 3 == 0) {
            throw new IllegalArgumentException("a ==> " + a);
        }
        log.info("[" + counter.incrementAndGet() + "]Port: " + port + ", Execute at: " + new Date());
        return a * b * 20;
    }

    @OnSuccess("calc")
    public void onSuccess(Object result, MethodInvocation invocation) {
        log.info("Result: " + result + ", Take: " + (System.currentTimeMillis() - invocation.getTimestamp()));
    }

    @OnFailure("calc")
    public void onFailure(ThrowableProxy info, MethodInvocation invocation) {
        log.info("========================================");
        log.error("{}", info);
    }

说明:

  1. 注解 @MultiProcessing修饰方法calc, 表示这个方法是多进程调用的
  2. onSuccess和onFailure两个方法都是异步的调用的

方法分片

方法分片又叫方法并行处理,其实就是将一组参数的每一个参数使用进程池分发到不同应用上运行,然后再合并输出,并需要实现分片规则接口,见源码:

public interface Parallelization {

    Object[] slice(Object argument); // 切片

    Object merge(Object[] results);  // 合并

}

示例代码:

    @ParallelizingCall(value = "loop-test", usingParallelization = TestCallParallelization.class)
    public long total(String arg) {// 0,1,2,3,4,5,6,7,8,9
        return 0L;
    }

    public static class TestCallParallelization implements Parallelization {

        @Override
        public Long[] slice(Object argument) {
            String[] args = ((String) argument).split(",");
            Long[] longArray = new Long[args.length];
            int i = 0;
            for (String arg : args) {
                longArray[i++] = Long.parseLong(arg);
            }
            return longArray;
        }

        @Override
        public Long merge(Object[] results) {
            long total = 0;
            for (Object o : results) {
                total += ((Long) o).longValue();
            }
            return total;
        }

    }

说明:

  1. 注解@ParallelizingCall修饰total方法,表示这个方法要做分片处理
  2. 参数arg, 比如说你可以传 0,1,2,3,4,5,6,7,8,9,分片规则会调用slice方法将参数以“,”分割,变成数组,然后将每个值转换成long型,再分发到各个应用执行,全部执行完了,再执行merge方法进行加和操作,有点MapReduce的味道
  3. total方法返回的0,是指当参数为空或方法异常返回的默认值

微服务能力

Rest客户端

示例代码:

@RestClient(provider = "test-service")
// @RestClient(provider = "http://192.168.159.1:5050")
public interface TestRestClient {

    @PostMapping("/metrics/sequence/{dataType}")
    Map<String, Object> sequence(@PathVariable("dataType") String dataType, @RequestBody SequenceRequest sequenceRequest);

}

说明:

  1. 注解@RestClient修饰的接口说明这是个Http客户端
  2. 注解中,provider属性表示服务提供方,可以是集群中的某个应用名(${spring.application.name}),也可以是具体http地址
  3. 支持Spring注解(GetMapping, PostMapping, PutMapping, DeleteMapping), 此外,用注解@Api可提供更细粒度的参数设置

网关

@EnableGateway
@SpringBootApplication
@ComponentScan
public class GatewayMain {

    public static void main(String[] args) {
        final int port = 9000;
        System.setProperty("server.port", String.valueOf(port));
        SpringApplication.run(GatewayMain.class, args);
    }
}

引用注解@EnableGateway就行了,tridenter的网关底层是用Netty4实现的

配置路由:
@Primary
@Component
public class MyRouterCustomizer extends DefaultRouterCustomizer {

    @Override
    public void customize(RouterManager rm) {
        super.customize(rm);
        rm.route("/my/**").provider("tester5");
        rm.route("/test/baidu").url("https://www.baidu.com").resourceType(ResourceType.REDIRECT);
        rm.route("/test/stream").url("  https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png").resourceType(ResourceType.STREAM);
    }

}

说明:
ResourceType的4种类型:
DEFAULT, 转发请求
REDIRECT, 跳转
STREAM, 二进制流
FILE 保存文件

限流降级

限流是指在客户端限流,而非服务端
限流会依赖3个指标:

  1. 响应超时率
  2. 错误率
  3. 并发度
    默认情况,当这三个指标中有任一指标超过80%,即会触发限流,调用降级服务
    限流指标统计类 : RequestStatisticIndicator
    降级服务接口:FallbackProvider
    相关源码可自行研究

健康监控

目前tridenter提供了3个HealthIndicator的子类

  1. ApplicationClusterHealthIndicator
    显示集群的整体健康状态
  2. TaskExecutorHealthIndicator
    显示集群线程池的健康状态
  3. RestClientHealthIndicator
    显示Rest客户端的健康状态(响应超时率,错误率,并发度)

最后,微服务分布式协作框架tridenter的源码地址:https://github.com/paganini2008/tridenter-spring-boot-starter.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 124,600评论 2 7
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,042评论 0 4