googleapis / googleapis/google-cloud-python
docs(spanner): document behavioral differences between regular and multiplexed sessions
- Ngôn ngữ chính
- Python
- Star
- 5.4k
- Fork
- 1.8k
- Merge trung bình
- 3 ngày 4 giờ
- Pull request đã merge (30 ngày)
- 122
Mô tả
## Summary
The Python Spanner client library (`google-cloud-spanner`) added multiplexed session support across PRs #1381, #1383, #1389, and #1394, and made them default-enabled in v3.57.0+.
There is currently no documentation in the library's `docs/` RST pages, README, or `advanced-session-pool-topics.rst` covering the behavioral differences between regular and multiplexed sessions. The references that exist are autogenerated protobuf docstrings and CHANGELOG entries.
The following was verified via REST API testing and source code inspection against `google-cloud-spanner` v3.63.0 on 2026-04-11.
## Behavioral Differences
| Property | Regular Session | Multiplexed Session |
|---|---|---|
| Concurrent transactions | 1 per session | N per session (routed by transaction\_id) |
| Labels | Supported | Server returns 400 INVALID\_ARGUMENT: Labels are not supported in multiplexed sessions |
| Session ID length | 62 chars | 68 chars |
| `multiplexed` field in CreateSession response | Absent | `"multiplexed": true` |
| OTel span name on create | CloudSpanner.CreateSession | CloudSpanner.CreateMultiplexedSession |
| Delete via API | DeleteSession returns 200 OK | DeleteSession returns 400 |
| Lifecycle | Client-managed — create, ping, delete | Auto-rotated every 7 days by library maintenance thread; no keep-alive needed |
| Idle timeout | ~60 min (server GC) | Long-lived, no idle timeout |
| Pool integration | Checked out/in from SessionPool | Singleton per DatabaseSessionsManager; never pooled |
| Pre-commit token | Not used | Required — server sends token with each query/DML; must be included in CommitRequest |
| Mutation-only transactions | Begin normally | Library prepends SELECT 1 to obtain pre-commit token |
| Previous transaction ID | Not used | multiplexed\_session\_previous\_transaction\_id passed in BeginTransactionRequest |
| Batch creation | BatchCreateSessions supported | BatchCreateSessions cannot create multiplexed sessions |
| Visibility in ListSessions | **Visible** | **Not returned** — server excludes multiplexed sessions from listing |
## How the server distinguishes them
The client sets `session.multiplexed = True` in the `CreateSessionRequest` protobuf:
```python
# google/cloud/spanner_v1/session.py, lines 173-179
create_session_request = CreateSessionRequest(database=database.name)
if self._labels:
create_session_request.session.labels = self._labels
if self._is_multiplexed:
create_session_request.session.multiplexed = True
```
`labels` and `multiplexed` are set independently. There is no client-side guard against setting both. The server enforces the restriction.
## API verification
### Test 1 — Regular session with labels
```bash
curl -X POST "https://spanner.googleapis.com/v1/projects/PROJECT/instances/INSTANCE/databases/DB/sessions" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d '{ "session": { "labels": {"env":"test", "pod":"test-pod", "service":"test-svc"} } }'
```
Response: `200 OK`
```json
{
"name": "projects/.../sessions/AMkeXgpXcn6_fz0Gn3Yrf285Y35OgcWE8z0DZGZ3IaUN9aUVTMC8bLudNLUAiA",
"labels": { "service": "test-svc", "pod": "test-pod", "env": "test" },
"createTime": "2026-04-11T19:35:48.946415Z",
"approximateLastUseTime": "2026-04-11T19:35:48.948744Z"
}
```
### Test 2 — Multiplexed session with labels
```bash
curl -X POST ".../sessions" \
-d '{ "session": { "labels": {"env":"test"}, "multiplexed": true } }'
```
Response: `400 INVALID_ARGUMENT`
```json
{
"error": {
"code": 400,
"message": "Labels are not supported in multiplexed sessions",
"status": "INVALID_ARGUMENT"
}
}
```
### Test 3 — Multiplexed session without labels
```bash
curl -X POST ".../sessions" \
-d '{ "session": { "multiplexed": true } }'
```
Response: `200 OK`
```json
{
"name": "projects/.../sessions/AMkeXgrSFuqnRwBCAsbKWtQZ3-8idoYHiXuCNzkbTKOVdcZ7tApRmh6_0ORRXirCXO5b",
"createTime": "2026-04-11T19:36:06.805225Z",
"multiplexed": true
}
```
Note: Session ID is 68 chars vs 62 for the regular session in Test 1.
### Test 4 — Delete behavior
| Target | DeleteSession result | Notes |
|---|---|---|
| Regular session | 200 OK | Deleted |
| Multiplexed session | 400 | Cannot be manually deleted; server manages lifecycle |
### Test 5 — ListSessions visibility
A multiplexed session created via `CreateSession` (confirmed by `"multiplexed": true` in the response) does **not** appear in subsequent `ListSessions` results — neither via the REST API nor `gcloud spanner databases sessions list`.
This is consistent with the protobuf docstring on the `Session` message: *"You can't delete or list multiplexed sessions."*
```bash
# Create a multiplexed session
MUX_ID=$(curl -s -X POST ".../sessions" \
-d '{ "session": { "multiplexed": true } }' | python3 -c "import json,sys; print(json.load(sys.stdin)['name'].split('/')[-1])")
# Try to find it in ListSessions
curl -s ".../sessions?pageSize=500" | python3 -c "
import json, sys
sessions = json.load(sys.stdin).get('sessions', [])
found = any(s['name'].endswith('$MUX_ID') for s in sessions)
print(f'Found in ListSessions: {found}') # prints: False
"
```
**Implication**: The only server-side way to observe multiplexed sessions is through the built-in OTel metrics with the `is_multiplexed` attribute filter. There is no Admin API method to enumerate active multiplexed sessions.
## Library architecture
### Regular session flow
```
SessionPool (PingingPool, TransactionPingingPool, etc.)
├── N sessions pre-created at pool init (via BatchCreateSessions)
├── get() → checks out a Session for 1 transaction
├── put() → returns Session to pool
└── ping() → periodic keep-alive SELECT 1 to prevent idle GC
```
### Multiplexed session flow
```
DatabaseSessionsManager
├── 1 multiplexed Session singleton (created on first use via CreateSession)
├── get_session() → returns the same Session for all transaction types
├── put_session() → no-op (session is never returned to a pool)
└── maintenance thread:
├── polls every 10 minutes
└── recreates session every 7 days (rotation)
```
### Transaction protocol differences
Regular sessions: each `Session.run_in_transaction()` uses a dedicated session. Concurrent transactions require separate sessions from the pool.
Multiplexed sessions: all concurrent transactions share one session. The server routes them by `transaction_id`. Additional protocol requirements:
- **Pre-commit token**: Server returns a token with each query/DML. The client must include it in `CommitRequest`. For mutation-only transactions (no prior query/DML), the library prepends `SELECT 1` to obtain a token.
- **Previous transaction ID**: `multiplexed_session_previous_transaction_id` is passed in `ReadWrite` transaction options for server-side ordering of transactions on the same multiplexed session.
## Environment variables
| Variable | Default (v3.57.0+) | Controls |
|---|---|---|
| GOOGLE\_CLOUD\_SPANNER\_MULTIPLEXED\_SESSIONS | true | Read-only transactions use multiplexed sessions |
| GOOGLE\_CLOUD\_SPANNER\_MULTIPLEXED\_SESSIONS\_FOR\_RW | true | Read-write transactions use multiplexed sessions |
| GOOGLE\_CLOUD\_SPANNER\_MULTIPLEXED\_SESSIONS\_PARTITIONED\_OPS | false | Partitioned operations use multiplexed sessions |
Setting any to `"false"` falls back to pool-based regular sessions for that transaction type. `DatabaseSessionsManager._use_multiplexed()` reads these at runtime via `os.getenv()` with a default of `"true"`.
## Built-in OTel metrics
Spanner's built-in client metrics include an `is_multiplexed` attribute (see [Spanner docs: View traffic for regular and multiplexed sessions](https://cloud.google.com/spanner/docs/sessions#view_traffic_for_regular_and_multiplexed_sessions)). This can be used in Metrics Explorer to filter between session types. The built-in metrics can be disabled with `SPANNER_DISABLE_BUILTIN_METRICS=true`.
## Request
Add documentation covering the differences listed above. This could be a new RST page (e.g. `docs/multiplexed-sessions.rst`) or an addition to `advanced-session-pool-topics.rst`.
## Environment
- `google-cloud-spanner` v3.63.0
- Python 3.10
Hướng dẫn đóng góp
Đánh giá
Issue này chưa được đánh giá.