前言
感谢崖山数据库(YashanDB)邀请我参与数据沙箱的首批内测。作为"尝鲜官"之一,我带着期待领取了测试包,准备好好体验一下这个号称"秒级创建、随意回滚、多分支不打架"的数据沙箱功能。
第一次接触崖山数据库,整个过程有惊喜也有坎坷,我花了大概 1 小时完成从零部署到全部功能测试。本文既是我的真实测试记录,也是一份来自一线 DBA 的坦诚反馈——希望对崖山团队和同行们都有参考价值。
一、先说结论:数据沙箱能力令人印象深刻
先把结论放在前面:YashanDB 数据沙箱的核心能力值得肯定,三个测试任务全部跑通,体验远超预期。
数据沙箱(Data Sandbox)的概念在数据库领域并不是全新的——类似于 Neon 等产品的 Branching 能力,但崖山把它落地在了国产数据库上,这本身就是一件值得点赞的事。作为一个 DBA,我对这类"让数据管理更灵活"的能力一直很关注,而崖山的实现确实给了我不少惊喜。
三个核心任务我都跑通了,下面展开说说实际体验。
任务1:分支生命周期管理 — 丝滑
全流程操作包括创建、切换、查看、冻结、激活、删除,一步到位,非常丝滑。
-- 创建分支
EXEC DBMS_BRANCH.CREATE('test_01', 'BRANCH$TEMPLATE');
-- 查看分支列表
SQL> SELECT DBMS_BRANCH.LIST() FROM dual;
+---------------------------------------------------------------------------------+
| BRANCH_NAME | STATUS | PARENT_NAME | CREATED_AT |
+---------------------------------------------------------------------------------+
| BRANCH$TEMPLATE | FROZEN | | 2026-05-30 13:58:49 |
| MASTER | ACTIVE | BRANCH$TEMPLATE | 2026-05-30 13:59:25 |
| TEST_01 | ACTIVE | BRANCH$TEMPLATE | 2026-05-30 14:16:21 |
+---------------------------------------------------------------------------------+
-- 切换到新分支
SQL> EXEC DBMS_BRANCH.CHECKOUT('test_01');
Succeed.
-- 两种查看当前分支的方式
SQL> show branch;
BRANCH
----------------------------------------------------------------
TEST_01
SQL> SELECT DBMS_BRANCH.CURRENT() FROM dual;
DBMS_BRANCH.CURRENT()
----------------------------------------------------------------
TEST_01
-- 切回 master
SQL> EXEC DBMS_BRANCH.CHECKOUT('master');
Succeed.
-- 冻结test分支
SQL> EXEC DBMS_BRANCH.FREEZE('test_01');
PL/SQL Succeed.
-- 激活test分支
SQL> EXEC DBMS_BRANCH.ACTIVATE('test_01');
PL/SQL Succeed.
-- 删除test分支
SQL> EXEC DBMS_BRANCH.DELETE('test_01');
PL/SQL Succeed.
体验上有几个亮点:
- 速度极快:分支创建和切换几乎是瞬时的,完全感受不到传统克隆实例那种等待感。不管数据量多大,这个速度是否还能保持,值得进一步验证,但目前的体验非常好。
- 信息展示直观:
DBMS_BRANCH.LIST()以表格形式展示分支列表,BRANCH_NAME、STATUS、PARENT_NAME、CREATED_AT一目了然,设计得很贴心。
此外还支持 SHOW BRANCH 和 SELECT DBMS_BRANCH.CURRENT() 两种方式查看当前分支,充分考虑了不同用户的使用习惯,这个细节点赞。
任务2:数据时间漫游 — “时光机”
这个功能让我印象深刻,有点类似 Oracle 的闪回(Flashback),但体验更轻量、更直观。
-- 创建并切换到测试分支
SQL> EXEC DBMS_BRANCH.CREATE('test_02', 'BRANCH$TEMPLATE');
SQL> EXEC DBMS_BRANCH.CHECKOUT('test_02');
SQL> SHOW BRANCH;
BRANCH
----------------------------------------------------------------
TEST_02
-- 建表、插数据
SQL> CREATE TABLE AAA (id NUMBER, name VARCHAR2(50));
SQL> INSERT INTO AAA VALUES (1, 'haha');
SQL> COMMIT;
-- 记录当前时间
SQL> SELECT SYSTIMESTAMP FROM DUAL;
SYSTIMESTAMP
----------------------------------------------------------------
2026-05-30 18:49:58.378073 +08:00
然后我等了一段时间(实际是从傍晚等到凌晨),再回来执行:
SQL> SELECT SYSTIMESTAMP FROM DUAL;
SYSTIMESTAMP
----------------------------------------------------------------
2026-05-31 01:41:59.166817 +08:00
-- 删表!
SQL> DROP TABLE AAA;
SQL> select * from AAA;
[1:15]YAS-02012 table or view does not exist
-- 一键恢复到删表之前的时间点
SQL> EXEC DBMS_BRANCH.RESTORE('2026-05-30 18:50:00');
Succeed.
-- 数据回来了!
SQL> select * from AAA;
ID NAME
----------- -----------------------------------------------------
1 haha
表没了,一键恢复,数据完整回来。
这个能力对于开发测试环境来说太实用了——开发人员可以放心大胆地做各种实验,不怕搞砸;DBA 也不用再为误操作恢复大动干戈。从傍晚到凌晨跨了好几个小时的数据变化,一条命令就回去了,效率很高。
时间参数格式也设计得很友好,直接用 YYYY-MM-DD HH:MI:SS 这种人类可读的格式,不需要转成 ISO 8601 什么的,上手零成本。
任务3:分支并行与隔离 — 互不干扰
我同时创建了两个分支,验证数据隔离:
-- 在 master 上建表
SQL> CREATE TABLE ABC (id NUMBER, name VARCHAR2(50));
SQL> INSERT INTO ABC VALUES (1, 'haha');
SQL> COMMIT;
-- 创建两个并行分支
SQL> EXEC DBMS_BRANCH.CREATE('test_03', 'BRANCH$TEMPLATE');
SQL> EXEC DBMS_BRANCH.CREATE('test_04', 'BRANCH$TEMPLATE');
-- 在 test_03 上建自己的表
SQL> EXEC DBMS_BRANCH.CHECKOUT('test_03');
SQL> SHOW BRANCH;
BRANCH
----------------------------------------------------------------
TEST_03
SQL> create table AAA03 (id number,name varchar2(50));
SQL> insert into AAA03 values (1,'AAA03');
SQL> commit;
SQL> select * from AAA03;
ID NAME
----------- -----------------------------------------------------
1 AAA03
-- 切到 test_04,看不到 test_03 的表
SQL> EXEC DBMS_BRANCH.CHECKOUT('test_04');
SQL> show branch;
BRANCH
----------------------------------------------------------------
TEST_04
SQL> select * from AAA03;
[1:15]YAS-02012 table or view does not exist
-- 切回 test_03,数据还在
SQL> EXEC DBMS_BRANCH.CHECKOUT('test_03');
SQL> select * from AAA03;
ID NAME
----------- -----------------------------------------------------
1 AAA03
多个分支之间数据完全隔离,来回切换后各自数据互不干扰。对于并行开发、多人同时测试的场景,这个能力非常实用。
额外探索:磁盘动态扩容
在测试过程中,我还尝试了通过 yfscmd 动态添加磁盘到磁盘组:
sudo dd if=/dev/zero of=/home/yashan/yfs_data2.img bs=1M count=2048
sudo losetup /dev/loop2 /home/yashan/yfs_data2.img
sudo ln -sf /dev/loop2 /dev/yfs/data2
sudo chown yashan:yashan /dev/loop2 /dev/yfs/data2
yfscmd -D /data/yashandb/yasdb_data/ycs/ce-1-1 exec \
"ALTER DISKGROUP DG0 ADD DISK '/dev/yfs/data2' FORCE"
在线扩容,不需要停机,操作也比较直观。YashanDB 在存储管理层面的灵活性值得肯定。
二、部署过程的一些坎坷
核心能力体验完了,再聊聊"走到这一步"的过程中遇到的一些小插曲。这里把遇到的问题记录下来,既是给自己备忘,也希望能帮到后续参与内测的同行。
1. 裸盘需求:环境准备是第一道门槛
文档要求:
--data和--system-data指定的目录必须是裸磁盘,不挂载任何文件系统。
对于内测体验来说,这个要求可以理解——沙箱底层依赖 YFS 存储引擎,裸盘是架构设计决定的。但文档只写了"裸磁盘可以通过虚拟化方式创建"一笔带过,没有给出具体操作步骤。
我的做法是用 dd + losetup 模拟裸盘,这样在内测场景下更轻量:
# 创建 yashan 用户并配置 sudo
useradd -d /home/yashan -m yashan
passwd yashan
echo "yashan ALL=(ALL) ALL" >> /etc/sudoers
# 创建镜像文件模拟裸盘(各 4GB)
dd if=/dev/zero of=/home/yashan/yfs_system.img bs=1M count=4096
dd if=/dev/zero of=/home/yashan/yfs_data.img bs=1M count=4096
# 绑定 loop 设备
sudo losetup /dev/loop0 /home/yashan/yfs_system.img
sudo losetup /dev/loop1 /home/yashan/yfs_data.img
# 创建软链接让安装程序识别
sudo mkdir -p /dev/yfs
sudo ln -sf /dev/loop0 /dev/yfs/system
sudo ln -sf /dev/loop1 /dev/yfs/data
sudo chown -R yashan:yashan /dev/yfs
sudo chown yashan:yashan /dev/loop0 /dev/loop1
之后创建安装目录、上传安装包、解压:
sudo mkdir -p /data/yashan
sudo chown -R yashan:yashan /data
sudo chown -R yashan:yashan /home/yashan/install
cd /home/yashan/install
tar -zxf yashandb-23.6.0.1-linux-x86_64.tar.gz -C /data/
建议: 如果官方能在部署说明中补充裸盘模拟的完整步骤,或者提供一个 init_env.sh 一键初始化脚本,新用户的上手体验会好很多。
2. 一些小坑:端口占用与密码校验
环境准备好后,按照官方文档执行部署:
cd /data
bin/yasboot package ce gen \
--cluster yashan -u yashan -p yashan --ip 127.0.0.1 --port 22 \
--install-path /data/yashandb --begin-port 1688 \
--data /dev/yfs/data \
--system-data /dev/yfs/system \
--disk-found-path /dev/yfs \
--node 1 -f --enable-branch
这一步比较顺利。但 yasboot package install 阶段因为之前尝试部署过一次,端口被占用导致失败。我摸索出来需要在安装前清理残留进程:
sudo kill -9 $(ps aux | grep -E 'yasom|yasagent' | grep -v grep | awk '{print $2}')
另外,部署时密码有复杂度要求——我一开始用了简单密码,部署到一半报错不得不重头来过。重装的清理流程是我自己摸索的:
rm -rf /home/yashan/.yasboot
rm -rf /data
ps -ef | grep yashan # 找到残留进程
kill -9 <pid> # 杀掉
建议: 部署文档如果能补充密码复杂度要求和重装清理步骤,可以帮用户少走不少弯路。
最终部署成功:
bin/yasboot cluster deploy -t yashan.toml -p Cod-2022 --yfs-force-create -d
| task | ... | DeployYasdbCluster | ... | SUCCESS | 0 | 100 | 57 |
| child | ... | DeployDBBranch | ... | SUCCESS | 0 | 100 | 57 |
57 秒完成部署,集群状态正常,这个速度值得点赞。
3. 功能体验中的小插曲
进入 yasql 后,按照官方内测指南的示例操作,遇到了两个小问题:
EXEC 关键字缺失: 官方示例写的是:
DBMS_BRANCH.CREATE('test_01');
但实际在 yasql 中需要加 EXEC:
EXEC DBMS_BRANCH.CREATE('test_01', 'BRANCH$TEMPLATE');
另外,CREATE 接口实际需要两个参数(分支名 + parent branch),官方示例只写了一个。
任务描述偏简洁: 以"数据时间漫游"为例,官方只给了几行零散的代码片段。实际操作需要完整链路:创建分支→建表→插数据→记录时间戳→等待→删表→恢复到之前的时间点→验证数据。中间"记录时间戳"这一步很关键,但文档没提。时间参数格式也没有明确说明,我试了几次才确认是 YYYY-MM-DD HH:MI:SS 格式。
建议: 内测指南如果能提供端到端的操作剧本——每一步有命令、有预期输出、有前后上下文,新用户的体验会更顺畅。文档里的每一行代码也建议经过实际验证,确保可以直接复制执行。
三、写在最后
再次感谢崖山数据库给我这次内测机会。
这次体验下来,YashanDB 数据沙箱给我留下的整体印象是:能力扎实,方向正确,值得持续关注。
分支管理秒级完成、数据恢复一键搞定、多分支数据完全隔离——这三个核心能力对于开发测试、误操作恢复、并行实验等场景都有很高的实用价值。再加上在线磁盘扩容、YFS 存储引擎的灵活性,可以看出崖山在数据库技术创新上的投入和决心。
同时,作为一个真诚的内测参与者,我也希望崖山能在文档和体验上持续打磨。一个好产品,不只是功能好用,更要让用户能轻松地用上。部署文档和内测方案就是产品体验的第一道门——把这道门修得宽敞明亮,更多 DBA 才能走进来,看到门里面的风景。
降低门槛,才是最好的增长策略。
期待崖山数据库越来越好。




