Verbindingspooling met mssql-python

Connection pooling verbetert de applicatieprestaties door databaseverbindingen opnieuw te gebruiken in plaats van nieuwe te maken voor elk verzoek. Het openen van een verbinding vereist meerdere tijdrovende stappen:

  • De driver stelt een netwerksocket op.
  • De bestuurder voltooit de TLS-handdruk.
  • De driver authenticeert zich bij de server.
  • De driver valideert verbindingsparameters.

Connection pooling houdt verbindingen open en beschikbaar voor hergebruik, zodat je app deze stappen niet per verzoek hoeft te herhalen.

Standaardgedrag

Connection pooling is standaard ingeschakeld wanneer je je eerste verbinding aanmaakt. De standaardinstellingen zijn:

Configuratie Standaardwaarde Beschrijving
max_size 100 Maximale verbindingen per unieke verbindingsreeks.
idle_timeout 600 seconden (10 minuten) Aantal seconden voordat de inactieve verbindingen worden gesloten.
import mssql_python

# Pooling is automatically enabled with defaults
conn = mssql_python.connect(connection_string)

Groepsgewijze verbindingen configureren

Configureer pooling voordat je verbindingen maakt:

import mssql_python

# Configure custom pool settings
mssql_python.pooling(max_size=50, idle_timeout=300)

# Now create connections
conn = mssql_python.connect(connection_string)

Parameters

De pooling() functie accepteert de volgende parameters:

Parameter Type Default Beschrijving
max_size int 100 Maximaal aantal gepoolde verbindingen per verbindingsreeks.
idle_timeout int 600 Aantal seconden voordat inactieve verbindingen uit de pool worden verwijderd.
enabled bool True Schakel pooling in of uit.

Schakel verbindingspooling uit

Om pooling uit te schakelen, roep je pooling() aan met enabled=False voordat je verbindingen maakt:

import mssql_python

mssql_python.pooling(enabled=False)

# Connections are now created and destroyed per use
conn = mssql_python.connect(connection_string)

Opmerking

Stel de poolconfiguratie in voordat je verbindingen maakt. Bellen pooling() na het maken van verbindingen heeft geen effect.

Hoe pooling werkt

Isolatie van verbindingsreeksen

Elke unieke verbindingsreeks onderhoudt zijn eigen onafhankelijke pool. Pools delen geen verbindingen over verschillende verbindingsstrings:

# These use separate pools
conn1 = mssql_python.connect("Server=<server1>;Database=<database1>;...")
conn2 = mssql_python.connect("Server=<server2>;Database=<database2>;...")

Levenscyclus van de verbinding

Acquire (een verbinding krijgen):

  1. De pool verwijdert verlopen (tijdens inactiviteit verlopen) verbindingen.
  2. De pool probeert een bestaande verbinding te hergebruiken:
    • Het controleert of de verbinding actief is.
    • Het reset de verbindingsstatus.
    • Als beide checks slagen, geeft hij de verbinding terug.
  3. Als er geen herbruikbare verbinding beschikbaar is en de pool onder de limiet van max_size blijft, maakt het stuurprogramma een nieuwe verbinding aan.
  4. Als de pool vol is zonder geldige verbindingen, geeft de driver een foutmelding.

Loslaten (verbinding teruggeven):

  1. Als het zwembad capaciteit heeft, slaat het de verbinding op voor hergebruik.
  2. Als de pool op max_sizestaat, sluit de driver de verbinding onmiddellijk.

Statuscontroles van verbindingen

De driver voert verbindingsgezondheidscontroles uit voordat een gepoolde verbinding opnieuw wordt gebruikt.

  1. Alive check: Zorgt ervoor dat de netwerkverbinding nog geldig is.
  2. Resetcontrole: Reset sessiestatus (isolatieniveau, instellingen) voor schoon hergebruik.

Als een van de checks faalt, verwijdert de pool de verbinding en maakt een nieuwe aan.

Automatische schoonmaak

  • Idle timeout: De driver sluit verbindingen die langer ongebruikt zijn dan de idle_timeout waarde.
  • Proces afsluiten: Een atexit handler sluit alle gepoolde verbindingen wanneer het Python-proces afsluit.

Beste praktijken

Bepaal je zwembad op de juiste manier

Stem de grootte van je pool af op de gelijktijdigheid van je applicatie.

# For a web application with 20 concurrent requests
mssql_python.pooling(max_size=25)  # Slightly more than expected concurrency

Gebruik contextmanagers

Contextmanagers zorgen ervoor dat je de verbindingen correct teruggeeft aan de pool.

with mssql_python.connect(connection_string) as conn:
    cursor = conn.cursor()
    cursor.execute("SELECT TOP 5 Name, ListPrice FROM Production.Product")
    rows = cursor.fetchall()
# Connection returned to pool

Houd verbindingsreeksen consistent

Verschillende parameters in verbindingsstrings creëren aparte pools.

# These create THREE separate pools (inefficient)
conn1 = mssql_python.connect("Server=<server>;Database=<database>;Encrypt=yes;")
conn2 = mssql_python.connect("SERVER=<server>;DATABASE=<database>;ENCRYPT=yes;")  # Different case
conn3 = mssql_python.connect("Server=<server>;Database=<database>;Encrypt=yes;", timeout=30)  # Extra parameter

# Use a constant connection string instead
CONNECTION_STRING = "Server=<server>;Database=<database>;Encrypt=yes;"
conn1 = mssql_python.connect(CONNECTION_STRING)
conn2 = mssql_python.connect(CONNECTION_STRING)  # Same pool

Houd rekening met verbindingslimieten van Azure SQL

Azure SQL Database handhaaft verbindingslimieten op basis van de serviceniveau. De volgende waarden zijn benaderbaar; Bekijk de gekoppelde documentatie voor de huidige limieten:

Serviceniveau Maximum aantal gelijktijdige verbindingen
Basic 30
Standaard S0-S2 60-120
Standaard S3 en latere versies 200
Premium 500

Bepaal je max_size waarde onder deze limieten.

# For Azure SQL Standard S2 (120 limit)
mssql_python.pooling(max_size=100)  # Leave headroom

Pas de time-out voor inactiviteit van je workload aan

  • Frequente verbindingen: Gebruik een langere idle_timeout waarde om de verbindingen warm te houden.
  • Sporadische verbindingen: Gebruik een kortere idle_timeout waarde om middelen vrij te geven.
# High-frequency API: keep connections warm
mssql_python.pooling(idle_timeout=1800)  # 30 minutes

# Batch job running every hour: release between runs
mssql_python.pooling(idle_timeout=60)  # 1 minute

Limitations

De huidige implementatie heeft enkele beperkingen ten opzichte van andere drivers:

Feature Status
ClearPool() / ClearAllPools() Niet beschikbaar.
Poolstatistieken/monitoring Niet beschikbaar.
Pooloverschrijving per verbinding Niet beschikbaar.
Minimale zwembadgrootte Kan niet worden geconfigureerd.

Voorbeeld: Webapplicatiepatroon

Het volgende Flask-voorbeeld laat zien hoe verbindingen transparant worden gepoold over verzoeken:

import mssql_python
from flask import Flask, g

app = Flask(__name__)

# Configure pooling at startup
mssql_python.pooling(max_size=20, idle_timeout=300)

def get_db():
    if 'db' not in g:
        g.db = mssql_python.connect(app.config['DATABASE_URL'])
    return g.db

@app.teardown_appcontext
def close_db(error):
    db = g.pop('db', None)
    if db is not None:
        db.close()  # Returns to pool

@app.route('/products')
def list_products():
    conn = get_db()
    cursor = conn.cursor()
    cursor.execute("SELECT TOP 5 Name, ListPrice FROM Production.Product")
    return cursor.fetchall()

Herken uitputting van de pool

Wanneer alle aansluitingen in het zwembad in gebruik zijn en je vraagt om een nieuwe aansluiting, zie je symptomen zoals:

  • Verbindingen hangen of lopen uit terwijl ze wachten op een gratis verbinding.
  • De applicatiedoorvoer daalt plotseling onder belasting.
  • Het geheugengebruik stijgt naarmate de driver verbindingen maakt die hij niet kan hergebruiken.

Veelvoorkomende oorzaken:

  • Verbindingen worden niet teruggegeven aan het zwembad. Sluit altijd de connecties als je klaar bent, of gebruik contextmanagers. Een verbinding die niet gesloten is, blijft gecontroleerd.
  • Het zwembad is te klein voor de werkdruk. Als je 50 gelijktijdige verzoeken hebt, maar max_size=20, wachten 30 verzoeken.
  • Langlopende zoekopdrachten houden verbindingen. Breek lange operaties op of gebruik speciale verbindingen voor batchwerk.

Zo lost u dit op:

# 1. Always use context managers to guarantee return
with mssql_python.connect(connection_string) as conn:
    cursor = conn.cursor()
    cursor.execute("SELECT ...")
    rows = cursor.fetchall()
# Connection returned to pool here, even if an exception occurs

# 2. Size the pool to match your concurrency
mssql_python.pooling(max_size=50)  # Match or slightly exceed expected concurrent connections

# 3. Reduce idle timeout if connections go stale
mssql_python.pooling(idle_timeout=120)