【问题标题】:JDBC connection pool compatible with App Engine与 App Engine 兼容的 JDBC 连接池
【发布时间】:2015-01-06 14:20:48
【问题描述】:

注意:我知道 this 线程,但它已经很老了,而且该解决方案对我不起作用。

我正在使用 App Engine 和 Cloud SQL,我想在应用程序的所有当前用户之间共享一个开放连接池。我尝试了几种连接池实现,它们都可以与本地开发服务器完美配合,但是,当部署到云时,它们会失败。我想原因是 App Engine 受限的“沙盒”环境。有人知道在 App Engine 上工作的 JDBC 连接池吗?

Apache Commons DBCP

...
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.commons.dbcp2.PoolableConnection
at com.google.appengine.runtime.Request.process-a49d46300800d0ca(Request.java)
at org.apache.commons.dbcp2.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:254)
at org.apache.commons.dbcp2.BasicDataSource.validateConnectionFactory(BasicDataSource.java:2162)
at org.apache.commons.dbcp2.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:2148)
at org.apache.commons.dbcp2.BasicDataSource.createDataSource(BasicDataSource.java:1903)
at org.apache.commons.dbcp2.BasicDataSource$PaGetConnection.run(BasicDataSource.java:2267)
at org.apache.commons.dbcp2.BasicDataSource$PaGetConnection.run(BasicDataSource.java:2263)
at java.security.AccessController.doPrivileged(AccessController.java:63)
at org.apache.commons.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1404)
...

Tomcat JDBC 连接池

...
Caused by: java.lang.SecurityException: Unable to get members for class org.apache.tomcat.jdbc.pool.DataSource

...

Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
... 45 more
Caused by: java.lang.NoClassDefFoundError: javax/management/MalformedObjectNameException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2517)
... 45 more
Caused by: java.lang.ClassNotFoundException: javax.management.MalformedObjectNameException
... 45 more

HikariCP

...
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:375)
at java.security.AccessController.checkPermission(AccessController.java:565)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.ThreadGroup.checkAccess(ThreadGroup.java:315)
at java.lang.Thread.init(Thread.java:378)
at java.lang.Thread.<init>(Thread.java:527)
at com.zaxxer.hikari.util.DefaultThreadFactory.newThread(DefaultThreadFactory.java:32)
at java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor.java:591)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:922)
at java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1591)
at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:305)
at java.util.concurrent.ScheduledThreadPoolExecutor.scheduleAtFixedRate(ScheduledThreadPoolExecutor.java:542)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:161)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:114)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:102)
...

Vibur DBCP

...
Caused by: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:375)
at java.security.AccessController.checkPermission(AccessController.java:565)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.ThreadGroup.checkAccess(ThreadGroup.java:315)
at java.lang.Thread.init(Thread.java:378)
at java.lang.Thread.<init>(Thread.java:448)
at org.vibur.objectpool.reducer.SamplingPoolReducer.<init>(SamplingPoolReducer.java:78)
at org.vibur.dbcp.pool.PoolOperations$PoolReducer.<init>(PoolOperations.java:88)
at org.vibur.dbcp.pool.PoolOperations$PoolReducer.<init>(PoolOperations.java:86)
at org.vibur.dbcp.pool.PoolOperations.<init>(PoolOperations.java:79)
at org.vibur.dbcp.ViburDBCPDataSource.start(ViburDBCPDataSource.java:197)
....

c3p0

...
Caused by: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:375)
at java.security.AccessController.checkPermission(AccessController.java:565)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.ThreadGroup.checkAccess(ThreadGroup.java:315)
at java.lang.Thread.init(Thread.java:378)
at java.lang.Thread.<init>(Thread.java:487)
...

【问题讨论】:

  • 在其他一些 stackoverflow 问题上看到 HikariCP 支持自定义 ThreadManager,因此您可以使用 GAE 的白名单 ThreadManager 创建线程。

标签: java google-app-engine jdbc connection-pooling google-cloud-sql


【解决方案1】:

您可能会收到 AccessControlException,因为您的应用程序设置为“自动缩放”。

过去,GAE 应用程序可以是“后端”或“前端”,并且只有后端可以使用后台线程。现在不推荐使用后端并替换为模块,后台线程的使用与应用程序的缩放类型相关。

https://cloud.google.com/appengine/docs/java/modules/#Java_Background_threads

【讨论】:

    【解决方案2】:

    我不得不使用 Tomcat DBCP 1.4(旧版本),因为 GAE 前端不允许线程存在于请求范围之外。这是一个示例项目: https://github.com/kennberg/appengine-java-connection-pool

    请注意,一旦您有太多请求,连接池是必需的,因为每个实例的挂起连接数是有限制的。重复使用连接有助于保持在限制范围内。

    【讨论】:

    • 感谢 Alex,我使用的是 2.x 版本,但不知道是什么原因。将其降级到 1.4,它就像魅力一样工作。
    【解决方案3】:

    您可能根本不需要连接池:

    https://cloud.google.com/sql/faq#connections

    ...如果创建新连接的时间与测试 if 的时间大致相同 现有连接处于活动状态并重用它,那么我们建议 您创建一个新连接来服务每个 HTTP 请求,并重用它 在请求期间。特别是,后一种情况可能 当您从 Google App Engine 连接到 Google Cloud SQL 时应用。

    【讨论】:

    • 是的,我知道。但是,每个 App Engine 实例与 Cloud SQL 实例的并发连接不能超过 12 个,这是拥有连接池的另一个原因,因为它会跟踪活动连接,如果没有可用连接,它会阻塞直到有一个可用或次出去。否则我会报错。
    • 据我所知,Java GAE 默认只向您的实例发送 10 个并发请求,因此 12 个并发数据库连接应该没问题。
    • 一个潜在的问题是谷歌有一个应用程序可以使用的套接字连接的每日配额。如果不进行池化,则更容易达到该限制,并且您的应用程序突然无法连接到数据库。限制非常高,因此您可能永远不会达到它,但如果您这样做,效果会很明显。
    • 如何最好地管理您的数据库连接取决于您的用例,但一般来说,我们建议使用连接池。池将保护数据库服务器免受过快创建的大量新连接的影响,这会影响性能。在云托管环境中,您管理数据库连接的方式应不同于在传统的外部服务器环境中管理它们。我们建议您通过实施指数退避等错误处理策略来设计应用程序以处理偶发的连接故障。
    • @I.Tyger 已粘贴该链接中的最新文本,这不再推断 GAE + CloudSQL 可能不需要连接池。我确实找到了cloud.google.com/sql/docs/mysql/connect-app-engine,上面写着“对于 App Engine 标准环境,App Engine 实例可以打开到 Cloud SQL 的连接数有硬性限制。如果您的应用程序需要更多打开的连接,请考虑使用连接池。”
    猜你喜欢
    • 1970-01-01
    • 2011-12-05
    • 2021-01-22
    • 2017-06-19
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    相关资源
    最近更新 更多