-
Windows操作系统自带ODBC数据源管理器,无需用户手动安装管理器便可直接进行配置。操作步骤步骤一 下载客户端GaussDB驱动程序并进行安装:下载地址:cid:link_0在本地(例如D:/download)下载ZIP文件后进行解压缩,解压缩后文件如下。由于本实验openGauss安装在ECS(openEuler ARM)上,所以进入Euler2.8_arm_64文件夹,显示如下:解压缩GaussDB-Kernel-V500R001C10-Windows-Odbc.tar.gz文件,显示如下:点击psqlodbc_x86.msi进行安装:默认设置,直到安装完毕。步骤二 打开驱动管理器。在配置数据源时,请使用对应的驱动管理器(假设操作系统安装盘符为C盘,如果是其他盘符,请对路径做相应修改):64位操作系统上进行64位程序开发,安装64位驱动程序后,使用64位的驱动管理器:C:\Windows\System32\odbcad32.exe 或者直接使用“控制面板 > 管理工具 > ODBC 数据源(64 位)。步骤三 配置数据源。在打开的驱动管理器上,选择“用户DSN > 添加 > PostgreSQL Unicode(x64)”,然后进行配置:Data Source:openGauss (数据源名称,可以自定义)。Database:db_tpcc (需要连接的Datebase名称)。Server:openGauss数据库服务器的公网IP,请根据实际情况填写。Pot:26000 (端口号)。User Name:joe (连接数据库的用户名,不能使用omm用户,需要在数据库中创建)Password:dbuser用户的密码,请根据实际情况填写。步骤四 验证并保存设置。点击Test,显示 Connection successful 表示设置成功:点击保存:配置成功!
-
open gauss数据库和华为云mysql数据库区别
-
数据库论坛10月份热门问题合集云数据库有哪些优点特点?cid:link_0相比自建数据库,云数据库在机房风火水电网络等基础设施方面、服务器部署及维护、数据库软件安装、数据库软件版本升级和补丁等云数据库相比自建数据库在机房、电力、空调、网络等基础设施方面节省了很多的人力、硬件、维护服务成本,尤其对于中小型企业,没有足够的财力和技术基础建设专业的机房网络等环境,则很容易导致各种各样让人抓狂的问题,比如机房所在的大楼动辄断电停电、空调停摆、UPS故障,总是让人心里慌慌,睡觉不踏实,更有时候会出现老鼠窜进去咬断网线之类的让人匪夷所思的事情,导致整个IT环境的不稳定。往往在这些不太起眼细节上的一个疏忽,会消耗掉管理维护人员的很多时间精力,甚至导致业务中断等故障。高斯数据库相比普通的数据库有什么优点?cid:link_1高性能:高斯数据库采用了自主设计的高性能存储引擎,具备快速的数据读写能力,能够处理大规模数据并发访问的场景。高可靠性:高斯数据库支持主备容灾机制,数据备份与恢复以及故障切换等功能,能够提供可靠的数据保护与高可用性。数据安全:高斯数据库采用了多层次的数据安全措施,包括权限管理、数据加密、审计日志等功能,保护数据的安全性和完整性。可扩展性:高斯数据库支持分布式架构,可以通过增加节点实现水平扩展,适应数据量和用户数的快速增长。数据库连接方面出现问题,目前还不知道如何解决,与delphi链接总是超时cid:link_2代码哪里写错了。我用python和java试过,链接完全没有问题交换数据空间EDS是如何实现可信、可控功能的?cid:link_3交换数据空间(Encrypted Data Space,EDS)是一种用于保护数据隐私的技术,它通过加密和分割数据,实现了可信和可控的功能。下面是关于EDS如何实现这些功能的一般原理:加密保护:EDS使用加密算法对数据进行加密,确保数据在传输和存储过程中的安全性。加密可以防止未经授权的访问者获取敏感信息,即使数据被盗或泄露,也无法直接访问其内容。数据分割:EDS将数据分割成多个部分,并将这些部分分散存储在不同的位置。这种分割和分散存储的方式可以减少数据泄露的风险,即使某个部分的数据被获取,也无法还原出完整的数据。访问控制:EDS采用访问控制机制来管理数据的访问权限。只有经过授权的用户或实体才能够解密和访问数据。这种控制机制可以确保只有合法的用户可以访问数据,提高了数据的可信度。审计和监控:EDS提供审计和监控功能,可以记录数据的访问记录和操作日志。这样可以对数据的使用情况进行监控和审计,发现异常行为或违规操作,并及时采取相应的措施。【鲲鹏服务器】【编译安装mysql】【openEuler】【openssl】编译安装mysql报错cid:link_4指定 OpenSSL 路径:如果已经安装了 OpenSSL,但编译过程仍然找不到相关库或头文件,可以通过指定 OpenSSL 的路径来解决。在运行 configure 脚本时,使用 --with-openssl= 参数指定 OpenSSL 路径。例如:./configure --with-openssl=/usr/local/openssl其中 是 OpenSSL 的安装路径。国产神通数据库ENCRYPT_ORA加密函数如何用Java代码实现cid:link_5Java Cryptography Architecture (JCA) 是一组 API,用于实现现代密码学的概念,例如数字签名、消息摘要、证书、加密、密钥生成和管理、安全随机数生成等。使用 JCA 开发人员可以通过以下方式构建他们的应用程序将安全性融入其中。要在您的应用程序中集成安全性,而不是依赖于复杂的安全算法,您可以轻松调用 JCA 中提供的相应 API 来获取所需的服务。创建分区表时,分区键需要是generated always的生成列,执行报错,请问oracle可以,到gaussDB的话,该如何处理?cid:link_6在GaussDB for openGauss中,分区表的分区键可以是generated always的生成列。然而,对于某些特定情况,由于openGauss版本的差异,可能会导致从Oracle迁移到openGauss时遇到一些兼容性问题。如果您在创建分区表时遇到了报错,请确保按照openGauss的语法和规范进行操作。以下是一些处理方法和注意事项:确认openGauss版本:不同版本的openGauss可能有略微不同的语法和支持特性。请确保您正在使用最新版本,并参考相应版本的文档。检查数据类型和语法差异:数据库系统之间存在数据类型和语法差异的情况,例如数据类型名称、函数用法等。在迁移过程中,请检查并调整相关代码以符合openGauss的语法规范。检查限制和约束:openGauss中有一些与分区表相关的限制和约束,例如每个分区表的最大分区数、生成列的限制等。请确保您的表定义符合这些限制。考虑手动处理:如果无法直接将Oracle的创建表语句转换为openGauss的语法,请考虑手动重建表结构并添加分区键。这样可以更好地适应openGauss的语法和规范要求。Gauss DB 查询数据库全量表的行信息问题cid:link_7use information_schema; select sum(table_rows) from tables where TABLE_SCHEMA = "test" order by table_rows asc;鲲鹏架构默认的char是有符号还是无符号呢?鲲鹏的问题有专门的渠道进行支持,欢迎到昇腾新论坛发帖进行求助~鲲鹏新论坛地址:cid:link_11解锁新论坛:在新论坛中发帖需要大家先注册账号,建议大家新账号的昵称与老账号一致哦!欢迎大家多多提问和分享技术干货,感谢大家支持和谅解。鲲鹏论坛迁移公告:cid:link_8大二电子信息工程专业在鲲鹏华为云数据库上有啥推荐的学习路径吗cid:link_9数据库学习路线,cid:link_10
-
问题背景测试环境后台开启log_min_duration_statement为3s抓取慢sql时(版本低没开topsql),突然发现后台日志有条sql语句执行了65s,业务sql语句一般执行时间很短,这个不正常,得拿出来看下了. 计划见下图-----(**表名,字段和值已自定义化**)排查思路从计划可以看出为明显的nested loop导致的慢 1.计划选择nested loop的原因为where后面的条件为not in 2.此计划慢的原因为not in里面的语句过滤后的数据量太大,且无法走索引(year条件过滤性太差吧,我怀疑表里面一半值都是这个)。解决方案:从上面分析可知慢的原因,就好下手去优化了。 首先去掉nested loop,改为hash join方式 以下为改下后的语句和计划从计划可以看到改写后的语句走的是hash join的方式,且总体执行代价从38万降到8万,执行时间也从65s下降到1s。问题思考:1.为啥数据库会选择nested loop计划 对于非等值条件数据库无法走hash join 2.是不是hash join一定比nest loop快? 对于被驱动表,如果存在索引的场景下,且整体过滤后的结果很少,走nested loop往往会优于hash join。 本问题语句被驱动表查询结果集很大,且无法走索引,因此nested loop计划就会很慢。
-
大二电子信息工程专业在鲲鹏华为云数据库上有啥推荐的学习路径吗
-
高斯数据库相比普通的数据库有什么优点?
-
mybatis缓存之一级缓存一级缓存的产生一级缓存的产生,并不是看mappper的xml文件的select方法,看下面的例子mapper.xml <select id="getById" resultType="entity.TempEntity"> select * from temp where id = #{id} </select>test @Test public void testSelectAsUpdate() throws IOException { InputStream inputStream = Resources.getResourceAsStream("mybatis.xml"); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = build.openSession(); sqlSession.update("dao.Temp03Dao.getById", 1); sqlSession.update("dao.Temp03Dao.getById", 1); }执行结果2020-06-26 17:33:27,899 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:33:27,922 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:33:27,923 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:33:27,923 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer)我们可以看到执行了2次查询。说明并没有产生缓存。说明和sqlsession调用的方法是有关系的只有调用上图中的方法才会产生一级缓存一级缓存的销毁1.关闭session这个是根据debug看到的一级缓存的最终结构。下面是整个依赖的类图test @Test public void test() throws IOException, NoSuchFieldException, IllegalAccessException { InputStream inputStream = Resources.getResourceAsStream("mybatis.xml"); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = build.openSession(); TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity1); Field executorField = sqlSession.getClass().getDeclaredField("executor"); executorField.setAccessible(true); CachingExecutor cachingExecutor = (CachingExecutor) executorField.get(sqlSession); Field declaredField = cachingExecutor.getClass().getDeclaredField("delegate"); declaredField.setAccessible(true); SimpleExecutor simpleExecutor = (SimpleExecutor) declaredField.get(cachingExecutor); Field localCacheField = simpleExecutor.getClass().getSuperclass().getDeclaredField("localCache"); localCacheField.setAccessible(true); PerpetualCache perpetualCache = (PerpetualCache) localCacheField.get(simpleExecutor); Field cacheField = perpetualCache.getClass().getDeclaredField("cache"); cacheField.setAccessible(true); Map<Object,Object> map= (Map<Object, Object>) cacheField.get(perpetualCache); logger.info("缓存关闭前"); for (Map.Entry<Object,Object> objectObjectEntry:map.entrySet()){ logger.info(objectObjectEntry.getKey() + "===" + objectObjectEntry.getValue()); } sqlSession.close(); logger.info("缓存关闭后"); for (Map.Entry<Object,Object> objectObjectEntry:map.entrySet()){ logger.info(objectObjectEntry.getKey() + "=" + objectObjectEntry.getValue()); } }运行结果2020-06-26 17:38:52,777 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:38:52,801 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:38:52,824 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:38:52,824 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'} 2020-06-26 17:38:52,825 INFO [TempTest] - 缓存关闭前 2020-06-26 17:38:52,826 INFO [TempTest] - -1654591322:461730790:dao.Temp03Dao.getById:0:2147483647:select * from temp where id = ?:1:dev===[TempEntity{id=1, value1='11111', value2='aaaaa'}] 2020-06-26 17:38:52,827 INFO [TempTest] - 缓存关闭后可以看到session关闭后,缓存就不存在了2.Commit提交test @Test public void testCommit() throws IOException { InputStream inputStream = Resources.getResourceAsStream("mybatis.xml"); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = build.openSession(); TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity1); sqlSession.commit(); TempEntity tempEntity2 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity2); logger.info(tempEntity1 == tempEntity2); }运行结果2020-06-26 17:40:40,821 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:40:40,846 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:40:40,862 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:40:40,862 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'} 2020-06-26 17:40:40,863 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:40:40,863 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:40:40,864 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:40:40,864 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'} 2020-06-26 17:40:40,864 INFO [TempTest] - false说明sqlSession.commit时会清空缓存3.Rollbacktest @Test public void testRollback() throws IOException { InputStream inputStream = Resources.getResourceAsStream("mybatis.xml"); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = build.openSession(); TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity1); sqlSession.rollback(); TempEntity tempEntity2 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity2); logger.info(tempEntity1 == tempEntity2); }执行结果2020-06-26 17:42:23,793 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:42:23,833 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:42:23,843 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:42:23,843 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'} 2020-06-26 17:42:23,844 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:42:23,844 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:42:23,845 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:42:23,845 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'} 2020-06-26 17:42:23,845 INFO [TempTest] - falsesqlSession.rollback()也会清空缓存4.update更新这里是在第一次查询后,紧接着进行update操作。这里与表无关。就是操作其它表,也会清空缓存。test @Test public void testForUpdate() throws IOException { InputStream inputStream = Resources.getResourceAsStream("mybatis.xml"); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = build.openSession(); TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity1); sqlSession.update("dao.Temp03Dao.updateById", 1); TempEntity tempEntity2 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity2); logger.info(tempEntity1 == tempEntity2); }运行结果2020-06-26 17:45:43,997 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:45:44,034 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:45:44,048 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:45:44,049 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'} 2020-06-26 17:45:44,049 DEBUG [dao.Temp03Dao.updateById] - ==> Preparing: update temp set value1 = 'ffffff' where id = ? 2020-06-26 17:45:44,049 DEBUG [dao.Temp03Dao.updateById] - ==> Parameters: 1(Integer) 2020-06-26 17:45:44,050 DEBUG [dao.Temp03Dao.updateById] - <== Updates: 1 2020-06-26 17:45:44,051 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:45:44,051 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:45:44,052 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:45:44,053 INFO [TempTest] - TempEntity{id=1, value1='ffffff', value2='aaaaa'} 2020-06-26 17:45:44,053 INFO [TempTest] - false这里还是在一个session会话中。记得之前有人给我说只要在一个session会话中,执行update不会清空缓存。这里的代码就证明了5.clearCache 主动清除test @Test public void testClearCatch() throws IOException { InputStream inputStream = Resources.getResourceAsStream("mybatis.xml"); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = build.openSession(); TempEntity tempEntity1 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity1); sqlSession.clearCache(); TempEntity tempEntity2 = sqlSession.selectOne("dao.Temp03Dao.getById", 1); logger.info(tempEntity2); logger.info(tempEntity1 == tempEntity2); }运行结果2020-06-26 17:48:42,085 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:48:42,110 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:48:42,124 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:48:42,124 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'} 2020-06-26 17:48:42,125 DEBUG [dao.Temp03Dao.getById] - ==> Preparing: select * from temp where id = ? 2020-06-26 17:48:42,125 DEBUG [dao.Temp03Dao.getById] - ==> Parameters: 1(Integer) 2020-06-26 17:48:42,126 DEBUG [dao.Temp03Dao.getById] - <== Total: 1 2020-06-26 17:48:42,126 INFO [TempTest] - TempEntity{id=1, value1='11111', value2='aaaaa'} 2020-06-26 17:48:42,126 INFO [TempTest] - false一级缓存 脏读问题
-
鲲鹏架构默认的char是有符号还是无符号呢?
-
怎样前往WAF控制台进行误报屏蔽设置?
-
交换数据空间EDS是如何实现可信、可控功能的?
-
EDS有哪些应用场景?有哪些优势?
-
GaussDB用途特性,与其他数据库的异同? https://bbs.huaweicloud.com/forum/thread-0222129456565429281-1-1.htmlDTCC 2023专家解读丨GaussDB技术解读系列之数据库迁移创新实践https://bbs.huaweicloud.com/forum/thread-0246129349018228207-1-1.htmlGaussDB数据库SQL系列-表连接(JOIN)https://bbs.huaweicloud.com/forum/thread-0224128872778951555-1-1.htmlDTCC 2023专家解读 | GaussDB技术解读系列之性能调优https://bbs.huaweicloud.com/forum/thread-0299128917040068669-1-1.html如何提高单测覆盖率介绍https://bbs.huaweicloud.com/forum/thread-0249130843551639008-1-1.html idea的远程调试https://bbs.huaweicloud.com/forum/thread-0201130844150680015-1-1.html h2数据库在单元测试中的作用和如何使用https://bbs.huaweicloud.com/forum/thread-0201130846287046016-1-1.html java中使用h2数据库https://bbs.huaweicloud.com/forum/thread-0279130846188058018-1-1.html
-
申请开通DataArts Insight服务,并完成服务授权即可开启数据自助分析之旅,洞察数据的奥秘。前提条件DataArts Insight尚在公测阶段,请先申请产品公测,再参考本节操作开通服务。申请DataArts Insight公测。开通DataArts Insight服务套餐首次使用DataArts Insight服务请按照控制台引导开通服务,并完成委托授权。说明:服务授权需要主帐号或者用户组Admin中的子帐号进行操作。如果需要对委托权限进行调整,可在“委托授权”页面中进行修改。单击“开通服务”。阅读并勾选服务协议。图1 开通DataArts Insight服务获取云服务使用权限。授权后DataArts Insight才拥有对所选云服务的使用权限。授权后可在系统设置-授权功能下再次对云服务的使用进行授权或取消授权同意授权后,DataArts Insight将在统一身份认证服务IAM为您创建委托,授权成功后,可以进入服务委托列表查看。表1 DLI委托权限列表 权限名详细信息备注VPC AdministratorDataArts Insight数据源连接需要使用VPC、子网、路由、对等连接功能,因此需要获得使用VPC(虚拟私有云)的VPC Administrator权限。由于云服务缓存需要时间,授权需3分钟左右才能生效。IAM ReadOnlyAccessDataArts Insight对未登录过DLI的用户进行授权时,需获取IAM用户相关信息。因此需要IAM ReadOnlyAccess权限。单击“确认”完成服务授权后,即可开始用DataArts Insight服务。
-
目前,智能数据洞察(DataArts Insight)服务处于公测中,您可以申请公测,免费试用产品。前提条件由于公测期间资源有限,仅限已通过实名认证的华为账号申请公测。申请公测如果您已有华为账号并已开通华为云,请继续执行以下步骤。如果您还没有华为账号,参考注册华为账号并开通华为云。登录DataArts Insight DataArts Insight申请公测页面。填写公测申请表。在申请公测页面,填写公测申请表。勾选“同意《公测试用服务协议》”,单击“申请公测”。提交公测申请。系统提示已提交公测申请,预计5个工作日以内完成审核,请您耐心等待。审批成功。系统后台审批通过之后,会通过邮件(如果在申请表中填写了邮箱地址)或短消息的方式通知您。在“我的公测”页面单击“前往控制台”,或者重新进入DataArts Insight管理控制台即可使用DataArts Insight服务。公测期间产品规格信息DataArts Insight公测期间提供公测版本供用户体验,且公测期间免费试用。企业版规格如表1所示。表1 DataArts Insight公测期间企业版规格版本规格说明支持的用户数量适用场景企业版支持BI加速引擎支持盘古 for BI支持智能洞察50面向个人分析师或开发者,满足通常场景自助分析功能体验诉求。
-
VLDB技术论文《Taurus MM: bringing multi-master to the cloud》解读华为《Taurus MM: bringing multi-master to the cloud》论文被国际数据库顶会VLDB 2023录用,这篇论文里讲述了符合云原生数据库特点的超燃技术。介绍了如何通过各种黑科技减少云原生数据库的网络消耗,进而提升云原生数据库的性能和稳定性。下面就让我们抽丝剥茧,细细品味技术的魅力,揭开华为云数据库多主技术的面纱。说明:技术论文中的Taurus在华为云商用的产品名是GaussDB(for MySQL),是GaussDB(for MySQL)的云原生架构技术版本。一、引言现下,大型高性能数据库通常采用一写(主)多读(副本)这种标准部署方式来提高业务吞吐量。。然而,单主会导致单点故障,同时限制了写扩展性,也就是说带来了可用性和性能的双重挑战。而性能和可用性是衡量一个企业级数据库是否优秀最关键的两个方面。由此多主数据库应运而生。多主数据库有Shared-nothing和Shared-storage两种架构。谷歌Spanner、亚马逊DynamoDB、CockroachDB、OceanBase及其他一些数据库采用了Shared-nothing架构。亚马逊Aurora多主数据库、Oracle RAC和IBM DB2 pureScale采用了Shared-storage架构。对于Shared-nothing架构的多主,每个节点对一个小数据子集执行计算和存储。在高度分区的工作负载场景下,这类架构可以提供非常高的可扩展性。但在如下不均衡的工作负载场景中,其优势受限——节点数越多可能意味着节点间数据交换越多:数据无明显分区特征;工作负载随时间变化;存在热点数据场景。同时,Shared-nothing架构使用分布式提交协议,信息同步多轮交换,降低了多主系统的性能。对于传统的Shared-storage架构,计算层与存储层分离。这类架构由于其高度集成及密集网络通信的特点,需要高端和专用的网络硬件,更适用于对成本不敏感的线下数据中心部署,不适用于云原生数据库。云的最核心特点是通过多用户共享基础设施平摊成本(包括网络硬件)来实现高成本收益。云数据库性能的关键是对共享网络的优化。华为云数据库多主(Multi-Master)专注于从消息的数量和大小两方面减少网络流量,这一目标的达成并不容易,很多公司尝试过,但目前还没有看到成功案例。二、华为云数据库多主黑科技解析那究竟如何实现多主上云呢?华为云数据库多主有哪些硬核技术突破呢?通过对网络流量消耗进行分析和归类后,我们发现主要的网络消耗是由于主节点写页面、时钟同步和锁信息交互三个方面。华为云数据库在如上三个方面进行了探索和尝试,并取得了可喜成绩。下面详细讨论在每类开销上,华为云数据库是如何尽最大可能减少网络计算开销的。1. 减少直接页面写入带来的网络消耗此问题已有解决方案——2020年SIGMOD会议上我们向会议研究团体介绍了华为云原生数据库单主解决方案:“Log As Database”(日志即数据库)。简单说就是华为云数据库计算与存储分离,计算层包含一写(主)多读(副本)。计算层的作用是执行数据库的修改,主要功能有:接入连接、执行查询、管理事务以及生成WAL日志记录(日志用于描述对数据库页所做的修改)。事务更新时先生成日志记录,主节点将这些日志记录传送到存储层的Log Stores中进行存储,通过日志回放生成数据,从而无需通过网络执行整个数据页面的写入,节省了所需的网络带宽。详细见图1。图1:华为云数据库组件及分层架构华为云数据库多主重用了一主多读架构中的思想,采用Shared-storage体系结构,所有Master之间共享日志存储和页面存储,继续沿用悲观并发控制,且引入了全局锁管理器GLM(Global Lock Manager)。各Master维护自己的预写日志(WAL)。用户事务在单主上执行——没有分布式事务。日志记录写入执行事务的主机中。每个Master会定期将带有位置信息标识(哪个Master生成的)的新生成日志提交给所有其他Master。通过位置信息,各Master读取其他所有Master上生成的日志记录,并更新进自己的缓冲池页面中。详细如图2所示。图2:华为云数据库多主组件及分层架构2. 减少时钟同步带来的网络消耗多主数据库特有的第二个网络开销来源是时钟同步。在单主数据库上,事务时钟信息可以直接使用本地物理时钟。然而,在分布式系统中,不同节点上的物理时钟很难精确保持一致。而通过网络连接同步和获取时间戳,会带来无法容忍的时间延迟。因此,对于分布式数据库物理时钟这种方法不再适用。这在业界不是一个新近才提出的问题。早在20世纪70年代,莱斯利·兰伯特就为了解决此问题,提出并发明了标量时钟(常称为逻辑时钟,或兰伯特时钟)。此标量时钟由一个数字组成时间戳,仅在消息交换期间进行不同计算机间的时钟同步。兰伯特时钟的算法简单而优雅,但要通过它创建数据库的分布式快照基本不可能,而分布式快照对分布式数据库的性能又是非常重要的。同时,逻辑时钟无法保存事务间的因果关系。简单说,就是假设𝑇𝑆 (𝑎) < 𝑇𝑆 (𝑏),也就是事务a早于事务b,使用逻辑时钟,无法识别是a导致了b,还是a和b间仅是并发无因果关系。逻辑时钟之后又出现了矢量时钟,用于解决逻辑时钟的局限性。然而,虽然矢量时钟能够创建分布式快照,但是,矢量时钟有一个很大的缺点——加大了消息的大小。数据库之间的消息本来很小,矢量时间戳的加入使消息的大小增大为原来的两至三倍,从而加大了网络开销。华为云数据库团队发明了一种新型的时钟——VS时钟(VECTOR-SCALAR CLOCKS)。其关键的创新是,它既可以产生矢量时间戳,又可以产生标量时间戳,实现优势互补。VS时钟的应用,既达成了较小的网络消耗又保证了数据库全局快照的创建能力。例如,由于每个节点对同一页面的修改必须是串行的,无需关注因果(先后)关系,因此对单个页面修改的日志记录添加时间戳时,发放标量时间戳即可;当为全局快照的创建发放时间戳时,需要使用完整的矢量时间戳以便理清各主节点事务间的先后关系。由于全局快照这一类事件的数量级远小于日志记录,故而全局快照矢量时间戳所带来的空间开销可以忽略不计。3. 优化锁协议减少网络消耗多主数据库的第三个主要网络开销是锁信息交互带来的开销。对数据库的某些更改需要被视为原子更改,例如对内部数据库页的修改,或事务对记录行的修改。通常,数据库使用锁来实现原子性。通过观察我们得到一个重要结论:鉴于所有行都是存储在页面上的,因此要修改或读取对应行,就意味着必须修改或读取此行所在的页面。由此,我们提出了,对于数据库最底层的行页混合锁定,行锁信息不再作为单独的消息进行传递,而是作为页锁的一部分来传递。这种方案,会将锁信息的数量显著减少,从而进一步降低了网络负载。数据库系统的行锁类型有:(普通)共享和独占行锁、间隙锁、next-key锁和意向锁,在华为云数据库多主中讨论的“行锁”包括了所有这些类型的锁。行锁可以以不同的方式管理,我们在分析和对比了下面的三种不同方法后,选择了行锁跟随页锁的方法。GLM管理行锁:让全局锁管理器GLM同时管理页锁和行锁。这种方法每次行锁获取时都需要走GLM,因而会增加网络负载。DB2 pureScale采用了这种方法,并进行了各种优化。GLM管理行锁的方案,网络流量很高,即使在工作负载大部分是分区的场景下,也依然很高;此外,GLM还必须要能支持底层系统使用的所有行锁类型及这些锁之间的复杂交互。在页面上存储行锁:将页面的行锁信息存储在本身所在的页面上。Oracle RAC采用这种方法。华为云数据库未采用这种方法,有两个原因:1)它需要将行锁获取/释放记录写入日志,从而增加了网络负载;2)它需要更改磁盘上的页面格式,华为云数据库由单主升级到多主时必须做这种数据库格式转换,将损失华为云数据库的原有优势。行锁跟随页锁:当Master获取页面锁时,一并获取该页面上的行锁列表,包括持有的锁和挂起的锁请求。之后,Master可以在页面上授予额外的行锁,当然前提是这些行锁要与其页锁兼容。当Master向GLM释放页锁时,同时会将页面上当前行锁的信息发送给GLM。需要说明的是,锁请求挂起的信息虽不是很关键,但它对GLM和Master上的锁调度决策很有用,因此也会传递给GLM。华为云数据库最终选择了这种方法。在华为云数据库中,GLM只管理页锁,不授予或释放行锁,但页锁信息中跟随有行锁信息。GLM将页面上的锁授予Master时,会将页的版本号(如果有)发给Master,从而该Master将拥有页的最新版本,以及页上的行锁列表。接收了页锁的Master会将行锁信息添加到其本地锁管理器LLM中。当Master释放页锁(自愿或响应请求)时,它向GLM递交页面版本号和页面上的行锁列表。在不涉及数据一致性的前提下,Master上的行锁更改不需要立即与其他Master同步。除非另外的Master要请求锁定的页面与当前Master是有锁冲突的同一个页面。这种情况下页锁释放和回收流程将被启用,行锁信息被一并发送到GLM,将很好地避免行锁授予或等待时频繁联系GLM,可以显著减少行锁网络流量。以下是更详细的流程:释放页锁时(自愿或被动响应回收):–Master上:有关页面上所有行锁的信息将发送到GLM。–GLM上:接收到的行锁信息缓存在内存中。请求和授予页锁时:–Master上:为了响应本地事务的行锁请求,Master必须持有行所在页上的锁。如果Master没有拿到所需的页锁,它会首先向GLM发送页锁请求。–GLM上:当页面锁请求到达时,GLM会判断同一页面是否有其他冲突锁或者挂起的其他Master锁请求,如果有,新的Master所请求需要等待。当GLM准备好授予页锁时,它首先回收页面上的冲突锁(如果有),并捕获新接收到的行锁信息;之后将页面锁授予Master,并将响应消息、行锁信息及页面的最新版本号一并发给Master。–Master上:收到页锁授权响应消息后,将行锁信息添加到LLM(Local Lock Manager)中,并刷新页面版本号。本地事务再次尝试后可以成功获取所需的行锁。三、华为云数据库多主架构效果验证我们首先测试了华为云数据库多主架构自身的性能和可扩展性。同时,我们将华为云数据库多主与亚马逊的Aurora 多主(我们所知的唯一一个云原生Shared-storage数据库)进行了对比。最后,我们还将华为云数据库多主与Shared-nothing架构的CockroachDB进行了对比。1. 测试环境说明实验验证运行在一个最多8个主节点的集群上,并在4个具有相同硬件配置的节点上部署了存储层(数据存储和日志存储)。详细见表1。表1:测试环境规格配置项规格说明集群规模4存储节点&最多8个主节点存储节点和主节点的硬件配置相同。CPUIntel Xeon Gold 6278C 2.6GHz CPU 28核*2在每个节点上,主Master独用一个CPU,工作负载驱动程序使用第二个CPU。操作系统CentOS 7.0-Buffer Pool128GB-网络25Gbps-在所有实验中均使用了两个标准工作负载:Sysbench和Percona TPC-C。Sysbench是一个流行的基准测试,它可以生成插入、删除、更新、点查、范围查询及这些类型的各种组合。我们扩展了Sysbench,以便控制数据共享的程度。在一个由N个主节点组成的集群上,实验将表逻辑上分为N+1组。前N组中的表是私有表,即每个组被分配给一个单独的主节点,只有指定的主节点可以访问对应组中的表。最后一个组是共享的,即任何主节点都可以访问此组中的表。当实验指定共享程度为X%时,表示X%的数据库读写访问是针对共享表进行的,其余的读写访问是针对私有表进行的。完全分区的工作负载对应于X=0%,完全共享的工作负载对应于X=100%。实验设置中,对于共享工作负载场景,每个组包括100个表,每个主节点访问100个私有表以及100个共享表。对于完全分区的工作负载,每个组包含200个完全分区的表。每个表有2.35M行数据,每行约200字节, 因此对于所有的实验,每个主节点都可以访问约100GB的数据。TPC-C是评估OLTP系统性能的行业标准性基准。数据按仓库跨主节点分区,但10%的事务访问了远程的数据分区。除非另有说明,我们使用的是1000个仓库配置。2. 华为云数据库多主性能测试结果华为云数据库多主在Sysbench只写、Sysbench读写(80%读取,20%写入)和TPC-C基准测试上的性能表现如图3所示,3(a-c)。在X轴上,集群大小从1个主节点到8个主节点。在Y轴上,显示了绝对吞吐量以及相对于单个主节点的吞吐量。Sysbench测试结果的每条线对应不同程度的数据共享。TPC-C使用的是固定的10%共享查询。对于只读工作负载,由于多版本的存在,其可以完美地扩展,因此这里略去不显示从图中可以看出,对于完全分区的工作负载,随着主节点数量的增加其性能几乎线性扩展。8个主节点集群规模下,10%共享的Sysbench只写和读写场景,相较单个主节点,分别实现了3.5倍、4.5倍的加速; TPC-C工作负载下,相较单个主节点,实现了5倍的加速。正如预期的一样,可扩展性受数据共享程度的影响较大。同样8个主节点集群上,30%共享负载下的只写和50%共享负载下的读写,相较单个主节点,均实现了不到2倍的加速。由于可用的硬件有限,我们未验证16个主节点集群的结果,但从图中不难看出,8个主节点的可扩展性已接近线性。图3. 华为云数据库多主Sysbench和TPC-C性能测试结果3. 与Aurora多主的性能对比图4对比了基于相同CPU核数和内存缓冲池情况下华为云数据库多主和Aurora多主的性能。在所有测试中,我们观察到单主情况下,华为云数据库的性能超过了Aurora。由于Aurora多主除了计算层之外,未暴露其他硬件细节,因此我们只测试对比了各自相对于其单主的性能数据。鉴于Aurora不允许超过4个主节点,因此8个主节点性能测试仅在华为云数据库多主上进行。对于完全分区的工作负载,两个数据库的扩展几乎相同,故测试时省略了不同分区负载的差异对比,而是选取了具有代表性的10%共享负载做性能对比测试。在此较小的共享负载场景下,华为云数据库处理工作负载的能力要好得多。在共享写入工作负载场景下,我们发现Aurora中所有主节点上存在大量因冲突导致的被中止事务,从而带来主节点之间的性能不均衡。华为云数据库的多主由于其基于混合行页锁的并发控制,未发生任何事务中止。图4 华为云数据库多主 VS Aurora多主4. 与CockroachDB的性能对比我们还将华为云数据库多主与基于Shared-nothing架构的CockroachDB(简称CRDB)进行了比较。之所以选择CRDB,是因为它是开源的,且根据相关报告分析,其性能比Spanner和TiDB更好。实验使用两种配置规格,即分别将CRDB和华为云数据库部署在相同的6节点和12节点集群上,从而比较相同硬件条件下双方的性能。由于华为云数据库专门使用4个节点用于存储层,而CRDB为Shared-nothing架构,每个节点上既有计算层又有存储层,因此将6个和12个节点CRDB分别与2个主节点和8个主节点的华为云数据库多主进行了比较。对于CRDB和华为云数据库多主,实验时使用了尽可能大的连接数来提高吞吐量。对于华为云数据库多主来说,每个主节点上的连接数为64个;对于CRDB,每个主节点上的连接数从128到512不等。在CRDB上,我们运行了CRDB附带的类似TPC-C的基准测试。对于华为云数据库多主,我们运行了Percona TPC-C。在表2中列出了1000和5000个仓库的结果。对于每次运行,我们记录了每秒可处理的新订单事务数(tpmC)、事务平均请求时延和95%事务的请求时延。在所有测试场景下:华为云数据库多主吞吐量都明显更高,从6节点、5000个仓库的吞吐量高出60%,到12个节点、1000个仓库的吞吐量高出320%。华为云数据库双主的交易延迟也要低得多,平均请求时延和95%事务的请求时延均低得多。我们还计算了一个扩展比,即12节点相较6节点其吞吐量的增加比例,华为云数据库多主要优于CRDB。正如引言中所指出的,Shared-nothing架构的开销受分布式事务提交的影响更明显,分布式事务提交的开销随着事务中涉及的节点数量的增加而增长。对于给定的工作负载,效率受限于事务复杂性。表2 华为云数据库多主 VS CockroachDB: TPC-C结果 华为云数据库MMCRDB1000w5000w1000w5000w6节点 tpmC250000216000121000137000时延(ms)17/4816/3590/150220/62012节点 tpmC691000734000164000279000时延(ms)21/10619/80150/300590/1280比例因子2.83.41.42效率0.70.80.71.0 四、总结华为云数据库多主是专门为云环境设计的云原生多主OLTP数据库系统。它是一个存算分离的云原生数据库系统,使用全局锁管理器来协调对数据库页和行的读写访问。现实业务中的许多OLTP工作负载大多是可分区的,其中只有一小部分页面在多个主节点之间共享。例如,在TPC-C中,只有10%的访问是对远程仓库的访问。华为云数据库多主设计的一个关键目标是为了在共享程度低的工作负载上实现良好的性能和可扩展性。华为云数据库多主采用了两个关键创新技术: VS(vector-scalar)时钟和混合行页锁,旨在降低网络负载和提高性能。VS时钟通过对系统中更频繁的消息(日志记录)使用单个标量时间戳,而数量很少的消息使用矢量时间戳来降低网络负载。同时,使用VS时钟,系统保留了查看系统级事务一致性状态的能力。混合行页锁技术通过减少发送到全局锁管理器的锁请求数量来提高事务吞吐量和减少延迟。特别是,如果页面被主节点访问一段时间后,行页锁将自动委托给单一的主节点。我们的实验结果证实了华为云数据库多主系统的性能和可扩展性。在TPC-C基准测试中, 4个主节点的最大扩展效率为84%, 8个主节点的最大扩展效率为62%。在最大8个计算节点的集群上,华为云数据库多主在TPC-C上展示了优于Aurora多主和CRDB的性能。
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签