代码之家  ›  专栏  ›  技术社区  ›  Chris

重写Web应用程序的数据库设计

  •  10
  • Chris  · 技术社区  · 15 年前

    我们向客户提供的许多业务线应用程序都具有营销/促销性质(抽奖、活动注册等)。大多数应用程序虽然非常简单,但对数据库的要求非常高。例如,想象一个“注册”类型的站点作为超级碗期间播放的商业广告的后盾(是的,我们有几个)。

    尽管我们已经非常擅长优化我们的web应用程序代码,但是数据库始终是一个问题,尽管应用程序相对简单。流程通常是这样的:

    1. 从数据库读取以检测现有记录
    2. 如果记录是新的,则写入数据库

    在许多情况下,这就是我们的应用程序需要执行的所有数据访问。然而,考虑到这是应用程序的唯一目的,对这个简单的过程进行大幅度优化是非常重要的。

    对于这个问题,我们有一台服务器运行一个用于数据文件的RAID 5磁盘阵列,另一个用于日志的RAID 5阵列。此时,操作系统为Windows2003标准32位,服务器内存为4GB。一些应用程序使用SQL 2005标准,而其他应用程序使用MySQL5.1。我是 非常清楚 某些操作系统和硬件优化在这里是可能的,但我希望首先从软件方面解决我的需求。广泛的分析告诉我们 磁盘IO通常是主要的瓶颈 .

    说了这么多,并且知道缓存没有多大帮助,因为大多数读取都是唯一的,返回的数据很少(通常只有一点指示记录是否存在),所以我正在考虑将内存数据库领域作为一种对真实数据库的写缓存层。这似乎是一个很好的适应,因为我们的大部分高流量交通是零星的性质,并没有持续几个小时。此外,在大多数情况下,由于服务器崩溃而可能丢失几分钟的数据是可以接受的。

    在最简单的形式中,我将修改一个典型的注册应用程序来执行以下操作:

    1. 查询磁盘数据库和内存数据库中的现有记录
    2. 如果没有,则将数据写入内存数据库并返回
    3. 定期将内存数据库刷新到磁盘数据库

    我的问题是 :这个中间内存数据库的选项是什么?我尝试过内存中的哈希表、数据表等等,但是我正在寻找其他选项,甚至是完全不同的方法的建议。

    9 回复  |  直到 11 年前
        1
  •  6
  •   srini.venigalla    15 年前

    接受“一切都是信息,数据库是备份”的新概念。当您有东西要存储时,创建一个消息并使用xmpp将它发送到一个黑盒(如ejabberd)。让blackbox按照自己的计划更新数据库。像twitter这样的网站就是这样运作的。

    看看这个幻灯片: http://www.slideshare.net/kellan/beyond-rest

        2
  •  7
  •   Ryan Brunner    15 年前

    如果您不需要实时知道是否存在现有记录(即记录在其中很重要,但您不需要向用户报告它是新的还是现有的),您可以以允许极快写入时间的方式构建数据库,而不需要内存中的数据库,因为内存中的数据库承载了大量如果服务器停机或工作进程重新启动,则可能出现问题。

    在数据库中为每个与此写重流相关的表创建两个表。一个表应该是您的“活动”表,并且应该尽可能地进行写优化(即,没有索引,除非移动到读取表,否则永远不会从中读取)。您的另一个表应该是您的读优化表-根据任何报告注意事项等进行索引。

    无论何时,当您正在写入活动表时,忽略与记录是新记录还是现有记录有关的任何事情,或者与将数据尽可能快地放入表并从数据库中取出无关的任何事情。设置一个计划作业,将记录从活动表移到读取优化表中,并担心在该表中匹配现有记录。理想情况下,这将在非高峰时间完成,但否则,您可能需要考虑第三个临时表,以便在任何时候都不会对活动表产生争用。

        3
  •  2
  •   Neil N HLGEM    15 年前

    与编程无关,但肯定会有帮助:获得一些新的固态磁盘。

    是的,它们的大小是昂贵的,但由于磁盘IO是瓶颈,将当前的HDD换成某些SSD将大大提高性能。

        4
  •  2
  •   Walter Mitty    15 年前

    这里有一个奇怪的想法:不要使用数据库进行初始捕获。设计两三个快速索引文件,其格式不需要经常更改。捕获这些文件中的数据。

    编写一些适当触发的软件,将捕获的数据复制到数据库中,但不会延迟交互式用户。标记复制的数据以防止复制,并回收文件中的空间。

    现在,您可以使用在多个用途之间共享数据的思想来设计数据库,而不是使用跟上捕获过程的思想。毕竟,共享数据才是数据库真正的亮点。

        5
  •  1
  •   Ewan Todd    15 年前

    SQLite有一个 in memory 操作模式。如果在页面点击处理程序后面有一个持久的服务器进程,那么这就可以工作。

    否则,常规的基于文件的DBS会被愚弄到将其文件写入内存文件系统,比如 tmpfs .

        6
  •  1
  •   user189327    15 年前

    在我看来,您应该能够使用一个RDBMS来适应您的工作负载,该RDBMS具有用户大小的缓存。我看到的是每秒10000个索引记录的顺序,一个简单的C++可调用的RDBMS和普通的硬件。包括提交到磁盘。此外,由于您可能只查看一个记录中的一个小字段,因此请查找一个面向列的数据库——一个沿着列存储数据的数据库。如果你只对一个领域感兴趣,那么阅读整行没有意义。

        7
  •  1
  •   Mike    15 年前

    正如许多其他人提到的,优化数据库模式以进行写入而不是读取是您的第一个调用点,尽管我猜您已经到了那里。

    在研究内存数据库之前,您可能需要查看一些可用的ORM,特别是NHibernate。

    nhibernate将一些数据保存在内存中,并允许您控制何时从内存中“刷新”数据更新并与数据库同步。

    你可能觉得值得一看。

        8
  •  1
  •   hythlodayr    15 年前

    编辑:严格关注磁盘I/O…

    1. 尽可能多地删除不必要的索引。指数不是免费的——空间或时间。
    2. 撕掉任何你不需要的特殊触发器或约束。
    3. 删除任何不是绝对关键的实体关系/关系完整性操作符。
    4. 如果您当前的DBMS支持它,请将事务表分为多个磁盘(例如,循环)。
    5. 考虑到添加更多相互独立的数据库服务器(即不涉及复制);为此,您需要一个调度程序来决定哪个服务器将接受事务,以及一个合并事务的方案/单独进程。

    将数据库逻辑的数量最小化,并从侧面添加服务器(而不是使用边缘服务器技术),这基本上是易趣采用的方法。

        9
  •  0
  •   Jens Schauder    15 年前

    我不知道您提到的数据库,但是如果数据库的内容(或者至少重要的表)适合内存,Oracle就能够将其固定在缓存中,所以它基本上就像内存中的数据库一样。

    我还将检查数据库的隔离级别设置。如果你能放松这些,你就可以减少锁定。

    最后考虑删除唯一约束,或者在高峰时间禁用它们。