sql >> Databasteknik >  >> RDS >> PostgreSQL

Hantera Connection Pooling i multi-tenant webbapp med Spring, Hibernate och C3P0

Du kan välja mellan 3 olika strategier som kommer att påverka anslutningsundersökningar. I vilket fall som helst måste du tillhandahålla en implementering av MultiTenantConnectionProvider . Strategin du väljer kommer naturligtvis att påverka din implementering.

Allmän anmärkning om MultiTenantConnectionProvider.getAnyConnection()

getAnyConnection() krävs av hibernate för att samla in metadata och ställa in SessionFactory. Vanligtvis i en multi-tenant-arkitektur har du en speciell/masterdatabas (eller schema) som inte används av någon hyresgäst. Det är en slags malldatabas (eller schema). Det är ok om den här metoden returnerar en anslutning till den här databasen (eller schemat).

Strategi 1 :varje hyresgäst har sin egen databas. (och så det är en egen anslutningspool)

I det här fallet har varje hyresgäst sin egen anslutningspool som hanteras av C3PO och du kan tillhandahålla en implementering av MultiTenantConnectionProvider baserat på AbstractMultiTenantConnectionProvider

Varje hyresgäst har sin egen C3P0ConnectionProvider , så allt du behöver göra i selectConnectionProvider(tenantIdentifier) är att returnera den korrekta. Du kan behålla en karta för att cache dem och du kan lata-initiera en C3POConnectionProvider med något som :

private ConnectionProvider lazyInit(String tenantIdentifier){
    C3P0ConnectionProvider connectionProvider = new C3P0ConnectionProvider();
    connectionProvider.configure(getC3POProperties(tenantIdentifier));
    return connectionProvider;
}

private Map getC3POProperties(String tenantIdentifier){
    // here you have to get the default hibernate and c3po config properties 
    // from a file or from Spring application context (there are good chances
    // that those default  properties point to the special/master database) 
    // and alter them so that the datasource point to the tenant database
    // i.e. : change the property hibernate.connection.url 
    // (and any other tenant specific property in your architecture like :
    //     hibernate.connection.username=tenantIdentifier
    //     hibernate.connection.password=...
    //     ...) 
}

Strategi 2 :varje hyresgäst har sitt eget schema och sin egen anslutningspool i en enda databas

Det här fallet är mycket likt den första strategin angående ConnectionProvider implementering eftersom du också kan använda AbstractMultiTenantConnectionProvider som basklass för att implementera din MultiTenantConnectionProvider

Implementeringen är mycket lik den föreslagna implementeringen för Strategi 1 förutom att du måste ändra schemat istället för databasen i c3po-konfigurationen

Strategi 3 :varje hyresgäst har sitt eget schema i en enda databas men använder en delad anslutningspool

Det här fallet är något annorlunda eftersom varje hyresgäst kommer att använda samma anslutningsleverantör (och så anslutningspoolen kommer att delas). I fallet:anslutningsleverantören måste ställa in schemat för användning innan anslutningen används. du måste implementera MultiTenantConnectionProvider.getConnection(String tenantIdentifier) (dvs. standardimplementeringen som tillhandahålls av AbstractMultiTenantConnectionProvider fungerar inte).

Med postgresql kan du göra det med :

 SET search_path to <schema_name_for_tenant>;

eller använda aliaset

 SET schema <schema_name_for_tenant>;

Så här är vad din getConnection(tenant_identifier); kommer att se ut så här:

@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
    final Connection connection = getAnyConnection();
    try {
        connection.createStatement().execute( "SET search_path TO " + tenanantIdentifier );
    }
    catch ( SQLException e ) {
        throw new HibernateException(
                "Could not alter JDBC connection to specified schema [" +
                        tenantIdentifier + "]",
                e
        );
    }
    return connection;
}

Användbar referens finns här (officiellt dokument)

Annan användbar länk C3POConnectionProvider.java

Du kan kombinera strategi 1 och strategi 2 i din implementering. Du behöver bara ett sätt att hitta rätt anslutningsegenskaper/anslutnings-url för den aktuella hyresgästen.

REDIGERA

Jag tror att valet mellan strategi 2 eller 3 beror på trafiken och antalet hyresgäster på din app. Med separata anslutningspooler:antalet tillgängliga anslutningar för en hyresgäst kommer att vara mycket lägre och så:om en hyresgäst av någon legitim anledning plötsligt behöver många anslutningar kommer prestandan för just denna hyresgäst att minska drastiskt (medan den andra hyresgästen inte kommer att vara påverkas).

Å andra sidan, med strategi 3, om en hyresgäst av någon legitim anledning plötsligt behöver många kontakter:prestanda som varje hyresgäst ser kommer att minska.

Generellt sett tror jag att strategi 2 är mer flexibel och säker:varje hyresgäst kan inte konsumera mer än en given mängd anslutning (och detta belopp kan konfigureras per hyresgäst om du behöver det)



  1. Gruppera data med OVER- och PARTITION BY-funktionerna

  2. Bygga en mycket tillgänglig databas för Moodle med MariaDB (replikering och MariaDB-kluster)

  3. Hur man ändrar standarddatabaspostprofilen för en användare i SQL Server (T-SQL)

  4. GET_FORMAT() Exempel – MySQL