Files
racket-wiki/architecture/pages/performance.md
T

81 lines
5.4 KiB
Markdown

# Verwachte performance op lange termijn
## Status van deze verwachting
De onderstaande schaalinschatting is een architectuuranalyse, geen benchmark. Werkelijke grenzen hangen af van PostgreSQL, netwerkvertraging, documentgrootte, aantallen versies, browser en gelijktijdige gebruikers. Optimaliseer pas na meting met representatieve data.
## Verwacht schaalbeeld
| Omvang | Verwachting met huidige architectuur |
| --- | --- |
| Honderden pagina's, tientallen CMaps | Normale lees-, schrijf- en zoekacties horen ruim voldoende te zijn op een gewone lokale server. |
| Enkele duizenden pagina's, honderden CMaps | Paginaweergave en geïndexeerd paginazoeken blijven waarschijnlijk goed; volledige graph-opbouw, CMap-zoeken, catalogusgrootte en verbindingsopbouw worden zichtbaar. |
| Tienduizenden pagina's of veel grote CMaps | Paginering, server-side graphindex, connectionpooling, geïndexeerd CMap-zoeken en versie-/bijlagebeleid worden waarschijnlijk noodzakelijk. |
Het ontwerp is dus passend voor een persoonlijke of teamwiki. Het is niet zonder aanvullende maatregelen ontworpen als internetbrede kennisbank met zeer veel gelijktijdige gebruikers.
## Sterke performance-eigenschappen
De actuele pagina staat direct in `pages`; voor normaal lezen hoeft geen versiegeschiedenis te worden opgebouwd. Titel en Markdown leveren een opgeslagen gewogen zoekvector met GIN-index. PostgreSQL verwerkt transacties en locking dicht bij de data. De browser ontvangt bij de paginacatalogus alleen metadata en haalt Markdown pas op bij gebruik.
Vendor-assets worden lokaal geserveerd en veranderen niet tijdens normaal gebruik. De browser cachet de opgebouwde navigatiegraaf totdat pagina- of CMapcatalogus opnieuw wordt geladen.
## Belangrijkste toekomstige knelpunten
### Volledige navigatiegraaf
`loadGraphData()` haalt momenteel iedere pagina en iedere CMap sequentieel via een eigen API-request op en extraheert daarna links in de browser. Voor `P` pagina's en `C` CMaps zijn dat `P + C` inhoudsrequests naast de catalogi. Latency groeit daardoor lineair en netwerkvertraging telt herhaaldelijk op.
De duurzame oplossing is een server-side relationele linkindex die in dezelfde schrijftransactie als pagina of CMap wordt bijgewerkt. Een graph-endpoint kan dan alle nodes en edges in één compacte response leveren.
### CMap-zoeken
Paginazoeken gebruikt een opgeslagen index. CMap-zoeken bouwt per query tekst uit JSONB-items en maakt daar op dat moment een `tsvector` van. Bij veel of grote kaarten wordt dit een volledige scan. Voeg dan een opgeslagen zoektekst/`tsvector` en GIN-index aan `concept_maps` toe, bijgewerkt tijdens CMap-opslag.
### Databaseverbindingen
`call-with-wiki-database` opent en sluit voor iedere dienstaanroep een PostgreSQL-verbinding. Dit houdt lifecycle en foutisolatie eenvoudig, maar connection setup wordt bij hogere requestfrequentie overhead. Een begrensde connectionpool is dan logischer dan één globale verbinding. Meet eerst connecttijd, querytijd en gelijktijdigheid afzonderlijk.
### Catalogi
`list-pages` en `list-concept-maps` leveren alle huidige metadata. Dat is prettig voor client-side navigatie, WikiWords en comboboxen. Bij tienduizenden objecten worden responsegrootte, browsergeheugen en sorteren merkbaar. Mogelijke vervolgstappen zijn server-side paginering, een compacte referentiecatalogus en lazy loading per namespace.
### Volledige versies
Iedere pagina- en CMapsave bewaart een volledige snapshot. Opslag groeit lineair; CMap-autosave kan veel bijna gelijke JSONB-documenten opleveren. Meet per object het aantal versies, bytes en savefrequentie. Een later beleid kan oude autosaves uitdunnen terwijl expliciete snapshots en betekenisvolle saves blijven bestaan. Zo'n beleid vereist eerst een expliciete bewaargarantie en back-up.
### Bijlagen
Bijlagebytes staan in PostgreSQL en worden volledig in geheugen gelezen voor de response. Stel een maximale uploadgrootte in voordat grote media worden ondersteund. Voor echt grote objecten zijn streaming of een object store mogelijk, maar dat verandert back-up, autorisatie en referentiebeheer en is dus geen kleine optimalisatie.
### Browserrendering
Grote CMaps tekenen veel DOM/SVG-objecten en connectors. Volledige maps en graphs hebben uiteindelijk layoutkosten die niet met een snellere database verdwijnen. Meet nodeaantal, rendertijd en interactieframes. Sub-CMaps, viewportculling of vereenvoudigde read-only rendering zijn dan gerichte opties.
## Meetplan
Voeg vóór optimalisatie minimaal deze metingen toe:
- requestduur per endpoint en responsebytes;
- connecttijd versus SQL-tijd;
- aantallen pagina's, CMaps, graph-edges en versies;
- gemiddelde en p95 Markdown-, JSONB- en bijlagegrootte;
- tijd voor volledige graph-opbouw;
- tijd voor CMap-zoekquery's;
- browserrendertijd bij representatieve CMaps.
Gebruik datasets met echte linkdichtheid en documentgroottes. Duizend lege pagina's voorspellen het gedrag van duizend technische documenten niet.
## Optimalisatievolgorde
De verwachte volgorde bij groei is:
1. graph-edges tijdens opslag indexeren en in één request leveren;
2. CMap-zoekvector opslaan en indexeren;
3. databaseconnectionpool toevoegen;
4. catalogi pagineren of per namespace laden;
5. expliciet versie- en uploadbeleid ontwerpen;
6. pas daarna horizontale of servicegerichte architectuur overwegen.
Deze volgorde behoudt de eenvoud van [Structuur en samenhang](racket-wiki:structuur-en-samenhang) zolang die nog waardevol is.