JoyLau's Blog

JoyLau 的技术学习与思考

安装插件

插件地址: https://jenkinsci.github.io/dingtalk-plugin/

流水线配置

使用语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def description = sh(returnStdout: true, script: 'mvn -q -N -Dexec.executable="echo"  -Dexec.args=\'${project.description}\'  org.codehaus.mojo:exec-maven-plugin:3.0.0:exec').trim()
dingtalk (
robot: 'id',
type: 'ACTION_CARD',
title: 'Jenkins 流水线构建提醒',
text: [
'![](http://nas.joylau.cn:5016/1920x1080?' + UUID.randomUUID().toString() + ')',
'### Jenkins 流水线构建结果',
'- 项目描述:' + description,
'- 分支名:' + env.BRANCH_NAME,
'- 构建状态:失败',
'- 构建时间:' + currentBuild.durationString
],
)

效果

Jenkins-Dingtalk

说明

Spring Boot 项目使用 ShardingSphere-JDBC,默认情况下会接管配置的全部数据源,这会导致一些问题
比如,所有的 sql 执行都会走 ShardingSphere 的分库或者分别的逻辑判断
最重要的是,ShardingSphere 不支持的 SQL 会直接报错
比如: https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/unsupported-items/
还有: https://shardingsphere.apache.org/document/current/cn/features/sharding/use-norms/sql/#%E4%B8%8D%E6%94%AF%E6%8C%81%E7%9A%84sql

1
2
3
4
5
6
7
8
9
10
-- SELECT子句暂不支持使用*号简写及内置的分布式主键生成器
INSERT INTO tbl_name (col1, col2, …) SELECT * FROM tbl_name WHERE col3 = ?
-- SELECT子句暂不支持使用*号简写及内置的分布式主键生成器
REPLACE INTO tbl_name (col1, col2, …) SELECT * FROM tbl_name WHERE col3 = ?
-- 会导致全路由
SELECT * FROM tbl_name1 UNION SELECT * FROM tbl_name2 UNION
SELECT * FROM tbl_name1 UNION ALL SELECT * FROM tbl_name2 UNION ALL
SELECT * FROM tbl_name WHERE to_date(create_time, ‘yyyy-mm-dd’) = ?
-- 查询列是函数表达式时,查询列前不能使用表名;若查询表存在别名,则可使用表的别名
SELECT MAX(tbl_name.col1) FROM tbl_name

这是不能忍的情况

解决方案

官方已经给出的解决方案:
FQA

  1. 如果只有部分数据库分库分表,是否需要将不分库分表的表也配置在分片规则中?
    回答:

是的。因为ShardingSphere是将多个数据源合并为一个统一的逻辑数据源。因此即使不分库分表的部分,不配置分片规则ShardingSphere即无法精确的断定应该路由至哪个数据源。
但是ShardingSphere提供了两种变通的方式,有助于简化配置。

方法1:配置default-data-source,凡是在默认数据源中的表可以无需配置在分片规则中,ShardingSphere将在找不到分片数据源的情况下将表路由至默认数据源。

方法2:将不参与分库分表的数据源独立于ShardingSphere之外,在应用中使用多个数据源分别处理分片和不分片的情况。

方法 1 的配置方式不适合我
我选择了 方法 2
具体做法如下:

操作

依赖引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.0.0-beta</version>
<exclusions>
<!-- 版本太低,有安全漏洞:log4j-1.2.17.jar: CVE-2020-9488, CVE-2019-17571 ,排除掉 -->
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>

项目配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
spring:
application:
name: im
datasource:
dynamic:
primary: im
strict: false
datasource:
im:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://xxxxxx:xxxx/im?useUnicode=true&characterEncoding=utf-8
type: com.zaxxer.hikari.HikariDataSource
username: xxxx
password: xxxx
shardingsphere:
datasource:
names: sharding-sphere
sharding-sphere:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://xxxxxx:xxxx/sharding-sphere?useUnicode=true&characterEncoding=utf-8
type: com.zaxxer.hikari.HikariDataSource
username: xxxx
password: xxxx
rules:
sharding:
tables:
message:
actual-data-nodes: sharding-sphere.message_$->{0..1}_$->{2021..2030}${(1..12).collect{t ->t.toString().padLeft(2,'0')}}
table-strategy:
complex:
sharding-columns: conversation_type, timestamp
sharding-algorithm-name: message-table-strategy
sharding-algorithms:
message-table-strategy:
type: MessageComplexKeysShardingAlgorithm
props: { }
props:
sql-show: true

配置了 2 个数据库
im 为主库:正常增删改查的数据库
sharding-sphere:专为分库分表的使用的数据库

还配置一个分表规则,分表策略为自定义策略 MessageComplexKeysShardingAlgorithm

自定义策略

shardingsphere-jdbc 5.x 的分表策略使用的是 SPI 机制

具体就是在 resources/META-INF/services 目录下新增配置文件 org.apache.shardingsphere.sharding.spi.ShardingAlgorithm
将 shardingsphere-jdbc 5.x 自带的策略和自定义的策略加入进去

如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

org.apache.shardingsphere.sharding.algorithm.sharding.inline.InlineShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.mod.ModShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.mod.HashModShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.range.VolumeBasedRangeShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.range.BoundaryBasedRangeShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.datetime.AutoIntervalShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.datetime.IntervalShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.classbased.ClassBasedShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.complex.ComplexInlineShardingAlgorithm
org.apache.shardingsphere.sharding.algorithm.sharding.hint.HintInlineShardingAlgorithm

com.hfky.im.wildfirechat.msgforward.policy.MessageComplexKeysShardingAlgorithm

自定义策略如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MessageComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<?>> {

/**
* 根据type和time分片。
*/
@Override
public Collection<String> doSharding(
Collection<String> collection, ComplexKeysShardingValue<Comparable<?>> shardingValue) {
}

@Override
public void init() {
//
}

@Override
public String getType() {
return "MessageComplexKeysShardingAlgorithm";
}

@Override
public Properties getProps() {
return ComplexKeysShardingAlgorithm.super.getProps();
}

@Override
public void setProps(Properties props) {
ComplexKeysShardingAlgorithm.super.setProps(props);
}
}

安装规则重写 doSharding 方法即可

动态多数据源配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Configuration
public class DataSourceConfiguration {

private final DynamicDataSourceProperties properties;

private final Map<String, DataSource> dataSources;

public DataSourceConfiguration(DynamicDataSourceProperties properties, @Lazy Map<String, DataSource> dataSources) {
this.properties = properties;
this.dataSources = dataSources;
}


/**
* 加入 shardingSphere 的数据源。
*/
@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
return new AbstractDataSourceProvider() {
@Override
public Map<String, DataSource> loadDataSources() {
Map<String, DataSource> dataSourceMap = new HashMap<>();
dataSourceMap.put(ShardingSphereDataSource.class.getAnnotation(DS.class).value(),
dataSources.get("shardingSphereDataSource"));
return dataSourceMap;
}
};
}

/**
* 设置主数据源。
*/
@Bean
@Primary
public DataSource dataSource() {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
}

2 个注解用来切换数据源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@DS("im")
public @interface ImDataSource {
}


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@DS("sharding-sphere")
public @interface ShardingSphereDataSource {
}

使用方法

是需要使用数据源的 Mapper 或者 Service 加入 @ImDataSource 注解 或者 @ShardingSphereDataSource 注解, 不加的话使用的是默认数据源 im
如上配置的话,正常使用用的就是 im 数据库,分库分表使用的就是 sharding-sphere 数据库

使用 Maven 的 exec 插件

有时候我们需要使用 mvn 命令获取 maven 项目的一些信息, 比如版本号, 项目名称,项目描述等,除了解析 pom.xml 文件,还可以使用以下
命令来获取这些信息

1
mvn -q -N -Dexec.executable="echo"  -Dexec.args='${project.description}'  org.codehaus.mojo:exec-maven-plugin:3.0.0:exec

proxy_cookie_path source target;
source 源路径
target 目标路径

使用原因

cookie 的 path 与地址栏上的 path 不一致
浏览器就不会接受这个 cookie,无法传入 JSESSIONID 的 cookie
导致登录验证失败

使用场景

当 nginx 配置的反向代理的路径和源地址路径不一致时使用

使用 Demo

1
2
3
4
5
6
7
8
9
# elastic-job 代理配置
location /etc-job/api/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://10.55.3.139:8088/api/;
proxy_cookie_path / /etc-job/api/;
proxy_set_header Cookie $http_cookie;
}

  1. 下载 minIO 客户端

http://dl.minio.org.cn/client/mc/release/linux-amd64/mc

拷贝到 MySQL 服务器的 /usr/bin 目录下并授权

chmod +x /usr/bin/mc

  1. 配置 mc 客户端

mc config host add minio http://10.55.3.132:9000 "AKIAIOSFODNN7EXAMPLE" "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

文档地址: https://docs.min.io/minio/baremetal/reference/minio-cli/minio-mc.html

  1. 添加备份脚本

mysql-backup.sh

1
2
3
4
5
6
7
8
9
#!/bin/sh

# 创建桶 mysql-backup
mc mb minio/mysql-backup

docker exec mysql-slave-1 mysqldump -h 10.55.3.123 -u root -pKaiyuan@2020 etc | mc pipe --attr "Artist=mysql" minio/mysql-backup/etc-`date "+%Y-%m-%d_%H-%M-%S"`.sql

# 删除 10 天前的备份
mc rm --older-than=10d --force --recursive minio/mysql-backup/

chmod +x mysql-backup.sh

  1. 添加定时任务
1
2
3
4
crontab -e

30 4 * * * /root/backup-mysql.sh>/root/backup-mysql.log 2>&1 &

说明

公司内网的 GitLab 服务很久没升级了,记录下最近的升级步骤

现有部署情况

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: "3"
services:
gitlab:
image: gitlab/gitlab-ce:15.4.2-ce.0
container_name: gitlab
ports:
- 80:80
- 443:443
- 22:22
volumes:
- ./config:/etc/gitlab
- ./log:/var/log/gitlab
- ./data:/var/opt/gitlab
restart: always

gitlab.rc 文件配置:

1
2
3
external_url 'http://192.168.1.41'
#备份保存时间为 2 天, 单位为秒
gitlab_rails['backup_keep_time'] = 172800

只配置了这 2 项, 其他均为默认配置

升级步骤

首先备份当前服务的数据, docker exec 进入容器, 执行

gitlab-backup create

耐心等待备份完成
后续出问题要恢复的话,执行
gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce

接下来开始升级,升级的思路是逐步升级到一个大版本开始和结束,一层层往上升级,这里官方给出的升级路线是:

8.11.Z -> 8.12.0 -> 8.17.7 -> 9.5.10 -> 10.8.7 -> 11.11.8 -> 12.0.12 -> 12.1.17 -> 12.10.14 -> 13.0.14 -> 13.1.11 -> 13.8.8 -> 13.12.15 -> 14.0.12 -> 14.3.6 -> 14.9.5 -> 14.10.Z -> 15.0.Z -> 15.4.0 -> latest 15.Y.Z

官方文档

还有个升级路径检测 工具

根据上述路径, 我们只需要每次更改 image: gitlab/gitlab-ce:15.4.2-ce.0 的版本号,重启容器,等容器 Gitlab 正常提供服务,再重复步骤即可

0%