基本结构
恢复群晖数据盘
Recover Synology
- Recover Synology from AlpineLinux
- btrfs report I/O Error
问题
群晖的盘搞的很复杂
- mdraid -> lvm -> btrfs
只看到 btrfs 报错(I/O Error),无法使用,没看到具体的磁盘错误,只能逐级排查。
主要目的是挂载 btrfs 恢复数据。
操作
file -s /dev/sda1 # linux_raid_member
file -s /dev/sda2 # swap
file -s /dev/sda3 # 发现是用的 mdadm RAID 6
# /dev/sda3: Linux Software RAID version 1.2 (1) UUID= name=DF:2 level=6 disks=4
apk add mdadm
mdadm --examine --scan # 扫描
mdadm --assemble --scan # 添加
cat /proc/mdstat # 状态
file -s /dev/md127 # 发现是 LVM
# /dev/md127: LVM2 PV (Linux Logical Volume Manager), UUID: , size: 11980386729984
挂载 LVM
apk add lvm2
pvscan
# PV /dev/md127 VG vg1 lvm2 [<10.90 TiB / 604.00 MiB free]
vgscan
# Found volume group "vg1" using metadata type lvm2
lvdisplay
lvs
# /dev/vg1/syno_vg_reserved_area
# /dev/vg1/volume_1
vgchange -ay vg1 # 激活 vg1
file -s /dev/vg1/volume_1 # -> /dev/mapper/vg1-volume_1
file -s /dev/mapper/vg1-volume_1
# /dev/mapper/vg1-volume_1: BTRFS Filesystem label "2022.12.04-17:42:08 v42661", sectorsize 4096, nodesize 16384, leafsize 16384, UUID=, 151894196224/11979737530368 bytes used, 1 devices
挂载 btrfs
apk add btrfs-progs btrfs-progs-extra
modprobe btrfs
btrfs device scan
btrfs filesystem show
btrfs check /dev/mapper/vg1-volume_1 # 尝试检测
ERROR: errors found in fs roots
found 151884984320 bytes used, error(s) found
total csum bytes: 2896392
total tree bytes: 127860736
total fs tree bytes: 99958784
total extent tree bytes: 15761408
btree space waste bytes: 25632487
file data blocks allocated: 103613448192
referenced 103061467136
- 发现不少问题
mount /dev/mapper/vg1-volume_1 /mnt # 尝试挂载
# wrong fs type, bad option, bad superblock on /dev/mapper/vg1-volume_1
dmesg # 内核日志找原因
# BTRFS critical (device dm-1): corrupt leaf
mount -t btrfs -o recovery,ro /dev/mapper/vg1-volume_1 /mnt
btrfs check /dev/mapper/vg1-volume_1 --repair # 尝试修复,但是失败
# ERROR: failed to repair root items: I/O error
btrfs scrub start -Bf /dev/mapper/vg1-volume_1
# btrfs rescue zero-log /dev/<device_name>
- smartctl 尝试检测硬盘问题
- mdadm 尝试 resync
无解, TODO
/dev/mapper/cachedev_0 on /volume1 type btrfs (rw,nodev,relatime,ssd,synoacl,space_cache=v2,auto_reclaim_space,metadata_ratio=50,block_group_cache_tree,subvolid=256,subvol=/@syno)
wrong fs type, bad option, bad superblock on /dev/mapper/vg1-volume_1
mount -t btrfs /dev/mapper/vg1-volume_1 /mnt
BTRFS: device label 2022.12.04-17:42:08 v42661 devid 1 transid 449145 /dev/mapper/vg1-volume_1 scanned by mount (4067)
BTRFS info (device dm-1): using crc32c (crc32c-intel) checksum algorithm
BTRFS info (device dm-1): using free space tree
BTRFS critical (device dm-1): corrupt leaf: root=1 block=668844032 slot=1, invalid root flags, have 0x400000000 expect mask 0x1000000000001
BTRFS error (device dm-1): read time tree block corruption detected on logical 668844032 mirror 1
BTRFS critical (device dm-1): corrupt leaf: root=1 block=668844032 slot=1, invalid root flags, have 0x400000000 expect mask 0x1000000000001
BTRFS error (device dm-1): read time tree block corruption detected on logical 668844032 mirror 2
BTRFS error (device dm-1): open_ctree failed
btrfs check /dev/mapper/vg1-volume_1 --repair
ERROR: failed to repair root items: I/O error
S.M.A.T Check
apk add smartmontools
smartctl -t long /dev/sda
smartctl -t long /dev/sdb
smartctl -t long /dev/sdc
smartctl -t long /dev/sdd
# 很慢
smartctl -l selftest /dev/sda
smartctl -l selftest /dev/sdb
smartctl -l selftest /dev/sdc
smartctl -l selftest /dev/sdd
smartctl -a /dev/sda
LVM Check
vgck vg1 -v
pvck /dev/md127
mdadm check
4*10T SAS 需要跑 8h, iostat -> ~200MB/s
mdadm --detail /dev/md127
mdadm --action=check /dev/md127
# 查看有问题的块
watch cat /sys/block/md127/md/mismatch_cnt
# 查看进度
cat /proc/mdstat
cat /sys/block/md127/md/sync_action
md127: mismatch sector in range 713232-713240
echo idle > /sys/block/md127/md/sync_action # 停止 check
mdadm --action=repair /dev/md127 # 尝试修复 - repair=resync
iostat -h # write 是有修复
# K/Sec
cat /proc/sys/dev/raid/speed_limit_max
sysctl dev.raid.speed_limit_max # 200000
sysctl dev.raid.speed_limit_max=2000000
# 不是平滑限速,而是平均 - 因此 resync 一会儿满速,一会儿 0
sysctl dev.raid.speed_limit_max=100000 # 如果觉得修复了问题,可以降低速度,然后尝试系统操作
BTRFS critical (device dm-1): corrupt leaf
BTRFS error (device dm-1): read time tree block corruption detected on logical 668844032 mirror 2
BTRFS critical (device dm-1): corrupt leaf: root=1 block=668844032 slot=1, invalid root flags, have 0x400000000 expect mask 0x1000000000001
BTRFS error (device dm-1): read time tree block corruption detected on logical 668844032 mirror 1
BTRFS critical (device dm-1): corrupt leaf: root=1 block=668844032 slot=1, invalid root flags, have 0x400000000 expect mask 0x1000000000001
BTRFS error (device dm-1): read time tree block corruption detected on logical 668844032 mirror 2
BTRFS error (device dm-1): open_ctree failed
btrfs check /dev/mapper/vg1-volume_1 --repair
[1/7] checking root items
checksum verify failed on 711114752 wanted 0xed010ef2 found 0xb32e10d9
checksum verify failed on 711114752 wanted 0xed010ef2 found 0x3a406fa5
checksum verify failed on 711114752 wanted 0xed010ef2 found 0xb32e10d9
Csum didn't match
ERROR: failed to repair root items: I/O error
BTRFS: device label 2022.12.04-17:42:08 v42661 devid 1 transid 449145 /dev/mapper/vg1-volume_1 scanned by btrfs (22854)
btrfs backup
apk add partclone
#btrfstune -u /dev/mapper/vg1-volume_1
https://manpages.debian.org/jessie/partclone/partclone.btrfs.8
noerror: Instructs dd to continue operation, ignoring all read errors sync: Instruct dd to fill input blocks with zeroes if there were any read errors
dd if=/dev/sda of=/dev/sdb1 bs=1MB conv=noerror,sync status=progress | gzip -c > backup.img.gz gunzip -c /PATH/TO/DRIVE/backup_image.img.gz | dd of=/dev/sda
LV Status NOT available
是因为没有 active
vgchange -ay vg1
WARNING: PV /dev/md127 in VG vg1 is using an old PV header, modify the VG to update.
不管
File descriptor 63 (pipe: 111755) leaked on pvck invocation.
LVM_SUPPRESS_FD_WARNINGS=1 vgck vg1
参考
- btrfs.8
- btrfs-check.8
- vgchange.8
- vgck.8
- md.4
- mdadm.8
- BTRFS: failed to read log tree
btrfs rescue zero-log /dev/<devicename>
- https://www.suse.com/support/kb/doc/?id=000018761
- https://www.cyberciti.biz/tips/linux-raid-increase-resync-rebuild-speed.html
clean up
apk del mdadm lvm2 btrfs-progs btrfs-progs-extra
迁移阿里云 CDN 到 Cloudflare
每月节省 30¥ 阿里云全站 CDN 流量费用。
CRM 实现经历
v1
- 后端 - Java - 2019.11 - 2021.1
- 前端 - NextJS v9 + Antd - 2019.11 - 2021.3
- @reduxjs/toolkit
非常简单的尝试,很快就失败了,目标并不明确。 对 CRM 并不了解,过于盲目。 堆砌了一些基础前端组件。前端开发能力尚不成熟。
v2
- 2020.1 - 2020.6
- 后端 - Node - nestjs
- nestjs
- objection - ORM
- swagger
- 前端 - Antd v4+NextJS v9
- react-final-form
- redux
- tinacms
后端
后端尝试构建基于 Schema 的 CRM,但过于动态,过于灵活导致逻辑开发复杂。 对 NodeJS 后端开发并不足够了解,目标更像是一个 low-code 后端,但是支持 CRM 实体。 这个阶段对 CRM 逻辑有了一些了解。
- 需要的是 先 CRM 再 low-code
- 核心逻辑是确定的才能更好开发业务 - 不然要做太多假设
- NodeJS 容器真的很大
- 确定了要走 Schema 的方式 - 前端通过 Schema 做更多的事情
前端
前端选择 Antd,发现阻力越来越大,实现定制化很难。 这时的前端开发能力还相对欠缺,对生态还不够了解。
- 探索了前端想要达成的目标 - 窗口、多 Tab
- 不要选择 antd 这种过于全面无法定制的组件库
v3
- 后端 - Go - 2020.11 - 2022.7
- gorm + restful - 前期
- ent + gqlgen - 中期
- gorm - 非核心 CRM 业务
- 前端 - 2020.11 - 2022.1
- NextJS
- BlueprintJS - 前期
- graphql-codegen
- urql - GraphQL
- TailwindCSS - 后期
- zustand - 后期
- react-hook-form
这个阶段是历时最长的,除了核心的 CRM 还完成了其他的一些附属模块。
后端
后端使用 Golang 开发上进行了一些探索,前期 gorm+restful 方式代码量大且重复。 之后选择 ent+gqlgen+自定义生成代码。
- GraphQL 对前端非常友好 - 但选择了先 GraphQL 而非先 GRPC 是比较失误的
- 基于 ent 实现自定义生成逻辑
- 生成了 schema - 但非标准 jsonschema - 且长期未从后端拉而是直接放在了前端
- 改动困难
- 自定义 schema 前期用起来爽,后期维护困难 - 记忆层面和熟悉度层面
- 生成了 graphql 的 golang resolver 代码 - 通过解析 AST 的方式植入
- 生成逻辑过于依赖 ent,改动维护困难
- 生成 golang resolver 逻辑维护困难
- 生成了 schema - 但非标准 jsonschema - 且长期未从后端拉而是直接放在了前端
- ent 生成过多的东西 - 代码库冗余
- ent 升级有风险
- 生成逻辑不兼容 - 主要问题 - 不敢随意升级 - 开发阻碍
- 自身不兼容
- 确定了要先 GRPC 的方式开发
- 基于多 DB 后端的多租户逻辑不好维护
- 优先设计的 On-Prime 模式,未考虑 SaaS,后期尝到了苦头
前端
前期基于 Blueprint 快速实现大多功能,但还是因为经验不足,很多东西实现有缺陷。但实现了初期原型,达到了想要的结果。
- Blueprint 提供 CSS 直接使用,非常方便 - 侵入性远远小于 Antd
- Blueprint 升级需要改动所有的 CSS 前缀 - ⚠️
- 后期选择 Tailwind 开发
- 组件传递、自定义经验欠缺 - 做了很多不好维护的扩展
- 基础 Schema 不标准 - 很多东西基于不标准的 schema 开发后结果是往更不好的方向发展
- 优先考虑了用户使用而非管理使用,导致所有管理维护开通都需要人为 - 不可持续
- 期望中的模块化一直未实现
v4
- 2022.6 ->
- 后端
- 确定了要优先 GRPC,且使用标准 Schema。
- 因此将 protobuf 的定义作为 Single-Source—Of—Truth Schema。
- 分离接口 Schema 和 DB - 之前是 ent schema -> graphql schema
- 虽然选择 GRPC 但也要直接能给前端访问
- 选择了 connect 协议
- 实现了 connect-gateway
- 实现了基于 Redis 服务发现
- 实现了基于 grpc reflection 自动暴露服务
- DB 确定不要通过 ORM 自动维护而是手动维护
- 实现基于 PG RLS 的多租户逻辑而非多 DB 模式
- 实现 CRM 时 DB Schema 的重要性等同接口
- 业务沉淀为数据库模型
- 也因此分离 API 模型和数据库模型
- Golang -> NodeJS
- 初期尝试用 Golang 实现
- 核心问题 ⚠️
- 开发一段 前端再回到 Golang 会 痛不欲生 - 上下文切换、开发思路切换
- Golang 生成代码只能静态生成,NodeJS 可以动态生成
- NodeJS 更加灵活 - PoC 阶段更有优势
- 使用 NodeJS 可以和前端在同一个仓库 - 核心逻辑开发维护更容易
- NodeJS
- fastify+jsonschema+sequelize
- 通过 grpc 生成 descriptor, definitoon
- 启动后通过 descriptor 生成 jsonschema
- 通过 jsonschema+definitoon 生成 grpc-service - nice-grpc
- 实现标准的 CRUD 语义
- fastify POST -> grpc 实现 - 类似 connect 语义
- grpc-server -> grpc 实现
- 未来: web -> connect-gateway -> grpc-server -> grpc 实现
- 确定了要优先 GRPC,且使用标准 Schema。
- 前端
- daisyui+tailwindcss
- 不再直接选择成熟的 UI 框架,而是选择基于 CSS 的样式库
- daisyui 提供了一套命名 class 的方式 - 有 Theme
- 确定 管理功能优先于用户功能
- 确定 功能能被看到才算开发完成
- 模块化
- 仍在尝试中 - 借鉴其他实现
- 提供开放的 OSS 存储
- 目前明确方向
- 分离 os 逻辑和核心 route 逻辑 - 揉在一起困难
大师之路
幼儿园小朋友的画和自由派名画师的话没什么区别,小学生作文和名作家的文章也没什么区别。它们在形式和内容上都是差不多的。
2022上海封城日记
封控自 2022-03-16 解封于 2022-06-01 共封控 77 天
企业建站的基本前提考量
基本功能
- 文章编辑
- 用户联系表单提交
- 静态 - 利于 SEO
考虑
- 是否需要自有域名
- 没有自有域名可用平台提供的
- 域名是必须的
- 是否需要 HTTPS 证书
- 可提供免费证书 - 涉及运维
- 可买 - 云平台购买,需要定期更新维护
- 是否需要备案
- 未备案微信无法直接打开
- 最简单的备案需要挂云服务商 - 服务器
- 使用平台提供的域名可避免备案
- 托管或自行提供服务器
- 托管 - 平台提供服务器资源 - 使用平台带宽
- 自行提供服务器 - 需要维护、定时付费
- 一般免费 1mb 带宽(图片多会非常慢)
Love the World
深切的爱着这个美好的世界,因此更深切的恨着让这个世界肮脏的东西。
数据同步模式
A 同步到 B
DBA -> A -> B -> DBB
Extract -> Load
Extract -Transform-> Load
组建你自己的 NAS 服务器
组建 NAS 需要考虑的因素和建议。