实施Google App Engine中记录更改的高效审计跟踪 - 设计模式

Ale*_*zyk 6 python performance audit google-app-engine expando

我有一个很常见的设计问题:我需要为Google App Engine中的记录实现历史记录(审计跟踪).历史日志必须是结构化的,即我不能将所有更改加入到一些自由格式文本中并存储在字符串字段中.

我已经考虑了历史模型的以下选项,并且在注意到选项#1中的性能问题之后,我选择实现选项#3.但是,如果这个解决方案是高效和可扩展的,那么我们会有些怀疑.例如:随着选项#3中动态属性数量的增加,性能是否会显着下降?

您是否对每个选项的优缺点有更深入的了解,或者可以建议适用于Google App Engine数据库特征的其他审计跟踪设计模式?

  1. 使用经典SQL"master-detail"关系
    • 优点
      • 具有SQL背景的数据库开发人员易于理解
      • clean:历史记录及其属性的直接定义
      • 搜索性能:轻松搜索历史记录(可以使用索引)
      • 故障排除:管理工具轻松访问(_ah/admin)
    • 缺点
      • 通常不建议在GAE DB中以这种方式实现一对多关系
      • 读取性能:过多的记录读取操作以显示长的审计跟踪,例如在大记录列表的详细信息窗格中.
  2. 将历史存储在BLOB字段中(酸洗python结构)
    • 优点
      • 易于实施和灵活
      • 阅读性能:非常高效
    • 缺点
      • 查询性能:无法使用索引进行搜索
      • 故障排除:无法通过admin db viewer(_ah/admin)检查数据
      • 不洁净:不太容易理解/接受SQL开发人员(他们认为这很难看)
  3. 在Expando的动态属性中存储历史记录.例如,对于每个字段fieldName创建history_fieldName_n字段(其中n = <0..N>是一些历史记录)
    • 优点:
      • 简单:易于实现和理解
      • 故障排除:可以通过管理界面读取所有历史属性
      • 读取性能:一次读取操作以获取记录
    • 缺点:
      • 搜索性能:不能简单地搜索历史记录(它们有不同的名称)
      • 不太干净:初看时,属性数量可能会令人困惑
  4. 将历史记录存储在主记录的某些列表字段中.例如.为每个fieldName创建一个fieldName_history列表字段
    • 优点:
      • clean:直接定义历史属性
      • 简单:SQL开发人员易于理解
      • 读取性能:一次读取操作以获取记录
    • 缺点:
      • 搜索性能:可以使用搜索索引仅适用于只要有一定的价值,不能搜索在一些特定的时间具有值的组合记录记录;
      • 故障排除:在admin db viewer中检查列表很困难

Koe*_*Bok 3

如果我必须选择,我会选择选项 1。读取的性能与其他选项一样(如果不是更好)。所有其他选项仅在特定情况下(小或非常大的更改集)才具有速度优势。它还将为您提供很大的灵活性(更轻松),例如 x 天后清除历史记录或跨不同模型类型的查询历史记录。确保在同一事务中将历史实体创建为已更改实体的子实体,以保证一致性。你最终可能会得到以下之一:

class HistoryEventFieldLevel(db.Model):
    # parent, you don't have to define this
    date = db.DateTime()
    model = db.StringProperty()
    property = db.StringProperty() # Name of changed property
    action = db.EnumProperty(['insert', 'update', 'delete'])
    old = db.PickleProperty() # Old value for field, empty on insert
    new = db.PickleProperty() # New value for field, empty on delete

class HistoryEventModelLevel(db.Model):
    # parent, you don't have to define this
    date = db.DateTime()
    model = db.StringProperty()
    action = db.EnumProperty(['insert', 'update', 'delete'])
    change = db.PickleProperty() # Dictionary with changed fields as keys and tuples (old value, new value) as values
Run Code Online (Sandbox Code Playgroud)