分布式系统:常见问题解决方案专题

专题一:分布式Id

分布式 ID 是什么?

分布式 ID 是一种在分布式系统中生成唯一标识符(ID)的方案,用于标识系统中各个实体(如用户、订单、商品等)。在分布式系统中,生成的 ID 需要具备全局唯一性和高效性。分布式 ID 通常用于数据库主键、消息队列标识、文件系统等场景中。

为什么使用分布式 ID?

分布式系统中,多个节点可能需要生成 ID,保证 ID 唯一性是一个关键问题。如果不采用合理的分布式 ID 生成机制,可能会导致冲突或重复的 ID,从而引发数据不一致、操作冲突等问题。分布式 ID 生成方案解决了以下几个问题:

  1. 全局唯一性:ID 在不同的机器、服务之间生成时必须确保全局唯一,避免重复。
  2. 高并发性能:分布式环境下,ID 生成需要支持高并发,避免成为系统的瓶颈。
  3. 去中心化:不依赖单一的中心节点生成 ID,避免单点故障和性能瓶颈。
  4. 时间有序:在某些场景中,ID 的生成顺序可能会对业务有一定要求。

分布式 ID 生成方案

目前有多种方案可以用于生成分布式 ID,下面是几种常见的实现方式:

方案一:UUID (通用唯一标识符)

UUID 是一种常见的 ID 生成方案,生成的 ID 长度通常为 128 位,具有全局唯一性。UUID 的特点是:

  • 全局唯一性:UUID 使用算法确保在分布式环境下的唯一性。
  • 不依赖于时间戳或者机器标识,生成方式完全独立。
  • 存储和传输时需要较大的空间(32 字符的字符串,带有 4 个连字符)。
	String id = UUID.randomUUID().toString();
	// 5d1634ae-da40-43ec-9aad-f0e808a42886
方案二:数据库自增 ID

通过数据库的自增列生成 ID,适用于小规模的分布式系统,单台数据库服务器生成自增 ID,但是该方案的缺点是:

  • 单点问题:如果数据库服务器出现故障,可能会导致 ID 生成不可用。
  • 性能瓶颈:当并发量较高时,数据库可能成为性能瓶颈。
  • 无法支持多节点:如果系统需要在多个节点上生成 ID,单一的数据库无法支持。
方案三:号段模式

号段模式的核心思想是,每个服务或每个节点从中心服务器申请一个 ID 号段(即一段连续的 ID),然后在本地生成 ID。当本地用完该号段时,再向中心服务器申请新的号段。这样,每个节点只需维护一个本地的计数器,并且可以通过持续请求号段来确保 ID 的唯一性。号段模式的特点:

  • 高效性:生成 ID 的速度非常快,因为本地计数器递增,不涉及复杂的网络请求。
  • 唯一性:每个服务都从中心服务申请独立的号段,因此 ID 在全局范围内是唯一的。
  • 分布式支持:多个节点可以并行生成 ID,避免了中心化服务的瓶颈。
  • 内存占用:每个节点都需要存储自己的号段和计数器,如果号段过大,可能会占用较多的内存。
  • 号段耗尽问题:如果某个节点的号段用尽且无法及时从中心服务器获取新的号段,可能会出现 ID 重复或 ID 不可用的情况。
方案四:Snowflake (雪花算法)

Snowflake 是 Twitter 提出的分布式 ID 生成算法,生成的 ID 是一个 64 位的整数,具有全局唯一性和时间有序性。Snowflake 的 ID 结构如下:
在这里插入图片描述

专题二:分布式Session

分布式 Session 是什么?

分布式 Session 是指在分布式系统或集群环境中,将用户的会话数据(Session 数据)存储在一个共享、可访问的地方,而不是存储在单一的应用服务器或单个进程中。这样,无论用户请求被哪个应用服务器处理,都能访问到相同的会话数据,从而确保在分布式环境下,用户体验一致且不丢失会话信息。

为什么使用分布式 Session?

负载均衡:在分布式系统中,负载均衡器会将请求分发到不同的服务器节点上。如果每个服务器节点维护本地 Session,用户的请求可能会被路由到不同的节点,导致无法共享同一个 Session 数据。而使用分布式 Session,可以确保无论用户请求被哪个节点处理,都能访问到一致的会话数据。

  1. 可扩展性:随着应用的扩展,可能需要添加更多的服务器节点。如果每个节点都维护自己的 Session 数据,扩展会变得困难。而使用分布式 Session,可以通过共享存储来处理扩展,不需要对每个节点的 Session 进行迁移或同步。
  2. 高可用性:分布式 Session 通过集中存储,可以确保会话数据的高可用性。即使某个节点宕机,其他节点仍然可以从共享存储中读取会话数据,避免用户体验中断。
  3. 容错性:通过将 Session 数据存储在分布式存储系统(如 Redis)中,可以提供数据的冗余备份,从而增强系统的容错性。如果某个节点故障,Session 数据不会丢失,系统可以继续正常工作。

分布式 Session 的常见实现方案

方案一:Spring-Session
  • 优点:数据持久化、易于管理、支持事务。
  • 缺点:性能较低,相比于内存数据库,响应速度较慢,数据库可能成为瓶颈。

pom.xml

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

application.yml

spring:
  redis:
    host: 127.0.0.1
    port: 6379
  session:
    store-type: redis
    timeout: 3600
    redis:
      namespace: login_user

demo

	@GetMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password, HttpSession session){
   
        //账号密码正确
        session.setAttribute("login_user", username);
        return "登录成功";
    }

    @GetMapping("/info")
    public String info(HttpSession session) {
   
        return "当前登录的是:" + session.getAttribute("login_user");
    }
方案二:Token + Redis

Redis 是一种高效的内存数据存储,它广泛用于存储 Session 数据,尤其适用于分布式应用。Redis 可以通过其高效的读写性能和数据共享功能,支持跨多个应用节点共享会话数据。

  • 优点:高性能、低延迟、易于扩展,支持数据的自动过期。
  • 缺点:数据可能会丢失(如果没有持久化),对内存要求较高。
    pom.xml
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

application.yml

spring:
  redis:
    host: 127.0.0.1
    port: 6379

demo

 	@GetMapping("/loginWithToken")
    public String loginWithToken(@RequestParam String username, @RequestParam String password) {
   
        //账号密码正确
        String key = "token_" + UUID.randomUUID().toString();
        stringRedisTemplate.opsForValue().set(key, username, 3600, TimeUnit.SECONDS);
        return key;
    }

    @GetMapping("/infoWithToken")
    public String infoWithToken(@RequestHeader String token) {
   
        return "当前登录的是:" + stringRedisTemplate.opsForValue().get(token);
    }
方案三:JWT WEb Token(加密算法)

通过JWT(JSON Web Token)生成 Token 来标识会话。客户端存储 Session ID,服务器只需验证 Token 即可。

  • 优点:无状态服务器,不需要额外的存储,简化了服务器端的会话管理。
  • 缺点:适用于无状态认证,且 Token 易被篡改,需额外的安全机制。
    pom.xml
		<dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>

demo

	@GetMapping("/loginWithJwt")
    public String loginWithJwt(@RequestParam String username, @RequestParam String password) {
   
        Algorithm algorithm = Algorithm.HMAC256(JWT_KEY);
        String token = JWT.create()
                .withClaim("login_user", username)
                .withClaim(UID, 1)
                .withExpiresAt(new Date(System.currentTimeMillis()</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值