分布式ETCD、Raft、Opentracing、Jaeger

文章介绍了ETCD作为服务发现的工具,基于Raft算法实现一致性,并探讨了服务注册、健康检查和查找机制。接着,文章讨论了Raft算法的领导者、跟随者和候选人的角色转换以及选举过程。Opentracing作为一个跨平台的链路追踪标准,通过Jaeger这样的实现帮助分析分布式系统中的服务调用。最后,文章提到了JWT作为跨域认证的解决方案,描述了其生成和验证流程。
摘要由CSDN通过智能技术生成

ETCD

  ETCD是一种开源分布式键值存储主要用在服务发现上,服务发现 (Service Discovery) 要解决的是分布式系统中最常见的问题之一,即在同一个分布式集群中的进程或服务如何才能找到对方并建立连接。,从本质上说服务发现就是要了解集群中是否有进程在监听UPD或者TCP端口,并且通过名字就可以进行查找和链接。要解决服务发现问题一般需要三个条件,分别是一个强一致性、高可用的服务存储目录;一种注册服务和审查服务健康状况的机制;一种查找和链接服务的机制。强一致性和高可用的服务存储目录:etcd是基于raft算法实现的,具有很好的一致性。etcd 集群是一个分布式系统,由多个节点相互通信构成整体对外服务,每个节点都存储了完整的数据,并且通过 Raft 协议保证每个节点维护的数据是一致的。每个 etcd 节点都维护了一个状态机,并且,任意时刻至多存在一个有效的主节点(领导者)。主节点处理所有来自客户端写操作,通过 Raft 协议保证写操作对状态机的改动会可靠的同步到其他节点。注册服务和审查服务健康状况的机制:用户可以在etcd中注册服务,并且对注册的服务配置key TTL,定时保持服务的心跳以达到监控健康状态的效果。查找和连接服务的机制:通过在etcd指定的主题下注册的服务业能在对应的主题下查找到。为了确保连接,我们可以在每个服务机器上都部署一个proxy模式的etcd,这样就可以确保访问etcd集群的服务都能够互相连接。
ETCD的项目地址:https://github.com/coreos/etcd/

Raft算法

  raft算法:raft算法是分布式系统中的保持数据一致性的算法,所有的一致性算法都会涉及到状态机,而状态机从一个一致的状态开始,以相同的顺序执行一系列指令最终到达另一个一致的状态,在raft算法中在任意时刻,每个服务器节点都只处于 leader,follower或candidate这三个状态之一。leader:领导者,在通常情况下,系统中只有一个领导人并且其他的节点全部都是跟随者。follow:跟随者,他们不会发送任何请求,只是简单的响应来自领导者或者候选人的请求。candidate:选举者,当集群没有领导者时,跟随者会转变成 candidate。几种状态变化如下所示:
starts up:集群启动时
time out, start election:follow 在没有收到 leader 心跳后开始选举变成选举者 candidate;
time out,new election:在当前选举中没有出现 leader,此轮次超时后进行下一轮选举
dicocers current leader or new term:当发现已经选出新的 leader,也就是收到 leader 的心跳信息,或者发现已经开始新的 term 任期,选举者状态 candidate 将会转化成 follow。
dicover serer with higher term:当前的 leader 可能因为网络分区的问题和集群中的其他 follow 失去心跳联系,这时候集群选举出了新的 leader,这时候 leader 就要变成 follow 状态。
receives votes from mahority servers:当 candidate 收到集群中大多数的投票时,会被选举成新的 leader,进入 leader 状态。
raft将时间划分成一个一个的任期,每个任期开始都是一个选举, 选举成功后 leader 会管理集群到任期结束,如果任期中没有选举成功,那么这个任期会因为没有领导人而结束,这时候 candidate 因为选举超时(也就是没有选出 leader 的超时时间)而自动开启下一个任期 term。
  他们通过 rpc 请求来进行服务器之间的远程调用和通信,并且基本的一致性算法只需要两种类型的 RPCs。请求投票(RequestVote) RPCs 由候选人在选举期间发起,然后附加条目 (AppendEntries)RPCs 由领导人发起,用来复制日志和提供一种心跳机制。除此之外在服务器之间传输快照增加了第三种 RPC。
RequestVote RPC(请求投票):由 candidate 在选举期间发起。
AppendEntries RPC(追加条目):由 leader 发起,用来复制日志和提供一种心跳机制。下面是一个展示raft算法很好的视频演示动画:http://thesecretlivesofdata.com/raft/

Opentracing

  使用链路追踪的原因:当一个生产系统面对真正的高并发,或者解耦成大量微服务时,以前很容易实现的重点任务变得困难了。开发过程中需要面临一系列问题:用户体验优化、后台真实错误原因分析,分布式系统内各组件的调用情况等。在这些问题的驱动下,Tracing 变成了分布式系统必不可少的组成部分。而Opentracing 通过提供平台无关、厂商无关的 API,使得开发人员能够方便的添加(或更换)追踪系统。Opentracing 提供了用于运营支撑系统的和针对特定平台的辅助程序库。在 Opentracing 标准中,trace 是多个 span 组成的一个有向无环图(DAG),每一个 span(一个 span 代表系统中具有开始时间和执行时长的逻辑运行单元。span 之间通过嵌套或者顺序排列建立逻辑因果关系。) 代表 trace (一个 trace 代表一个潜在的,分布式的,存在并行数据或并行执行轨迹(潜在的分布式、并行)的系统。一个 trace 可以认为是多个 span 的有向无环图(DAG))中被命名并计时的连续性的执行片段。分布式追踪中的每个组件都包含自己的一个或者多个 span。简单地说,OpenTracing 是一个 Library 库,定义了一套通用的数据上报接口,要求各个分布式追踪系统都来实现这套接口。这样一来,应用程序只需要对接 OpenTracing,而无须关心后端采用的到底是什么样的分布式追踪系统,因此开发者可以无缝切换分布式追踪系统,也使得在通用代码库增加对分布式追踪的支持成为可能。
  在知道了分布式链路追踪的基础概念之后,下面来使用一种流行的分布式链路追踪组件Jaeger。项目连接:https://github.com/go-gorm/opentracing
  Jaeger是用于追踪分布式服务之间事务的开源软件,它为微服务场景而生。它主要用于分析多个服务的调用过程,图形化服务调用轨迹,是诊断性能问题、分析系统故障的利器。使用时需要部署分布式追踪服务器(Jaeger)然后在项目中启动跟踪器客户端,并将跟踪器设置为开放跟踪,代码示例如下:

import (
	"github.com/opentracing/opentracing-go"
	"github.com/uber/jaeger-client-go"
	"github.com/uber/jaeger-client-go/config"
	jaegerlog "github.com/uber/jaeger-client-go/log"
)

func bootTracerBasedJaeger() {
	// jaeger tracer configuration
	cfg := &config.Configuration{
		Sampler: &config.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		ServiceName: "gormopentracing",
		Reporter: &config.ReporterConfig{
			LogSpans: true,
			//LocalAgentHostPort:  "127.0.0.1:6381",
			BufferFlushInterval: 100 * time.Millisecond,
			CollectorEndpoint:   "http://127.0.0.1:14268/api/traces",
		},
	}

	// jaeger tracer client 
	tracer, _, err := cfg.NewTracer(
		config.Logger(jaegerlog.StdLogger),
		config.ZipkinSharedRPCSpan(true),
	)
	if err != nil {
		log.Printf("failed to use jaeger tracer plugin, got error %v", err)
		os.Exit(1)
	}
	
	// set into opentracing's global tracer, so the plugin would take it as default tracer.
	opentracing.SetGlobalTracer(tracer)
}

  在本地打开http://127.0.0.1:14268/api/traces就可以看到如下界面
在这里插入图片描述
在这里插入图片描述
  我们可以在界面中使用搜索窗格搜索具有特定属性的trace:它们来自哪个服务、进行了哪些操作、跟踪中包含的特定标签(例如,http 状态代码)、响应多长时间。

  JWT认证:JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案。当用户成功登录系统并成功验证有效之后,服务器会产生一个token字符串,这个token中可以包含很多信息,例如来源IP,过期时间,用户信息等, 把这个字符串下发给客户端,客户端在之后的每次请求中都携带着这个token,携带方式其实很自由,无论是cookie方式还是其他方式都可以。当服务端收到请求,取出token进行验证(可以验证来源ip,过期时间等信息),如果合法则允许进行操作。具体的使用流程如下所示:客户端携带用户的登录凭证(一般为用户名密码)提交请求;服务端收到登录请求,验证凭证正确性,如果正确则按照协议规定生成token信息,经过签名并返回给客户端;客户端收到token信息,可以保存在cookie或者其他地方,以后每次请求的时候都携带上token信息;业务服务器收到请求,验证token的正确性,如果正确则进行下一步操作,示例如下:

@SpringBootTest
//第一步先引入依赖
class SpringBootJWtApplicationTests {

    public static final String SIGNATURE = "tiofjdifjaihu899#(*U(*#@";
    private String token;

    @Test
    public void contextLoads() {
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND, 90);
		
        # 第二步: 生成 token
        String token = JWT.create()
                .withClaim("username", "Zhang San")
                .withClaim("password", "Java")
                .withExpiresAt(instance.getTime())  // 过期时间
                .sign(Algorithm.HMAC256(SIGNATURE));

        this.token = token;
        System.out.println("令牌 = " + token);
		
        # 根据令牌和签名解析数据
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SIGNATURE)).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        System.out.println("用户名 : " + decodedJWT.getClaim("username").asString());
        System.out.println("密 码 : " + decodedJWT.getClaim("password").asString());
        System.out.println("过期时间 : " + decodedJWT.getExpiresAt());
    }
}

#4.常见异常信息
- SignatureVerificationException:  签名不一致异常
- TokenExpiredException: 令牌过期异常
- AlgorithmMismatchException: 算法不匹配异常
- InvalidClaimException: 失效的payload异常


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值