9

Nota: so di thread this ma è piuttosto vecchio e inoltre, la soluzione non ha funzionato per me.Pool di connessione JDBC compatibile con App Engine

Sto utilizzando App Engine insieme a Cloud SQL e vorrei condividere un pool di connessioni aperte tra tutti gli utenti correnti dell'applicazione. Ho provato diverse implementazioni di pool di connessioni e funzionano tutte perfettamente con il server di sviluppo locale, tuttavia, quando vengono implementate nel cloud, falliscono. Suppongo che la ragione sia l'ambiente "sandbox" ristretto di App Engine. Qualcuno sa del pool di connessioni JDBC che funziona su App Engine?

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 Connection Pool

... 
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) 
... 
+0

visto su alcune altre questioni che StackOverflow HikariCP supporta personalizzato ThreadManager, in modo da poter creare discussioni con ThreadManager whitelist di GAE. –

risposta

2

Probabilmente non è necessario il pool di connessioni a tutti:

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

... se il tempo per creare una nuova connessione riguarda il come per il test se una connessione esistente è attiva e riusandola, allora raccomandiamo che si crei una nuova connessione per servire ogni richiesta HTTP, e riutilizzarla per la durata della richiesta. In particolare, quest'ultimo caso può essere applicabile quando ci si connette da Google App Engine a Google Cloud SQL.

+1

Sì, lo so. Tuttavia, ogni istanza di App Engine non può avere più di 12 connessioni simultanee a un'istanza di Cloud SQL e questo è un altro motivo per avere un pool di connessioni poiché tiene traccia delle connessioni attive e se non ce ne sono disponibili, blocca fino a quando uno è disponibile o volte su. Altrimenti finirei con un errore. – pgiecek

+2

Per quanto ne so, Java GAE, per impostazione predefinita, invia solo 10 richieste simultanee all'istanza, pertanto 12 connessioni db simultanee dovrebbero essere corrette. – Christiaan

+0

Un potenziale problema è che Google ha una quota giornaliera di connessioni socket che un'app può utilizzare. Senza la condivisione diventa più facile raggiungere tale limite e improvvisamente la tua app non può connettersi al database. Il limite è molto alto quindi potresti non colpirlo mai, ma se fai gli effetti sono notevoli. – depsypher

3

Ho dovuto utilizzare Tomcat DBCP 1.4 (versione precedente), a causa del frontend GAE che non consente ai thread di vivere al di fuori dell'ambito della richiesta. Ecco un esempio di progetto: https://github.com/kennberg/appengine-java-connection-pool

Si noti che il pool di connessioni è necessario quando si hanno troppe richieste, poiché esiste un limite al numero di connessioni in sospeso per istanza. Il riutilizzo delle connessioni aiuta a rimanere sotto il limite.

+0

Sì, ogni istanza GAE ha un limite di 12 connessioni. Sembra molto basso .. – cfl

+0

Grazie Alex, stavo usando la versione 2.x e non riesco a capire qual è il motivo. Lo ha declassato a 1.4 e ha funzionato come un fascino. – Jay

0

È possibile che si ottenga AccessControlException perché l'applicazione è impostata su "Ridimensionamento automatico".

Un tempo un'app di GAE poteva essere un "backend" o un "frontend" e solo i backend potevano utilizzare thread in background. Ora con i backend deprecati e sostituiti con i moduli, l'uso dei thread in background è legato al tipo di ridimensionamento dell'app.

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