逗号的博客

这里有一句格言,但我还没想好

问题

在我们的业务中有一个生产者程序不停地向 message 表写入记录,简化的 message 表的结构如下所示

1
2
3
4
5
6
7
CREATE TABLE message
(
id SERIAL, -- ID
content VARCHAR, -- 消息内容
create_time TIMESTAMPTZ, -- 创建时间
PRIMARY KEY (id)
);

另外有一个消费者程序不停地读取 message 表的数据,这个消费者程序依赖一个称为“水位线”的时间戳,所有创建时间小于等于水位线的消息都已经处理,我们使用 consumer 表来记录当前的水位线

1
2
3
4
5
6
CREATE TABLE consumer
(
id SERIAL, -- ID
watermark TIMESTAMPTZ, -- 水位线
PRIMARY KEY (id)
);

我们会有一个定时任务每隔一段时间调度一次消费者程序,消费者程序的主要逻辑是

  1. 检查当前水位线

    1
    2
    3
    4
    5
    test=# SELECT watermark FROM consumer;
    watermark
    ------------------------
    2024-04-30 15:16:17+08
    (1 row)
  2. 使用当前水位线加载待处理消息

    1
    2
    3
    4
    5
    6
    test=# SELECT content, create_time FROM message WHERE create_time > '2024-04-30 15:16:17+08' AND create_time <= NOW() ORDER BY create_time;
    content | create_time
    ---------+-------------------------------
    aaa | 2024-04-30 16:17:18.936795+08
    bbb | 2024-04-30 17:18:19.956867+08
    (2 rows)
  3. 逐条处理消息,并用当前消息的创建时间更新水位线,最后一条消息处理完成时

    1
    2
    3
    4
    5
    6
    7
    test=# UPDATE consumer SET watermark = '2024-04-30 17:18:19.956867+08';
    UPDATE 1
    test=# SELECT watermark FROM consumer;
    watermark
    -------------------------------
    2024-04-30 17:18:19.956867+08
    (1 row)

就当前的 SQL 版本模拟的逻辑而言在定时任务第 2 轮调度时将没有待处理消息。但是当我们使用 Java 语言实现上面的逻辑时我们发现在定时任务第 2 轮调度时内容为 bbb 的消息会再一次被处理。在 Java 版本的实现里我们使用了 java.util.Date 类型来表示 create_timewatermark

阅读全文 »

问题

假设有一个 PDI(Kettle)Job,运行这个 Job 需要耗时 30 秒钟。现在每 10 秒钟调度运行一次这个 Job。我们的问题是这个 Job 的运行情况是怎样的?具体地说是上一个调度的 Job 还没有执行完就到了下一个调度的 Job 的执行时间,那么下一个调度的 Job 会执行吗?也就是定时任务如果执行的时间很长的话,那么下一次还能按时执行嘛?

  • Case 1:无论上一次 Job 是否执行完成,下一次 Job 按照 10 秒钟的间隔准时开始;
  • Case 2:上一次 Job 未执行完成,下一次 Job 不会开始执行;一旦上一次 Job 执行完成,下一次 Job 立即开始执行,中间没有间隔;
  • Case 3:上一次 Job 未执行完成,下一次 Job 不会开始执行;上一次 Job 执行完成后等待 10 秒钟的间隔再开启下一次 Job 的执行;

Kettle 的定时任务是哪一种情况呢?

阅读全文 »

通过前面几篇文章我们已经实现了将网关作为资源服务器并在网关实现认证和授权,其他服务将是一个纯粹的微服务,那么我们将问一个问题其他微服务如何获取到已授权用户的用户信息?

阅读全文 »

问题描述

通常授权服务是作为独立的服务进行部署的或者使用的是由其他服务商提供的服务。Spring Authorization Server 比较特殊,它既可以作为独立服务进行部署,就如在上一篇文章介绍的那样;又因为它是 Spring 体系下的一员,因此将它作为内部服务部署在 Gateway 后面又是完全可行的。但是在实践的过程中遇到了一点儿问题,下面是具体的问题描述。

阅读全文 »

我们将要实现这样一个微服务系统,将 Spring Cloud Gateway 作为 OAuth2 的资源服务器,在 Gateway 实现集中的统一的鉴权功能,各个微服务之间的调用不再单独鉴权。系统的规划如下表所示

系统 端口 说明
example-auth 9090 认证与授权服务
example-eureka 8761 服务注册中心
example-gateway 8080 服务网关
example-user 8081 用户服务
example-product 8082 商品服务
example-order 8083 订单服务
example-common - 公共模块

example-auth 是一个独立的服务,它不会向服务注册中心注册自己,其他的服务,包括 example-gateway,均需要向服务注册中心注册自己。

阅读全文 »

Spring Security OAuth 的生命周期已经结束,官方已经删除它的文档,现在推荐使用 Spring Authorization Server,但是还是有很多老项目在继续使用 Spring Security OAuth,学习它仍然是必要的。虽然官方文档已经删除了,但是找到了一篇较早时间的翻译 Spring Security OAuth2 开发指南,可以作为实践的基础。网络上也有很多如何使用它的文章,这篇文章是自己实践的一点记录。

阅读全文 »

备注:Knife4j 通过 com.github.xiaoymin.knife4j.spring.extension.Knife4jOpenApiCustomizer 类的 addOrderExtension 方法给 Tag 类应用 @ApiSupport 注解的 order 属性。

问题描述

在我们的一个项目中使用了 Knife4j 来显示 Swagger 的文档,具体的依赖如下

1
2
3
4
5
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>

同时我们有两个 Controller,它们分别是

1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController
@RequestMapping("/user")
@Tag(name = "用户管理")
public class UserController {
// 省略了...
}

@RestController
@RequestMapping("/role")
@Tag(name = "角色管理")
public class RoleController {
// 省略了...
}

默认情况下,在 Knife4j 的页面中“角色管理”显示在了“用户管理”的前面。我们期望“用户管理”显示在“角色管理”的前面。为了达到这个目的我们使用了 Knife4j 提供的注解 @ApiSupport,修改后的代码如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
@RequestMapping("/user")
@Tag(name = "用户管理")
@ApiSupport(order = 1)
public class UserController {
// 省略了...
}

@RestController
@RequestMapping("/role")
@Tag(name = "角色管理")
@ApiSupport(order = 2)
public class RoleController {
// 省略了...
}

但是并没有什么效果,“用户管理”并没有显示在“角色管理”的前面,即 @ApiSupport 注解没有生效。

阅读全文 »
0%