【问题标题】:How to expand single user WebApp to multiple users如何将单用户 WebApp 扩展到多个用户
【发布时间】:2013-04-11 01:10:34
【问题描述】:

有一个类似的线程没有具体的解决方案,我认为最好开始一个新的。

我面临的情况是,我在 RESIN 中托管了一个 WebApp(我猜就像 Tomcat)。到目前为止,我一直在使用 db4o 开发应用程序,因为我一个人,我需要尽快完成应用程序,我有一个用于用户的数据库和另一个用于单个用户(我)的应用程序数据的数据库,现在应用程序几乎完成我将要迁移到 postgresql 并且我正在认真考虑每个用户的数据库,即使数据库保存多个应用程序的数据,因为它将处理有点机密的数据,我认为拥有单独的数据库将是最好的(安全方面)。已经有一个基本的会话管理,可以在浏览器中存储用户数据,如 ID。但我想知道如何将它扩展到多个用户/数据库。

我正在考虑扩展监听器类来保存上下文数据以将正确的 db 对象传递给应用程序实例,或者为此目的设置一个过滤器。

.更新。

我想更深入地了解我目前拥有的东西。

我有:

包含对某些对象的引用的上下文,其中一个对象连接到数据库并检查用户和密码。

Presentation servlet (HttpServlet) 映射到具有 POST 到 /login 的登录表单的“/”。

登录 servlet (HttpServlet) 映射到“/login”,它检查 httpSession 用户密码属性与位于上下文中的相应对象,如果匹配,则设置一个包含 USERID 的 httpSession 属性并将用户重定向到应用程序本身位于 /index-debug.html 如果不是,它会再次创建一个带有登录表单的新 html 页面。

映射到 /index-debug.html 的授权和身份验证过滤器验证 USERID 属性的 httpServletRequest 并检查用户是否有权访问应用程序。

最后是一个负责读取和写入 webApp 用户数据 DB 的 DB bean。当我在 webApp CP2JAVAWS 中执行某个方法时,将该方法与 bean 中的相应方法相匹配,问题是这个 bean 有一个静态数据库,到目前为止它只允许一个用户。

我想做的是以某种方式允许这个 DB bean 为每个用户实例化一次,并根据当前登录的用户读取和存储相应的数据。

目前已放弃每个用户一个数据库的想法,但我不知道如何实现。

【问题讨论】:

    标签: web-applications resin multiple-users


    【解决方案1】:

    您提到 Postgres 作为数据库后端并且具有称为模式的功能。这是您在数据库中拥有一个物理数据库和多个模式的情况。我的经验来自 Rails,但概念是相同的。这种方法避免了将人们的数据混合在同一组表中,这听起来像是您最关心的问题。我知道您使用的是 Java,但 watch this talk on Multi-tenant apps in Rails to get a background from Guy Naor 了解其工作原理、权衡取舍等。

    以下是一些具体步骤,可帮助您开始使用 Postgres 模式:

    1. Postgres 中有一个默认的公共模式。这将是您放置用户身份验证表和有关用户登录等任何其他通用元数据表的位置。See Postgres docs for more info on how schemas work
    2. 为您将创建的每个架构(例如 user_001、user_002 等)提出一个命名约定。预先分配一堆空模式并设置所有表,当用户第一次注册或登录时,您为他们分配一个模式并将模式名称存储在公共模式和用户对象中的用户记录中你在 HttpSession 中。无需为第一次使用的用户运行表创建脚本——这会拖累 Web 应用程序的性能。您只需要保持领先于新用户的速度。例如,您可能有一堆空的 user_standby_1 ... user_standby_100 模式,然后当有人登录或注册时,您将运行以下 sql:

      myquery = "ALTER SCHEMA user_standby_? RENAME TO user_?"; myquery.setString(1,standby_id); myquery.setString(2,user_id);

    3. 当您创建 DB bean 时(为此使用超类,见下文),从 HttpSession 中的 User 对象传递模式名称,然后在每个操作之前执行此 SQL 以将它们仅隔离到它们的模式:

      myquery2 = "SET search_path TO ?";
      myquery2.setString(1,user.search_path);

    4. 如果您在 public 中有一个空的完整架构,那么您希望从搜索路径中省略 public,否则您将在搜索路径中有 2 个同名的表。如果您希望用户搜索路径包含SET search_path TO user_001,public,则在创建表后,从公共中删除除用户和您需要的任何元信息之外的所有数据表。

    5. 为了维护,编写一个可以通过命令行运行的脚本来删除空的 user_standby 模式,创建新的 user_standby 模式,并执行 Rails Migrations for Java 的等效操作以进行较小的表更改。
    6. 对于大型维护活动,最好创建新模式,例如user_v2_001,为每个用户编写脚本以迁移他们的数据。这取决于对表的更改有多复杂。

    如果您采用替代路线并将所有用户数据放在一组表中,那么最好的方法是在 every 表中设置 user_id 并编写 SQL 以使用该 every时间。如果您使用传统规范化并执行连接来获取您的 user_id,那么您最好确保您不会意外错过连接,否则用户将开始看到彼此的数据。

    Postgres 架构功能允许您锁定用户仅访问他们自己的数据。搞清楚基础知识后,使用 Java 中的超类编写上面的步骤 3,这样每个 MyTableDBBean 都从 MasterDBBean 扩展,并使用超类构造函数将搜索路径隔离到用户的模式。然后,您的代码中只有 1 个地方可以完成此操作,并且您不必记住每个表或查询来执行业务逻辑以外的任何操作。

    【讨论】:

    • 非常感谢,基本上补充了ryan1234的回答。谢谢你们。
    【解决方案2】:

    树脂!我已经有一段时间没有听说过 Resin 了,也没有使用过 Resin。 =)

    我在 Stack Overflow 上经常看到让系统的每个用户拥有一个数据库的想法。反应通常是相同的 - 这不是一个好主意。

    有很多原因,但我会坚持规模、可维护性和易变性。

    缩放

    有些数据库对它们可以拥有的数据库数量有限制。我不知道单个 Postgres 实例可以拥有多少个数据库。

    此链接 (https://dba.stackexchange.com/questions/23971/maximum-number-of-databases-for-single-instance-of-postgresql-9) 表示有人在一个实例上拥有 10,000 个数据库。

    我想说,随着时间的推移,一个网站获得一百万用户(当然不是全部活跃)并不少见。换句话说,我敢打赌,您的用户数量会在某个时候破坏 Postgres,每个用户只有一个数据库。

    可维护性

    假设您只需要 10,000 个用户,因此您可以创建 10,000 个数据库。当您想更新每个数据库中的表时会发生什么?推出这些更改很痛苦。

    通常会发生的情况是,您将编写一个脚本来接触每个数据库,即使您对其进行了测试,但脚本在执行到一半时就死掉了,现在您被困在绝望的几分钟里,一半的表处于一种状态,另一半处于其他状态。

    或者更糟糕的是,数据库不同步并且与其他数据库具有不同的架构。现在,您可能拥有多个实时版本的“用户”数据库。

    波动率

    用户是善变的。他们今天会注册,然后就再也不会回来了。他们将注册并在两年后再次登录。他们会因为忘记密码而创建多个帐户。

    这将很快导致孤立的数据库。您需要(或想要)编写一个脚本来定期清理它们。

    此外,一些更现代的数据库(如 MongoDB 和 Couchbase)实际上在创建数据库时会预先分配大部分磁盘/内存。我不相信 Postgres 会这样做,但这是需要考虑的事情。

    安全

    如果有人入侵了您的 Postgres 框,那么按数据库分隔用户对您没有帮助。它们可以在数据库之间移动,就像在表中的记录之间移动一样容易。最好只是很好地锁定数据库机器,然后让用户一起生活在一个表中。它更易于扩展、更易于维护,并且您可以管理波动性。

    【讨论】:

    • 谢谢!!,是的,database-per-user 的主题在堆栈溢出中已被多次触及,您的回答是第一个真正说服我不要那样做的人,但是仍然如何将我的 webApp 扩展到多个用户?我对此的了解非常初级,在我的情况下,WebApp(Cappuccino/Objective-J)没有直接查询数据库,基本上是通过 CP2JAVAWS 使用 javascript 远程 JAVA 方法调用,所以实际的 QUERY 发生在我制作的服务器中对象并将它们作为 JSON 对象发送,(当然这对我来说是透明的)
    猜你喜欢
    • 2010-09-07
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    相关资源
    最近更新 更多