2009年9月24日星期四

sqlalchemy、storm和web2py dal的比较报告

工作项目报告,所以抹掉项目名先,以"X"代之。

分割线内内容仅代表个人意见,与所供职企业及参与社区无关。

===================================

X 从很早的时候就出现各种数据库访问错误。包括链接数占用过多,死锁,
僵尸事务等。本周我集中梳理了一遍代码。我认为,虽然数据库设计方面有诸多
不合理之处,但是这些不合理主要影响业务错误,造成 X 性能和使用上的
问题是因为使用的ORM框架 storm 有严重的缺陷。

首先,storm 对数据库架构的同步有非常奇怪的设定。它不自动同步表结构,却插
手外键关联关系。强制要求外键必须都是级联更新、级联删除、set null。且不说
其设定中有自相矛盾之处,本身在MIS系统中做级联删除就是一件很危险的事——除
了系统维护、分表,MIS系统不应该删除任何数据。 storm 从一开始设计恐怕就没
有考虑企业级应用,但是对于web 开放式应用,storm 对外键的依赖又太笨重了。

其次,storm 在联接数据库后应该会有 DDL 操作(即修改数据库结构)或独占锁
定事务,此推断的证据在于用 storm 联接到 S 库后, S 无法进行
vacuumdb -a -f 处理。而根据 Postgres 手册,PG只有在遇到有链接正在进行
DDL 操作时,才会产生库级锁,造成 vacuum 操作无法进行(或手工建立一个隔离
级别相当的事务锁定)。作为世界上并发能力最强的数据库产品,正常的数据访问
操作与 vacuum 根本不会冲突,热处理资源回收正是 PG 独到的特性。这样造成了
X 应用频繁用光所有的链接数,还在数据库服务器遗留僵尸进程。我观察到
有僵死十几二十天没有完成过的 X 链接,这应该是因为同时多个 storm 链
接提交错误的锁定关系,造成死锁。

第三,storm 如果可以象 DAL 那样,明确设定不同步数据库,以上问题至少可以
解决一半,但是它没有链接配置参数。这造成了我们对其出现的问题无法进行友好
的调整。现在同事在 X 的 controll 层添加了强制的 commit 操作,一定
程度上减少了死链,但是我仍然观察到有点击 X 页面(在测试环境下)无
法响应,甚至造成数据库服务器闪断重启的现象,对于同时运营三十几个数据库的
数据库服务器,这是非常大的安全隐患。

昨天我尝试将 X 的数据库访问层迁移至 web2py DAL,经过一天尝试,总结
出以下的问题:

第一,DAL 缺少精确实数计算类型,它不支持 Numeric 或 Decimal,只能用
double,这是一个相当大的安全隐患,对于涉及财会计算的应用,使用浮点数是一
种很不严肃的作法。

第二,DAL 不支持数组和大数据类型,此类字段在 X 中有几处应用。

第三,DAL 对原生SQL的支持比较初级,虽然也可以使用,但是有时需要兼顾开发
速度,希望可以组合使用的时候,就会受限。

以上问题不是不能解决,但是需要修改 DAL 本身。虽然我一直有计划改造 DAL,
fork 一个对 PG 有良好支持的分支出来。但是这显然需要更多的开发时间。

昨天我详细查阅了一下 sqlalchemy 的文档,进行了一些简单的尝试,感觉这个
ORM 框架比较符合我们的需求:

第一,sqlachemy 对数据库链接的隔离级别和事务有良好的控制,默认也不会去尝
试DDL操作。

第二,sqlachemy 有非常丰富的数据类型支持,包括BLOB,Decimal/Numeric,以
及为 PG 特别定制的数组类型。

第三,sqlachemy 的查询类似 DAL (很可能DAL学习自sqlachemy),对各种查询操
作有良好的支持,还可以嵌入 SQL 片段,也可以方便的直接传入 SQL。

第四,sqlachemy 其实并不难学,它的功能虽然丰富,但是只掌握自己要用到的部
分即可,不需要完全学会,上手还是很简单的。

第五,文档比 storm 完整的多,而且现在仍在活跃开发。

第六,数据存储模型与业务模型分离,虽然看起来有重复劳动,但是对于一个需要
长期维护的企业应用项目,这是正确和严肃的作法。

第七,对特定数据库的特性有良好的支持,还可以扩展。

在使用 sqlachemy 时,我们还可以结合 web2py 原有的一些优秀工具,例如广泛
用于 DAL 的storage类型,这是一个类似 JS Object 的智能对象类型,很适合动
态结构的数据对象。

对于 X 项目的数据访问层重构,我评估工作量至少在一周左右。如果全部
换用 sqlachemy ,可以一劳永逸的解决数据库访问的问题,甚至 S 的后续版
本,我也建议尝试使用这个框架,毕竟这比 hack dal 要方便一些。

sqlachemy 当前的稳定版本是 0.5.6 ,我昨晚试验了开发中的 0.6 ,发现功能还
没有完整实现,现在还不能实用。


===================================

--
光见贼吃肉,没见贼挨打。
……

劉鑫
March.Liu

2009年9月15日星期二

近日 twitter 发布信息整理

  
   数据库的架构与设计,应该从整体的范围去看问题,要从"数据存储和管理服务"的角度,而不是"数据库软件"

   应用层开发阶段,可以不加入外键,在数据库运营阶段,由DBA补完

   ID列的主键身份,其实只是为了与ORM妥协,在很多情况下,一个表只有ID主键列,既危险又愚蠢。如果应用层存在BUG,就会引发严重问题。我的建议是,至少在运营前期,就为关键实体数据加上唯一索引。

   存储过程有没有用?这个要看情况。做数据库架构就像建筑工程,不是"对""不对"这么简单。早年Oracle宣传一切逻辑都封装在存储过程中,数只从存储过程访问,这叫蛋疼。后来MySQL宣传外键存储过程触发器都不需要,只要能增删改查,这叫犯二。

   一个数据库要如何设计,业务对数据可靠性、完整性、性能的需求平衡是一个很重要的因素。对于用户访问日志(包括点击率等等),有一定的误差也是允许的,而商务活动往往是不允许有哪怕毫厘之差。针对不同的业务,应该有不同的设计和架构方案。
         
   上次李元佳先生介绍的EDB集群方案给我一定启发。典型的集群节点可以每节点由三个机器组成:一个查询节点,一个写入节点,一个备份节点。写入节点和备份节点多出来的内存可以共享给查询节点做为无限缓存(EDB特有功能)。
         
   有时查询节点还要负担起OLAP的任务,或者本身统计查询的计算量就远大于写入量,此时可以由一个写入节点带多个查询节点,或者直接向一个EDB网格同步。当然网格化以后,写入性能通常会有接近线性提升,这样可能就不需要写入节点了。

   前段时间我写过一篇文章,合理利用触发器,可以把一个无限增长的日志表访问,变成限定于20条数据的访问,如果按现在流行的MySQL+ORM,这种东西是做不出来的。
         
   事实上很多项目,尤其是高负载的互联网应用,最终都没有使用ORM。既然如此,拒绝数据库服务端编程就是一件很奇怪的事。在数据库服务端进行合理的编程,可以大大提高性能。
         
   既然数据库服务是作为一个整体使用的,那么性能分析也要从整体考虑。有些功能虽然单独比较性能不高,但是却能在合适的时候,提高应用的整体性能。
         
   数据库设计要符合业务,不要拿来作为自己炫技的场所。
         
   虽然这年头是个人都知道出来吼一句"数据库太慢!"以显示自己牛B,但实际上有多少是真的牛B到跨过了关系型数据库的极限,有多少只是不懂数据库在那里装B呢?
         
   观点:DBA的职责,除了维护工作,应该有以下几个——帮助设计人员找出性能和安全方面的问题;帮助开发人员解决数据库方面的问题,例如一些用其它手段难以解决的性能瓶颈和复杂逻辑;协助架构师制定系统持久层架构;为乙方(通常是DBA就职的一方)提供架构方面的专业意见。
         
    个人认为大多数应用不应该出现大量存储过程,尤其在ORM比较成熟的现今,基本不需要为CRUD操作封装存储过程,而存储过程不能与用户多步交互执行,这就决定了它不会主导事务处理逻辑。但是存储过程可以简化复杂的事务逻辑。
         
    简单的说,存储过程最好是在开发由粗到精的优化过程中加入,代替需要优化的代码部分。如果是那种希望快速粗放的拼装一个项目然后交钥匙不管的初等级开发(不要拿这个来冒充XP过程)并不适合过多使用存储过程,最好是用熟ORM,积累并复用确实有效的一些存储过程和SQL脚本模板。


--
话题越大,废话越多;名字越火星,问题越脑残。
……

劉鑫
March.Liu