数据库的 migration 随着时间的迁移会越来越多,这会带来一些问题:
如果确认目前所有的生成环境都已经升级大于 migration 的某一个版本了就可以考虑把之前的 migration 都压缩掉了,这样可以减少一些不必要的麻烦。比如我们确定目前所有的环境的 migration 版本都大于 400 了,那么我们就可以压缩 400 以及之前的 migration。
本地启动一个新的 mysql:
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=mysql -p 3306:3306 -d mysql:8
然后在本地启动一个 springboot 项目,配置好 flyway 的配置,然后把 migration 的版本设置为 400,这样就可以把 migration 生成到 400 了:
./gradlew flywayMigrate -Dflyway.target="400"
这里我发现一个奇怪的问题,如果这里 400 这个版本不是一个 sql 而是一个 java 脚本类型的 migration 则会报错,不知道是不是我配置的问题。
mysqldump -u<username> -p<password> db > dump.sql
这里我只保存两部分内容:
我会让 chatgpt 分别给我写两个脚本帮我抽取其中的内容然后贴到我的项目里。
"""
抽取 create table 的 sql
"""
import re
def extract_create_table_statements(dump_file):
create_table_statements = []
create_table_pattern = r'CREATE TABLE.*?;'
with open(dump_file, 'r') as file:
dump_content = file.read()
create_table_matches = re.findall(create_table_pattern, dump_content, re.DOTALL)
for match in create_table_matches:
create_table_statements.append(match.strip())
return create_table_statements
# Example usage
dump_file = 'dump.sql'
create_table_statements = extract_create_table_statements(dump_file)
for statement in create_table_statements:
print(statement)
print()
"""
抽取 insert into 的 sql
"""
import re
def extract_insert_statements(file_path):
with open(file_path, 'r') as file:
dump_data = file.read()
insert_pattern = r'INSERT INTO .*?;'
insert_statements = re.findall(insert_pattern, dump_data, re.DOTALL)
return insert_statements
# Usage example
file_path = 'dump.sql'
insert_statements = extract_insert_statements(file_path)
# Print the extracted insert statements
for statement in insert_statements:
print(statement)
print()
这里记得手工剔除掉 migration 的 table。
这样就结束了。
flyway 会有一个 sql 的校验它会阻止你修改已经做过的 migration。这个机制是为了避免手贱不小心修改了老的 sql 不过我们这里是刻意为之,所以就需要把这个关掉了。
application.yaml
:
spring:
...
flyway:
validate-on-migrate: false
...
前天晚上 k8s 集群出现了问题,一开始是有一台 master 的内存不够了,然后导致了一些 k8s 系统的 pod 跪了,在对 master 节点升级之后开始去重启那些受影响的 crd controller,结果发现这个 crd controller 报错:
看到这个报错我很懵逼:我代码都没改,怎么突然就会报错呢,我启动的 argument list
也不长。连续重启两次发现没有什么效果就又去尝试重启其他的 pod 然后发现其他的 pod 也会报同样的错误...导致了问题的扩大。而且这个 crd controller 还是很重要的组件,它启动不起来由它管理的 crd 就都不能更新了,非常头大。
然后就去网上查资料,发现了一个几乎和我们集群一模一样的问题的帖子:事后分析:Kubernetes Pod 无法启动,因为服务太多 ,总结来说就是因为 k8s 默认会把一个 namespace 的 service 创建一组环境变量,然后把这些环境变量注入到 namespace 所有的 pod 里。service 越多,在 pod 里注入的环境变量就越多。
我们的 bayesjob
crd 里恰好有几个 service 那么所有启动的 pod 里就会默认多非常多的环境变量,然后恰好那天有个用户跑了非常多的 bayesjob
刚好冲破了这个程序启动注入环境变量的上限就引发了这个问题。
SVC_XXXA_TXWGIWBFC37V_PORT_80_TCP_PORT=80
SVC_BAADF_OE3QGDRQF7OX_PORT_6637_TCP_ADDR=10.97.0.126
SVC_ADMIN_VI6RZ95HMNVY_PORT_7088_TCP_ADDR=10.97.8.254
SVC_ADMIN_VI6RZ95HMNVY_SERVICE_PORT=80
SVC_ADMIN_VI6RZ95HMNVY_PORT=tcp://10.97.8.254:80
...
解决的办法就是在 pod 里增加额外的配置:enableServiceLinks: false
告诉 pod 不要主动去注入这些环境变量即可。
之前 bayesjob
的生命周期比较短,并没有遇到这个问题,直到最近调整了它的生命周期(从 72h -> 14d)带来大量存活的 service ,最后在这天又恰好来了一个创建 300+ 任务的用户。这种问题真的是要到一定规模你才能发现的,实现考虑到的难度有点大了。
crd controller 也应该有更好的容错性,不能因为一台 master 出问题就跪了才对,后续要对其进行调整。
最近攒了一台机器作为家里的 NAS,操作系统选择了 TrueNAS Scale ,之所以用这个系统原因有两个:
基本环境准备好了之后把由 5 块 HDD 组成的 RaidZ1 作为了主存储池就开始使用了。用了一段时间发现系统有一个小小的问题:这些 HDD 差不多每几秒就会卡卡响两下,不是什么异常的声音,就是正常的读写的声音,可我当时并没有使用它做什么事情,而且这种有节奏的噪音让我也有点难受。看了下监控,io 模式就是这个样子:
首先我就去 google 了,搜来搜去,用关键词「truenas scale idle read write」找到了 TrueNas Scale constant writes while idle 这个问题,下面的回复基本就就是清楚了原因,我这里简单复述下:
TrueNAS 会默认把你建立的第一个 data pool 设定为 System Dataset 然后会在这里塞日志等乱七八糟的东西,尤其是系统日志这种东西它就会持续的对系统进行写入。
既然 HDD 读写声音很讨厌,那我就还是再加一个 nvme 的盘做成存储池来用吧,幸好我的主板 m.2 的插槽管够。插上 nvme 硬盘并设置一个新的存储池后,通过「System Settings」-「Advanced」-「System Dataset Pool」把它修改成心态添加的 nvme 存储即可。
如果要使用上文提到的 Apps 的话,TrueNAS Scale 也会要求你指定存储的位置,考虑到性能和噪声也要把它指向 nvme 的存储。
所以对于 TrueNAS Scale 来说,最好要准备三个部分的存储: