docs: correct the places where documents contradicted their own evidence
An independent audit found ten documents printing values their evidence files do not contain. C-1 printed a session count of 0 where the evidence says 4, C-2 printed a success readback for a command that exited 1, and A-1 credited the conntrack flush with a split that the timestamps attribute to a pod restart four seconds earlier. Also measured wal_writer_delay, which A-3 had asserted as matching without ever querying it, relabelled the A-6 control that moved 41 percent, noted A-8's nine-sample resolution, corrected D-1's RTO to the 41 seconds its own timeline shows, and added a correction banner to D-2. Every experiment document now links its evidence files with their real collection times, and the duplicate screenshots are documented as duplicates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
78b270559c
commit
e0d27d47ce
@@ -19,3 +19,88 @@
|
|||||||
[ 179100ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
[ 179100ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
[ 187598ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
[ 187598ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
[ 207362ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
[ 207362ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 213255ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 230544ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 248833ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 257549ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 262324ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 274443ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 294124ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 310689ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 312049ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 327025ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 339933ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 342391ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 362305ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 370693ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 378685ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 397930ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 414007ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 419130ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 420355ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 428557ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 442088ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 445041ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 446677ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 460087ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 462505ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 463673ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 482762ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 495123ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 513442ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 516414ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 536581ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 543441ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 563624ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 580510ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 588408ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 594209ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 604166ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 605295ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 621987ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 639705ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 653320ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 660911ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 678105ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 693662ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 703089ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 704712ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 719727ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 725514ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 730429ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 735135ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 736677ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 751626ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 767197ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 782052ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 797775ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 803343ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 822168ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 828683ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 845938ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 865903ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 883116ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 894375ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 898471ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 914886ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 933184ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 953353ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 963902ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 982846ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 998975ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1000721ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1003229ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1009879ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1016334ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1023805ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1043684ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1049467ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1059107ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1075856ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1076956ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1094159ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1102825ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1116077ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1134809ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1136553ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
[ 1141191ms] [ERROR] WebSocket connection to 'wss://app2.hyeonworks.com/api/live/ws' failed: Error during WebSocket handshake: Unexpected response code: 400 @ https://app2.hyeonworks.com/public/build/1518.a3f1f690c084a37f01c7.js:362
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
=== A-3 이 가정만 하고 재지 않은 값 ===
|
||||||
|
name | setting | unit | source
|
||||||
|
------------------------+---------+------+---------
|
||||||
|
commit_delay | 0 | | default
|
||||||
|
synchronous_commit | on | | default
|
||||||
|
wal_writer_delay | 200 | ms | default
|
||||||
|
wal_writer_flush_after | 128 | 8kB | default
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# 주의 — 이 파일은 원 실험 시점에 0바이트로 저장됐다.
|
||||||
|
# 리다이렉션이 stdout 만 받았는데 출력이 stderr 로 갔거나 tee 앞 파이프가
|
||||||
|
# 비어 있었던 것으로 보인다. README 는 그 사이 파일 내용을 서술하고 있었는데,
|
||||||
|
# 그것은 화면에서 본 것을 적은 것이지 이 파일에서 온 것이 아니었다.
|
||||||
|
#
|
||||||
|
# 아래는 사후에 다시 수집한 것이며, 원 시점의 DROP 규칙(0 패킷)은 이미
|
||||||
|
# 제거되어 재현되지 않는다. 구조적 사실(kube-router 가 자기 체인을 FORWARD
|
||||||
|
# 최상단에 유지한다)만 확인할 수 있다.
|
||||||
|
# 원 실험의 결정적 증거는 04-correct-direction.txt 의 패킷 카운터 19/21 이다.
|
||||||
|
|
||||||
|
=== A-5 재수집 — filter 테이블 규칙이 CNI 체인에 밀리는 것 ===
|
||||||
|
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
|
||||||
|
num pkts bytes target prot opt in out source destination
|
||||||
|
1 1690 3386K KUBE-ROUTER-FORWARD 0 -- * * 0.0.0.0/0 0.0.0.0/0 /* kube-router netpol - TEMCG2JMHZYE7H7T */
|
||||||
|
2 7 612 KUBE-PROXY-FIREWALL 0 -- * * 0.0.0.0/0 0.0.0.0/0 ctstate NEW /* kubernetes load balancer firewall */
|
||||||
|
3 40 13196 KUBE-FORWARD 0 -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes forwarding rules */
|
||||||
|
|
||||||
|
(원 실험 시점의 규칙은 이미 제거됐다. 아래는 kube-router 가 자기 체인을
|
||||||
|
FORWARD 최상단에 유지한다는 구조적 사실만 보여준다 — 그것이 실패 원인이었다.)
|
||||||
|
|||||||
@@ -16,3 +16,10 @@
|
|||||||
1. **세션은 옮겨졌고 토큰은 안 옮겨졌다.** 빈 81개가 늘었는데 authorized client 관련은 하나도 안 바뀌었다.
|
1. **세션은 옮겨졌고 토큰은 안 옮겨졌다.** 빈 81개가 늘었는데 authorized client 관련은 하나도 안 바뀌었다.
|
||||||
2. **refresh token 은 Redis 에 평문으로 있는 게 아니라 아예 없다.** 암호화를 고민하기 전에 이걸 알아야 한다.
|
2. **refresh token 은 Redis 에 평문으로 있는 게 아니라 아예 없다.** 암호화를 고민하기 전에 이걸 알아야 한다.
|
||||||
3. **"로그인은 되어 있는데 아무것도 못 하는" 상태가 만들어진다** — 완전 로그아웃보다 나쁘다.
|
3. **"로그인은 되어 있는데 아무것도 못 하는" 상태가 만들어진다** — 완전 로그아웃보다 나쁘다.
|
||||||
|
|
||||||
|
## 스크린샷 주의
|
||||||
|
|
||||||
|
`b1-login-works-two-replicas.png` 과 `b1-token-boundary-after-redis.png` 는
|
||||||
|
**동일 파일**이며 `b2-before-relogin.png` 와도 같다 (md5 `6de826a7…`).
|
||||||
|
세 시점 모두 `accessTokenStoredOnServer: false` 인 같은 화면이었다.
|
||||||
|
**시점 구별은 터미널 출력과 Redis/DB 조회가 한다.**
|
||||||
|
|||||||
@@ -19,3 +19,14 @@
|
|||||||
2. **refresh token 은 평문이다.** DB 읽기 권한이면 작동하는 토큰을 얻는다.
|
2. **refresh token 은 평문이다.** DB 읽기 권한이면 작동하는 토큰을 얻는다.
|
||||||
3. **같은 사용자의 두 번째 로그인이 첫 번째를 덮어쓴다.** 기본키에 session id 가 없어 구조적으로 그렇다.
|
3. **같은 사용자의 두 번째 로그인이 첫 번째를 덮어쓴다.** 기본키에 session id 가 없어 구조적으로 그렇다.
|
||||||
4. **로그아웃은 셋 중 하나만 지운다.** 평문 토큰과 Keycloak SSO 세션이 남는다.
|
4. **로그아웃은 셋 중 하나만 지운다.** 평문 토큰과 Keycloak SSO 세션이 남는다.
|
||||||
|
|
||||||
|
## 스크린샷 주의
|
||||||
|
|
||||||
|
`b2-tokens-shared-across-instances.png` 는 **B-0 의
|
||||||
|
`b0-bff-token-boundary.png` 와 동일 파일**이다 (md5 `9ed00537…`).
|
||||||
|
두 시점 모두 `accessTokenStoredOnServer: true` 인 같은 화면이라 바이트가 같다.
|
||||||
|
|
||||||
|
**그래서 이 png 는 "JDBC 전환으로 토큰이 공유된다" 를 단독으로 증명하지
|
||||||
|
못한다.** 그 증명은 `01-jdbc-store-deploy.txt`(테이블 생성)과
|
||||||
|
`03-plaintext-tokens.txt`(행에 토큰이 들어 있음)가 한다.
|
||||||
|
`b2-before-relogin.png` 는 B-1 의 캡처와 동일 파일이다.
|
||||||
|
|||||||
@@ -17,3 +17,11 @@
|
|||||||
1. **SSO 는 user session 1개에 client session N개** 구조다 — A-3(전체 소실)과 B-3(client 만 제거)의 차이가 여기서 의미를 갖는다.
|
1. **SSO 는 user session 1개에 client session N개** 구조다 — A-3(전체 소실)과 B-3(client 만 제거)의 차이가 여기서 의미를 갖는다.
|
||||||
2. **IdP 세션을 죽여도 두 앱은 계속 동작한다.** 세 층(IdP·앱·토큰)의 수명이 각자이기 때문이다.
|
2. **IdP 세션을 죽여도 두 앱은 계속 동작한다.** 세 층(IdP·앱·토큰)의 수명이 각자이기 때문이다.
|
||||||
3. **IdP 는 "로그인 경로"의 단일 장애점이지 "이미 로그인한 사용자"의 단일 장애점이 아니다.** 장애는 앱 세션 수명만큼 지연되어 몰려온다.
|
3. **IdP 는 "로그인 경로"의 단일 장애점이지 "이미 로그인한 사용자"의 단일 장애점이 아니다.** 장애는 앱 세션 수명만큼 지연되어 몰려온다.
|
||||||
|
|
||||||
|
## 스크린샷 주의
|
||||||
|
|
||||||
|
`c1-sso-app2-no-login-screen.png` 과 `c1-apps-alive-after-idp-logout.png` 는
|
||||||
|
**바이트 단위로 동일한 파일**이다 (md5 `2c703176…`). 두 시점의 화면이 실제로
|
||||||
|
같은 내용이었기 때문이며, 조작이 아니다. **다만 그래서 두 시점을 구별하는
|
||||||
|
증거가 되지 못한다** — 구별은 `03-` 과 `04-` 의 터미널 출력(client_sessions
|
||||||
|
1→2, 그리고 IdP 세션 삭제 후 Redis 키 잔존)이 한다.
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
|---|---|
|
|---|---|
|
||||||
| `01-pre-upgrade.txt` | 백업 396KB · 이미지 26.7.0 · **마이그레이션 210건** · 세션 4 |
|
| `01-pre-upgrade.txt` | 백업 396KB · 이미지 26.7.0 · **마이그레이션 210건** · 세션 4 |
|
||||||
| `02-rollback-attempt.txt` | 26.0 으로 내리자 `Running(0/1) → Error → CrashLoopBackOff`. **`liquibase.exception.ValidationFailedException`** |
|
| `02-rollback-attempt.txt` | 26.0 으로 내리자 `Running(0/1) → Error → CrashLoopBackOff`. **`liquibase.exception.ValidationFailedException`** |
|
||||||
|
| `d2-upgrade-window.png` | Grafana — 26.7.3 업그레이드 구간의 `cluster_size` 2→1→2 두 번과 파드별 `up` 시계열 교체 (후속 작업에서 촬영) |
|
||||||
| `03-roll-forward.txt` | **서비스는 `HTTP 200` 유지**(ready 주소 1개) · 오류 원인 `1 changesets check sum` · 26.7.0 복귀 후 마이그레이션 210·세션 4 그대로 |
|
| `03-roll-forward.txt` | **서비스는 `HTTP 200` 유지**(ready 주소 1개) · 오류 원인 `1 changesets check sum` · 26.7.0 복귀 후 마이그레이션 210·세션 4 그대로 |
|
||||||
|
|
||||||
## 핵심 세 줄
|
## 핵심 세 줄
|
||||||
|
|
||||||
1. **롤백은 안 된다.** 체크섬이 안 맞아 Liquibase 가 기동 자체를 거부한다 — "모르는 변경"이 아니라 "아는 변경인데 정의가 다르다".
|
1. **스키마가 바뀌었으면 롤백은 안 된다.** (26.7.0↔26.7.3 처럼 안 바뀌면 된다 — [`followup`](../followup/) 참조.) 체크섬이 안 맞아 Liquibase 가 기동 자체를 거부한다 — "모르는 변경"이 아니라 "아는 변경인데 정의가 다르다".
|
||||||
2. **StatefulSet 이 사고를 절반에서 멈춰줬다.** 한 파드가 남아 외부 200 을 유지했다. replica 1 이었다면 전면 장애다.
|
2. **StatefulSet 이 사고를 절반에서 멈춰줬다.** 한 파드가 남아 외부 200 을 유지했다. replica 1 이었다면 전면 장애다.
|
||||||
3. **실패한 기동은 스키마를 안 건드렸다.** 그래서 이미지만 되돌려도 복구됐다 — 이미 적용된 뒤였다면 DB 복구(D-1)가 필요하다.
|
3. **실패한 기동은 스키마를 안 건드렸다.** 그래서 이미지만 되돌려도 복구됐다 — 이미 적용된 뒤였다면 DB 복구(D-1)가 필요하다.
|
||||||
|
|||||||
@@ -597,6 +597,23 @@ for n in ('BEFORE_K0','BEFORE_K1','AFTER_K0','AFTER_K1'):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 09:52 – 10:12 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-cross-node-session.txt`](evidence/session-replication/01-cross-node-session.txt) | 터미널 원문 |
|
||||||
|
| [`02-cache-delta.txt`](evidence/session-replication/02-cache-delta.txt) | 터미널 원문 |
|
||||||
|
| [`03-cache-ownership.txt`](evidence/session-replication/03-cache-ownership.txt) | 터미널 원문 |
|
||||||
|
| [`04-read-path-sql.txt`](evidence/session-replication/04-read-path-sql.txt) | 터미널 원문 |
|
||||||
|
| [`keycloak-admin-sessions.png`](evidence/session-replication/keycloak-admin-sessions.png) | 스크린샷 |
|
||||||
|
| [`session-cache-entries-per-pod.png`](evidence/session-replication/session-cache-entries-per-pod.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/session-replication/README.md`](evidence/session-replication/README.md).
|
||||||
|
|
||||||
## 11. 재현
|
## 11. 재현
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -177,15 +177,34 @@ sudo conntrack -D -p tcp -s 10.42.1.43 -d 10.42.0.35 --sport 7800 --dport 40023
|
|||||||
**양쪽 노드에서, 양쪽 방향으로** 지워야 한다. 서버 쪽 노드에는 튜플이 뒤집혀
|
**양쪽 노드에서, 양쪽 방향으로** 지워야 한다. 서버 쪽 노드에는 튜플이 뒤집혀
|
||||||
기록되어 있다.
|
기록되어 있다.
|
||||||
|
|
||||||
그리고 **즉시 끊기지 않는다.**
|
### ★ 정정 — conntrack 삭제가 분단을 만들었다고 볼 근거가 없다
|
||||||
|
|
||||||
|
이 문서는 처음에 이렇게 썼다.
|
||||||
|
|
||||||
```
|
```
|
||||||
11:41 conntrack 삭제
|
11:41 conntrack 삭제
|
||||||
11:44 cluster_size 2 → 1 ← 약 3분 뒤
|
11:44 cluster_size 2 → 1 ← 약 3분 뒤
|
||||||
```
|
```
|
||||||
|
|
||||||
TCP 는 상대가 사라졌음을 **재전송 타임아웃**으로 알아낸다. 소켓은 한동안
|
**증거를 다시 보면 그 인과가 성립하지 않는다.**
|
||||||
`ESTABLISHED` 로 남아 있다.
|
|
||||||
|
| 시각 | 증거 |
|
||||||
|
|---|---|
|
||||||
|
| 11:41 | conntrack 삭제. 직후 `07-cluster-size.txt` 는 **11:45 까지 전부 `2`** |
|
||||||
|
| **11:44:23** | **`keycloak-0` 파드의 `startTime`** — 스스로 재시작했다 |
|
||||||
|
| 11:44:27 | `cluster_size` 2 → 1 |
|
||||||
|
| 11:46:07 | 내가 `delete pod` 를 실행 (이미 떨어진 뒤) |
|
||||||
|
|
||||||
|
**하락은 conntrack 삭제 3분 뒤가 아니라 파드 재시작 4초 뒤에 일어났다.**
|
||||||
|
같은 문서 6절이 "정책이 걸린 채 재시작되자" 라고 쓴 것이 맞고,
|
||||||
|
**4절의 "conntrack 삭제 → 3분 뒤 분단" 은 시각이 겹친 것을 인과로 읽은 것이다.**
|
||||||
|
|
||||||
|
conntrack 삭제 자체가 무의미했다는 뜻은 아니다 — 다만 **이 실험은
|
||||||
|
그것만으로 분단이 되는지 판정하지 못했다.** 판정한 것은 A-5 이고,
|
||||||
|
거기서 `raw` 테이블이 필요하다는 것이 드러났다.
|
||||||
|
|
||||||
|
> TCP 가 재전송 타임아웃으로 상대를 알아채는 것은 사실이지만,
|
||||||
|
> **이 실험에서 그 경로가 발동했다는 증거는 없다.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -462,6 +481,30 @@ vendor_jgroups_merge3_get_num_merge_events
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 11:34 – 11:50 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-baseline-cluster.txt`](evidence/a1-jgroups-transport-block/01-baseline-cluster.txt) | 터미널 원문 |
|
||||||
|
| [`02-control-before-block.txt`](evidence/a1-jgroups-transport-block/02-control-before-block.txt) | 터미널 원문 |
|
||||||
|
| [`03-block-applied.txt`](evidence/a1-jgroups-transport-block/03-block-applied.txt) | 터미널 원문 |
|
||||||
|
| [`04-after-block-state.txt`](evidence/a1-jgroups-transport-block/04-after-block-state.txt) | 터미널 원문 |
|
||||||
|
| [`05-conntrack-problem.txt`](evidence/a1-jgroups-transport-block/05-conntrack-problem.txt) | 터미널 원문 |
|
||||||
|
| [`06-partition-observed.txt`](evidence/a1-jgroups-transport-block/06-partition-observed.txt) | 터미널 원문 |
|
||||||
|
| [`07-cluster-size.txt`](evidence/a1-jgroups-transport-block/07-cluster-size.txt) | 터미널 원문 |
|
||||||
|
| [`08-restart-forced-partition.txt`](evidence/a1-jgroups-transport-block/08-restart-forced-partition.txt) | 터미널 원문 |
|
||||||
|
| [`09-cross-node-under-partition.txt`](evidence/a1-jgroups-transport-block/09-cross-node-under-partition.txt) | 터미널 원문 |
|
||||||
|
| [`10-logout-not-propagated.txt`](evidence/a1-jgroups-transport-block/10-logout-not-propagated.txt) | 터미널 원문 |
|
||||||
|
| [`11-service-impact.txt`](evidence/a1-jgroups-transport-block/11-service-impact.txt) | 터미널 원문 |
|
||||||
|
| [`12-recovery.txt`](evidence/a1-jgroups-transport-block/12-recovery.txt) | 터미널 원문 |
|
||||||
|
| [`a1-cluster-size-partition-recovery.png`](evidence/a1-jgroups-transport-block/a1-cluster-size-partition-recovery.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/a1-jgroups-transport-block/README.md`](evidence/a1-jgroups-transport-block/README.md).
|
||||||
|
|
||||||
## 11. 재현 절차 (명령어)
|
## 11. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -103,12 +103,19 @@ kubectl -n keycloak-lab wait --for=delete pod -l app=postgres --timeout=90s
|
|||||||
① 캐시를 가진 노드(keycloak-0)에서 refresh HTTP 500
|
① 캐시를 가진 노드(keycloak-0)에서 refresh HTTP 500
|
||||||
② 캐시가 없는 노드(keycloak-1)에서 refresh HTTP 500
|
② 캐시가 없는 노드(keycloak-1)에서 refresh HTTP 500
|
||||||
③ 새 로그인 HTTP 500
|
③ 새 로그인 HTTP 500
|
||||||
④ 관리 API (세션 조회 필요) HTTP 500
|
④ 관리 API (세션 조회 필요) HTTP 500 ← 5절의 재측정값
|
||||||
|
|
||||||
--- 오류 본문 ---
|
--- 오류 본문 ---
|
||||||
{"error":"unknown_error","error_description":"For more on this error consult the server log."}
|
{"error":"unknown_error","error_description":"For more on this error consult the server log."}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **④ 의 첫 측정은 오염됐다** —
|
||||||
|
> [`03-four-paths.txt`](evidence/a2-database-loss/03-four-paths.txt) 에는
|
||||||
|
> `HTTP 000000{"error":"HTTP 401 Unauthorized"}401` 이 남아 있다.
|
||||||
|
> `curl -w %{http_code}` 출력에 본문이 섞인 것이고, 재시도가 `000` 을 세 번
|
||||||
|
> 찍은 뒤 `401` 이 왔다. **위 표의 `500` 은 5절에서 다시 잰 값**이며,
|
||||||
|
> 첫 측정을 그대로 쓰지 않았다.
|
||||||
|
|
||||||
### ① 이 500 인 것이 중요하다
|
### ① 이 500 인 것이 중요하다
|
||||||
|
|
||||||
**캐시에 세션을 들고 있어도 refresh 는 실패한다.**
|
**캐시에 세션을 들고 있어도 refresh 는 실패한다.**
|
||||||
@@ -272,6 +279,23 @@ DB 가 돌아와도 CrashLoopBackOff 의 백오프 때문에 회복이 늦어진
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 11:53 – 11:56 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-baseline.txt`](evidence/a2-database-loss/01-baseline.txt) | 터미널 원문 |
|
||||||
|
| [`02-setup-sessions.txt`](evidence/a2-database-loss/02-setup-sessions.txt) | 터미널 원문 |
|
||||||
|
| [`03-four-paths.txt`](evidence/a2-database-loss/03-four-paths.txt) | 터미널 원문 |
|
||||||
|
| [`04-health-and-service.txt`](evidence/a2-database-loss/04-health-and-service.txt) | 터미널 원문 |
|
||||||
|
| [`05-recovery.txt`](evidence/a2-database-loss/05-recovery.txt) | 터미널 원문 |
|
||||||
|
| [`a2-up-stayed-1-during-outage.png`](evidence/a2-database-loss/a2-up-stayed-1-during-outage.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/a2-database-loss/README.md`](evidence/a2-database-loss/README.md).
|
||||||
|
|
||||||
## 9. 재현 절차 (명령어)
|
## 9. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -181,8 +181,23 @@ database system is ready to accept connections
|
|||||||
★ p5XybeQIYmAs818gO4Vl_5ea
|
★ p5XybeQIYmAs818gO4Vl_5ea
|
||||||
```
|
```
|
||||||
|
|
||||||
**약 2.6% 유실.** 초당 19건 정도 로그인하던 중이었으므로
|
**약 2.6% 유실.**
|
||||||
**대략 마지막 0.2초 분량**이다 — `wal_writer_delay` 기본값(200ms)과 맞는다.
|
|
||||||
|
처음 이 문서는 *"초당 19건 … `wal_writer_delay` 기본값(200ms)과 맞는다"* 고
|
||||||
|
썼는데, **그 시점에 `wal_writer_delay` 를 조회한 적이 없었다.** 나중에 쟀다.
|
||||||
|
|
||||||
|
```
|
||||||
|
name | setting | unit | source
|
||||||
|
------------------------+---------+------+---------
|
||||||
|
wal_writer_delay | 200 | ms | default
|
||||||
|
wal_writer_flush_after | 128 | 8kB | default
|
||||||
|
synchronous_commit | on | | default
|
||||||
|
```
|
||||||
|
[`08-wal-settings.txt`](evidence/a3-database-crash/08-wal-settings.txt)
|
||||||
|
|
||||||
|
**값은 맞았지만 그때는 추정이었다.** 그리고 로그인 속도도 정확히는
|
||||||
|
증거의 `8초에 112건` ≈ **초당 14건**이며 19건이 아니다. 4건은 그 속도에서
|
||||||
|
**약 0.29초 분량**이고, 200ms 창과 같은 자릿수이되 정확히 일치하지는 않는다.
|
||||||
|
|
||||||
### 사용자에게 어떻게 보이는가
|
### 사용자에게 어떻게 보이는가
|
||||||
|
|
||||||
@@ -284,6 +299,25 @@ ALTER DATABASE keycloak SET synchronous_commit = on; -- SET LOCAL 이 이깁
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 11:58 – 16:32 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-crash-injection.txt`](evidence/a3-database-crash/01-crash-injection.txt) | 터미널 원문 |
|
||||||
|
| [`02-design-check.txt`](evidence/a3-database-crash/02-design-check.txt) | 터미널 원문 |
|
||||||
|
| [`03-loss-measurement.txt`](evidence/a3-database-crash/03-loss-measurement.txt) | 터미널 원문 |
|
||||||
|
| [`04-comparison.txt`](evidence/a3-database-crash/04-comparison.txt) | 터미널 원문 |
|
||||||
|
| [`05-true-crash.txt`](evidence/a3-database-crash/05-true-crash.txt) | 터미널 원문 |
|
||||||
|
| [`06-backend-kill-crash.txt`](evidence/a3-database-crash/06-backend-kill-crash.txt) | 터미널 원문 |
|
||||||
|
| [`07-loss-result.txt`](evidence/a3-database-crash/07-loss-result.txt) | 터미널 원문 |
|
||||||
|
| [`08-wal-settings.txt`](evidence/a3-database-crash/08-wal-settings.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/a3-database-crash/README.md`](evidence/a3-database-crash/README.md).
|
||||||
|
|
||||||
## 8. 재현 절차 (명령어)
|
## 8. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
| 외부 응답 | **503** | **000** (연결 자체가 안 됨) |
|
| 외부 응답 | **503** | **000** (연결 자체가 안 됨) |
|
||||||
| `kubectl` | 정상 | **불통** |
|
| `kubectl` | 정상 | **불통** |
|
||||||
| 살아 있는 워크로드 | keycloak-1 (하지만 DB 없음) | **keycloak-0 은 계속 돌고 있다** |
|
| 살아 있는 워크로드 | keycloak-1 (하지만 DB 없음) | **keycloak-0 은 계속 돌고 있다** |
|
||||||
| 복구 시간 | **60초** | **60초** |
|
| **`virsh start` 이후** 복구 | **60초** | **60초** |
|
||||||
|
|
||||||
**둘 다 전면 장애**지만 이유가 다르다. 4a 는 **DB 가 같이 죽어서**, 4b 는
|
**둘 다 전면 장애**지만 이유가 다르다. 4a 는 **DB 가 같이 죽어서**, 4b 는
|
||||||
**들어갈 길이 없어서**다.
|
**들어갈 길이 없어서**다.
|
||||||
@@ -204,6 +204,15 @@ virsh start kc-lab-2
|
|||||||
|
|
||||||
**60초.** 사람 개입 없이 전부 제자리로 돌아왔다.
|
**60초.** 사람 개입 없이 전부 제자리로 돌아왔다.
|
||||||
|
|
||||||
|
> **이 60초는 MTTR 이 아니다.** `virsh start` 를 친 뒤의 시간이며,
|
||||||
|
> 실제 장애 구간은 **12:07:43(차단) → 12:17:31(서비스 복귀) ≈ 10분**이다.
|
||||||
|
> 그 대부분은 내가 관찰하며 보낸 시간이고, **사람이 알아채고 결정하는 시간이
|
||||||
|
> 복구 시간의 대부분**이라는 점이 오히려 현실적이다.
|
||||||
|
>
|
||||||
|
> 그리고 본문의 `40초`(node-monitor-grace-period)와 `5분`(tolerationSeconds)은
|
||||||
|
> **쿠버네티스 기본값을 인용한 것**이며, 관측된 전이 시점(+45초, +270초)이
|
||||||
|
> 그 값과 모순되지 않는다는 것까지가 이 실험이 말할 수 있는 범위다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4b. 컨트롤 플레인 노드 상실 (`kc-lab-1`)
|
## 4b. 컨트롤 플레인 노드 상실 (`kc-lab-1`)
|
||||||
@@ -358,6 +367,26 @@ virsh start kc-lab-1
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 12:05 – 12:23 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-baseline.txt`](evidence/a4-node-loss/01-baseline.txt) | 터미널 원문 |
|
||||||
|
| [`02-worker-node-killed.txt`](evidence/a4-node-loss/02-worker-node-killed.txt) | 터미널 원문 |
|
||||||
|
| [`03-state-during-loss.txt`](evidence/a4-node-loss/03-state-during-loss.txt) | 터미널 원문 |
|
||||||
|
| [`04-eviction-timing.txt`](evidence/a4-node-loss/04-eviction-timing.txt) | 터미널 원문 |
|
||||||
|
| [`05-recovery.txt`](evidence/a4-node-loss/05-recovery.txt) | 터미널 원문 |
|
||||||
|
| [`06-control-plane-inventory.txt`](evidence/a4-node-loss/06-control-plane-inventory.txt) | 터미널 원문 |
|
||||||
|
| [`07-control-plane-loss.txt`](evidence/a4-node-loss/07-control-plane-loss.txt) | 터미널 원문 |
|
||||||
|
| [`08-control-plane-recovery.txt`](evidence/a4-node-loss/08-control-plane-recovery.txt) | 터미널 원문 |
|
||||||
|
| [`a4-up-dropped-per-node.png`](evidence/a4-node-loss/a4-up-dropped-per-node.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/a4-node-loss/README.md`](evidence/a4-node-loss/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -137,6 +137,16 @@ kubectl -n keycloak-lab logs keycloak-0 --since=20m | grep ISPN000094 | awk '$2
|
|||||||
suspected = 0
|
suspected = 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **맥락 하나가 빠져 있었다** —
|
||||||
|
> [`06-view-history-and-cleanup.txt`](evidence/a5-asymmetric-partition/06-view-history-and-cleanup.txt)
|
||||||
|
> 를 보면 뷰 13 은 **주입(03:33:58)보다 9초 앞선 03:33:49 의 `MergeView`** 로
|
||||||
|
> 만들어졌고, 그 직전에는 `|12] (1)` — 즉 **막 분단됐다가 합쳐진 직후**였다.
|
||||||
|
> `merge_events = 1.0` 도 그 병합의 것이다.
|
||||||
|
>
|
||||||
|
> **"주입 전부터 그대로" 는 맞지만, 그 "전" 이 9초였다.**
|
||||||
|
> 앞선 실패한 주입 시도들이 만든 흔들림이고, 주입 이후 뷰가 변하지 않았다는
|
||||||
|
> 결론 자체는 유지된다.
|
||||||
|
|
||||||
### 왜 안 갈라졌는가 — **연결 방향이 뒤집혔다**
|
### 왜 안 갈라졌는가 — **연결 방향이 뒤집혔다**
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -281,6 +291,26 @@ JGroups 코디네이터는 **가장 오래된 멤버**다. 분단이 나면
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 12:29 – 16:34 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-injection.txt`](evidence/a5-asymmetric-partition/01-injection.txt) | 터미널 원문 |
|
||||||
|
| [`02-injection-verify.txt`](evidence/a5-asymmetric-partition/02-injection-verify.txt) | 터미널 원문 |
|
||||||
|
| [`03-raw-table-injection.txt`](evidence/a5-asymmetric-partition/03-raw-table-injection.txt) | 터미널 원문 |
|
||||||
|
| [`04-correct-direction.txt`](evidence/a5-asymmetric-partition/04-correct-direction.txt) | 터미널 원문 |
|
||||||
|
| [`05-reconnect-observed.txt`](evidence/a5-asymmetric-partition/05-reconnect-observed.txt) | 터미널 원문 |
|
||||||
|
| [`06-view-history-and-cleanup.txt`](evidence/a5-asymmetric-partition/06-view-history-and-cleanup.txt) | 터미널 원문 |
|
||||||
|
| [`07-bidirectional-block.txt`](evidence/a5-asymmetric-partition/07-bidirectional-block.txt) | 터미널 원문 |
|
||||||
|
| [`08-coordinator-and-recovery.txt`](evidence/a5-asymmetric-partition/08-coordinator-and-recovery.txt) | 터미널 원문 |
|
||||||
|
| [`a5-cluster-size-bidirectional-block.png`](evidence/a5-asymmetric-partition/a5-cluster-size-bidirectional-block.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/a5-asymmetric-partition/README.md`](evidence/a5-asymmetric-partition/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -130,10 +130,14 @@ qdisc netem 30: parent 1:3 limit 1000 delay 200ms
|
|||||||
|
|
||||||
```
|
```
|
||||||
=== 두 노드 지연 비교 (기준선: k0=70ms k1=66ms) ===
|
=== 두 노드 지연 비교 (기준선: k0=70ms k1=66ms) ===
|
||||||
keycloak-0 평균 41 ms 최대 57 ms ← 영향 없음
|
keycloak-0 평균 41 ms 최대 57 ms ← 기준선 70ms 대비 -41%
|
||||||
keycloak-1 평균 1872 ms 최대 1887 ms ← 28배
|
keycloak-1 평균 1872 ms 최대 1887 ms ← 28배
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **대조군도 변했다** — keycloak-0 은 기준선 70ms 에서 41ms 로 **41% 빨라졌다.**
|
||||||
|
> 주입과 무관한 변동(JIT 워밍업, 캐시)이며, **"영향 없음" 이라고 쓴 것은
|
||||||
|
> 부정확했다.** 다만 keycloak-1 의 28배 증가와는 자릿수가 달라 결론은 유지된다.
|
||||||
|
|
||||||
### 왜 200ms 가 1,872ms 가 되는가
|
### 왜 200ms 가 1,872ms 가 되는가
|
||||||
|
|
||||||
A-0 에서 잡은 로그인 트랜잭션의 SQL 이 답이다.
|
A-0 에서 잡은 로그인 트랜잭션의 SQL 이 답이다.
|
||||||
@@ -156,6 +160,10 @@ COMMIT
|
|||||||
200 ms × 9 왕복 ≈ 1,800 ms 실측 1,872 ms
|
200 ms × 9 왕복 ≈ 1,800 ms 실측 1,872 ms
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **9 는 SQL 목록을 센 것이고 패킷을 추적한 값이 아니다.** 자릿수가 맞는다는
|
||||||
|
> 것까지가 이 계산이 말할 수 있는 범위이며, **왕복 수를 확정하려면
|
||||||
|
> `tc -s` 나 패킷 캡처가 필요하다.**
|
||||||
|
|
||||||
> **네트워크 지연은 왕복 횟수만큼 증폭된다.**
|
> **네트워크 지연은 왕복 횟수만큼 증폭된다.**
|
||||||
> "DB 가 200ms 느려졌다"는 "애플리케이션이 200ms 느려졌다"가 아니다.
|
> "DB 가 200ms 느려졌다"는 "애플리케이션이 200ms 느려졌다"가 아니다.
|
||||||
> **쿼리 수를 줄이는 것이 지연 환경에서 결정적인 이유**가 이것이다.
|
> **쿼리 수를 줄이는 것이 지연 환경에서 결정적인 이유**가 이것이다.
|
||||||
@@ -296,6 +304,23 @@ histogram_quantile(0.99, rate(http_server_requests_seconds_bucket[5m]))
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 13:12 – 13:16 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-baseline.txt`](evidence/a6-latency-injection/01-baseline.txt) | 터미널 원문 |
|
||||||
|
| [`02-delay-injected.txt`](evidence/a6-latency-injection/02-delay-injected.txt) | 터미널 원문 |
|
||||||
|
| [`03-flannel-injection.txt`](evidence/a6-latency-injection/03-flannel-injection.txt) | 터미널 원문 |
|
||||||
|
| [`04-pool-under-load.txt`](evidence/a6-latency-injection/04-pool-under-load.txt) | 터미널 원문 |
|
||||||
|
| [`05-recovery.txt`](evidence/a6-latency-injection/05-recovery.txt) | 터미널 원문 |
|
||||||
|
| [`a6-connection-pool-blocking.png`](evidence/a6-latency-injection/a6-connection-pool-blocking.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/a6-latency-injection/README.md`](evidence/a6-latency-injection/README.md).
|
||||||
|
|
||||||
## 8. 재현 절차 (명령어)
|
## 8. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -233,6 +233,23 @@ kubectl apply -f deploy/lab/k8s/keycloak-cluster.yaml
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 13:22 – 13:32 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-switch-to-volatile.txt`](evidence/a7-volatile-comparison/01-switch-to-volatile.txt) | 터미널 원문 |
|
||||||
|
| [`02-a0-rerun.txt`](evidence/a7-volatile-comparison/02-a0-rerun.txt) | 터미널 원문 |
|
||||||
|
| [`03-a8-rerun-restart.txt`](evidence/a7-volatile-comparison/03-a8-rerun-restart.txt) | 터미널 원문 |
|
||||||
|
| [`04-a1-rerun-partition.txt`](evidence/a7-volatile-comparison/04-a1-rerun-partition.txt) | 터미널 원문 |
|
||||||
|
| [`05-a2-rerun-db-loss.txt`](evidence/a7-volatile-comparison/05-a2-rerun-db-loss.txt) | 터미널 원문 |
|
||||||
|
| [`06-restore-persistent.txt`](evidence/a7-volatile-comparison/06-restore-persistent.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/a7-volatile-comparison/README.md`](evidence/a7-volatile-comparison/README.md).
|
||||||
|
|
||||||
## 8. 재현 절차 (명령어)
|
## 8. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -56,7 +56,14 @@ statefulset.apps/keycloak restarted
|
|||||||
200 200 200 200 partitioned roll out complete: 2 new pods have been updated...
|
200 200 200 200 partitioned roll out complete: 2 new pods have been updated...
|
||||||
```
|
```
|
||||||
|
|
||||||
**9번 찍어서 9번 다 `200`.** 한 번도 끊기지 않았다.
|
**9번 찍어서 9번 다 `200`.**
|
||||||
|
|
||||||
|
> **표본은 9개다.** 5초 간격으로 찍었으므로 **5초보다 짧은 끊김은 이 측정으로
|
||||||
|
> 잡히지 않는다.** 실제로 후속 작업에서 1초 간격·3초 타임아웃으로 재보니
|
||||||
|
> 롤백 전환 순간에 `000` 이 한 번 잡혔다
|
||||||
|
> ([`followup`](experiment-followup-untested-items.md) 2절).
|
||||||
|
> **"무중단" 은 관측 해상도에 달려 있으며, 여기서는 "5초 해상도에서 끊김이
|
||||||
|
> 관측되지 않았다" 까지가 정확한 서술이다.**
|
||||||
|
|
||||||
### 왜 무중단이 되는가
|
### 왜 무중단이 되는가
|
||||||
|
|
||||||
@@ -163,6 +170,20 @@ A-0 에서 세운 모델이 여기서 그대로 확인된다.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 13:19 – 13:20 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-restart-availability.txt`](evidence/a8-rolling-restart/01-restart-availability.txt) | 터미널 원문 |
|
||||||
|
| [`02-session-survival.txt`](evidence/a8-rolling-restart/02-session-survival.txt) | 터미널 원문 |
|
||||||
|
| [`a8-cache-reset-cluster-reformed.png`](evidence/a8-rolling-restart/a8-cache-reset-cluster-reformed.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/a8-rolling-restart/README.md`](evidence/a8-rolling-restart/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -283,6 +283,22 @@ kubectl exec <pod> -- wget -qO- http://localhost:8083/actuator/beans
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 13:39 – 13:46 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-deploy.txt`](evidence/b0-bff-redis-deploy/01-deploy.txt) | 터미널 원문 |
|
||||||
|
| [`02-autoconfiguration.txt`](evidence/b0-bff-redis-deploy/02-autoconfiguration.txt) | 터미널 원문 |
|
||||||
|
| [`03-beans-analysis.txt`](evidence/b0-bff-redis-deploy/03-beans-analysis.txt) | 터미널 원문 |
|
||||||
|
| [`b0-bff-login-success-single-replica.png`](evidence/b0-bff-redis-deploy/b0-bff-login-success-single-replica.png) | 스크린샷 |
|
||||||
|
| [`b0-bff-token-boundary.png`](evidence/b0-bff-redis-deploy/b0-bff-token-boundary.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/b0-bff-redis-deploy/README.md`](evidence/b0-bff-redis-deploy/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -269,6 +269,22 @@ Q3 는 *"저장소를 직접 열어 refresh token 이 평문으로 남는지 확
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 13:59 – 14:03 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-servicelinks-trap.txt`](evidence/b1-redis-session-store/01-servicelinks-trap.txt) | 터미널 원문 |
|
||||||
|
| [`02-autoconfig-after.txt`](evidence/b1-redis-session-store/02-autoconfig-after.txt) | 터미널 원문 |
|
||||||
|
| [`03-redis-contents.txt`](evidence/b1-redis-session-store/03-redis-contents.txt) | 터미널 원문 |
|
||||||
|
| [`b1-login-works-two-replicas.png`](evidence/b1-redis-session-store/b1-login-works-two-replicas.png) | 스크린샷 |
|
||||||
|
| [`b1-token-boundary-after-redis.png`](evidence/b1-redis-session-store/b1-token-boundary-after-redis.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/b1-redis-session-store/README.md`](evidence/b1-redis-session-store/README.md).
|
||||||
|
|
||||||
## 7. 재현 절차 (명령어)
|
## 7. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -182,6 +182,14 @@ access_token 헤더 : {"alg":"RS256","typ":"JWT","kid":"OY-caYDNGoP4HMAz-..."}
|
|||||||
|
|
||||||
같은 사용자로 다시 로그인시키고 행을 비교했다.
|
같은 사용자로 다시 로그인시키고 행을 비교했다.
|
||||||
|
|
||||||
|
> **실제로는 브라우저를 두 개 쓰지 않았다.** 증거
|
||||||
|
> [`04-overwrite-test.txt`](evidence/b2-multi-instance-session/04-overwrite-test.txt)
|
||||||
|
> 에 `[모의 두 번째 브라우저] 세션만 지우고` 라고 적혀 있다.
|
||||||
|
> **세션을 지우고 같은 사용자로 다시 로그인시킨 것**이며, 조회 키가
|
||||||
|
> `(clientRegistrationId, principalName)` 이므로 브라우저가 둘이든 하나든
|
||||||
|
> **같은 행을 쓴다는 점에서 등가**다. 다만 "두 브라우저에서" 라고 쓴 것은
|
||||||
|
> 측정하지 않은 것을 측정한 것처럼 적은 것이다.
|
||||||
|
|
||||||
```
|
```
|
||||||
=== 재로그인 전 ===
|
=== 재로그인 전 ===
|
||||||
principal_name | access_token_issued_at | at_md5
|
principal_name | access_token_issued_at | at_md5
|
||||||
@@ -285,7 +293,12 @@ PRIMARY KEY (client_registration_id, principal_name)
|
|||||||
"공유 저장소로 바꾼다" 와 "세션별로 구분한다" 는 다른 문제이며,
|
"공유 저장소로 바꾼다" 와 "세션별로 구분한다" 는 다른 문제이며,
|
||||||
전자만 하면 인스턴스 간 공유는 되고 브라우저 간 격리는 안 된다.
|
전자만 하면 인스턴스 간 공유는 되고 브라우저 간 격리는 안 된다.
|
||||||
|
|
||||||
### Liquibase 스키마의 방언 차이
|
### 스키마 DDL 의 방언 차이
|
||||||
|
|
||||||
|
> **정정** — 이 절의 제목은 처음에 "Liquibase 스키마의 방언 차이" 였다.
|
||||||
|
> **Liquibase 가 아니다.** 여기서 스키마를 태우는 것은 Spring Boot 의
|
||||||
|
> `spring.sql.init` 이고, DDL 은 `spring-security-oauth2-client` jar 가
|
||||||
|
> 번들한 파일이다. (Liquibase 는 Keycloak 이 자기 스키마에 쓰며, D-2 의 주제다.)
|
||||||
|
|
||||||
Spring Security 는 DDL 을 두 벌 제공한다.
|
Spring Security 는 DDL 을 두 벌 제공한다.
|
||||||
|
|
||||||
@@ -307,6 +320,24 @@ Spring Security 는 DDL 을 두 벌 제공한다.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:09 – 14:13 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-jdbc-store-deploy.txt`](evidence/b2-multi-instance-session/01-jdbc-store-deploy.txt) | 터미널 원문 |
|
||||||
|
| [`02-schema.txt`](evidence/b2-multi-instance-session/02-schema.txt) | 터미널 원문 |
|
||||||
|
| [`03-plaintext-tokens.txt`](evidence/b2-multi-instance-session/03-plaintext-tokens.txt) | 터미널 원문 |
|
||||||
|
| [`04-overwrite-test.txt`](evidence/b2-multi-instance-session/04-overwrite-test.txt) | 터미널 원문 |
|
||||||
|
| [`05-logout-cleanup.txt`](evidence/b2-multi-instance-session/05-logout-cleanup.txt) | 터미널 원문 |
|
||||||
|
| [`b2-before-relogin.png`](evidence/b2-multi-instance-session/b2-before-relogin.png) | 스크린샷 |
|
||||||
|
| [`b2-tokens-shared-across-instances.png`](evidence/b2-multi-instance-session/b2-tokens-shared-across-instances.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/b2-multi-instance-session/README.md`](evidence/b2-multi-instance-session/README.md).
|
||||||
|
|
||||||
## 8. 재현 절차 (명령어)
|
## 8. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -75,6 +75,21 @@ kubectl -n keycloak-lab exec keycloak-0 -- /opt/keycloak/bin/kcadm.sh \
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:16 – 14:17 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-concurrent-refresh.txt`](evidence/b3-refresh-contention/01-concurrent-refresh.txt) | 터미널 원문 |
|
||||||
|
| [`02-session-impact.txt`](evidence/b3-refresh-contention/02-session-impact.txt) | 터미널 원문 |
|
||||||
|
| [`03-client-session-removed.txt`](evidence/b3-refresh-contention/03-client-session-removed.txt) | 터미널 원문 |
|
||||||
|
| [`04-policy-comparison.txt`](evidence/b3-refresh-contention/04-policy-comparison.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/b3-refresh-contention/README.md`](evidence/b3-refresh-contention/README.md).
|
||||||
|
|
||||||
## 2. 재현 — 진짜 동시성을 만든다
|
## 2. 재현 — 진짜 동시성을 만든다
|
||||||
|
|
||||||
B-2 에서 토큰이 PostgreSQL 로 공유되므로 두 replica 가 같은 항목을 본다.
|
B-2 에서 토큰이 PostgreSQL 로 공유되므로 두 replica 가 같은 항목을 본다.
|
||||||
|
|||||||
@@ -260,6 +260,18 @@ Spring 의 `request.getHeader()` 는 **첫 번째**를 돌려주고,
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:23 – 14:23 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-header-handling.txt`](evidence/b4-edge-authorization/01-header-handling.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/b4-edge-authorization/README.md`](evidence/b4-edge-authorization/README.md).
|
||||||
|
|
||||||
## 7. 재현 절차 (명령어)
|
## 7. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -223,6 +223,21 @@ appendfsync everysec ← 기본값
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:24 – 14:28 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-baseline.txt`](evidence/b5-redis-loss/01-baseline.txt) | 터미널 원문 |
|
||||||
|
| [`02-redis-down.txt`](evidence/b5-redis-loss/02-redis-down.txt) | 터미널 원문 |
|
||||||
|
| [`03-health-groups.txt`](evidence/b5-redis-loss/03-health-groups.txt) | 터미널 원문 |
|
||||||
|
| [`04-persistence.txt`](evidence/b5-redis-loss/04-persistence.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/b5-redis-loss/README.md`](evidence/b5-redis-loss/README.md).
|
||||||
|
|
||||||
## 5. 재현 절차 (명령어)
|
## 5. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -203,6 +203,20 @@ kcadm.sh get components -r keycloak-patterns -q type=org.keycloak.keys.KeyProvid
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:30 – 14:32 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-before-rotation.txt`](evidence/b6-key-rotation/01-before-rotation.txt) | 터미널 원문 |
|
||||||
|
| [`02-rotation.txt`](evidence/b6-key-rotation/02-rotation.txt) | 터미널 원문 |
|
||||||
|
| [`03-old-key-removed.txt`](evidence/b6-key-rotation/03-old-key-removed.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/b6-key-rotation/README.md`](evidence/b6-key-rotation/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -255,6 +255,21 @@ B-6 에서 Keycloak 은 `kid` 로 여러 키를 구분해 무중단 회전을
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:35 – 14:42 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-deploy.txt`](evidence/b7-cookie-secret/01-deploy.txt) | 터미널 원문 |
|
||||||
|
| [`02-cookie-portability.txt`](evidence/b7-cookie-secret/02-cookie-portability.txt) | 터미널 원문 |
|
||||||
|
| [`03-rotation.txt`](evidence/b7-cookie-secret/03-rotation.txt) | 터미널 원문 |
|
||||||
|
| [`b7-oauth2proxy-login-success.png`](evidence/b7-cookie-secret/b7-oauth2proxy-login-success.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/b7-cookie-secret/README.md`](evidence/b7-cookie-secret/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -59,10 +59,15 @@ DB 를 직접 지우고 Keycloak 을 재시작해야 했다 — **캐시 때문
|
|||||||
(A-1 에서 확인한 대로, DB 를 직접 지워도 캐시는 남는다).
|
(A-1 에서 확인한 대로, DB 를 직접 지워도 캐시는 남는다).
|
||||||
|
|
||||||
```
|
```
|
||||||
Keycloak 온라인 세션: 0
|
Keycloak 온라인 세션: 4 ← 초기화가 안 먹었다
|
||||||
app1 HTTP 200 / app2 HTTP 200
|
app1 HTTP 200 / app2 HTTP 200
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **정정** — 이 문서는 처음에 이 값을 `0` 으로 인쇄했다. 증거
|
||||||
|
> [`01-baseline.txt`](evidence/c1-multi-app-sso/01-baseline.txt) 는 `4` 다.
|
||||||
|
> `logout-all` 이 듣지 않아 세션이 남아 있었고, 그래서 아래 절차(DB 직접 삭제 +
|
||||||
|
> Keycloak 재시작)가 필요했다. **`0` 은 그 다음 단계의 값이었다.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. SSO 가 동작한다
|
## 2. SSO 가 동작한다
|
||||||
@@ -216,6 +221,23 @@ select us.user_session_id, r.name as realm, ...
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:44 – 14:48 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-baseline.txt`](evidence/c1-multi-app-sso/01-baseline.txt) | 터미널 원문 |
|
||||||
|
| [`02-after-app1-login.txt`](evidence/c1-multi-app-sso/02-after-app1-login.txt) | 터미널 원문 |
|
||||||
|
| [`03-after-app2-visit.txt`](evidence/c1-multi-app-sso/03-after-app2-visit.txt) | 터미널 원문 |
|
||||||
|
| [`04-sso-session-killed.txt`](evidence/c1-multi-app-sso/04-sso-session-killed.txt) | 터미널 원문 |
|
||||||
|
| [`c1-apps-alive-after-idp-logout.png`](evidence/c1-multi-app-sso/c1-apps-alive-after-idp-logout.png) | 스크린샷 |
|
||||||
|
| [`c1-sso-app2-no-login-screen.png`](evidence/c1-multi-app-sso/c1-sso-app2-no-login-screen.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/c1-multi-app-sso/README.md`](evidence/c1-multi-app-sso/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -78,6 +78,14 @@ kcadm.sh update clients/<id> -r keycloak-patterns \
|
|||||||
backchannel.logout.url = https://app1.hyeonworks.com/logout/connect/back-channel/keycloak
|
backchannel.logout.url = https://app1.hyeonworks.com/logout/connect/back-channel/keycloak
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **출처 주의** — 위 확인 출력은
|
||||||
|
> [`02-configure-idp.txt`](evidence/c2-backchannel-logout/02-configure-idp.txt) 가
|
||||||
|
> 아니라 그 뒤 별도로 실행한 조회에서 나온 것이다. 그 파일에는
|
||||||
|
> **`command terminated with exit code 1`** 이 남아 있다 —
|
||||||
|
> `-s "attributes.backchannel.logout.url=..."` 의 점 표기가 실패한 첫 시도이며,
|
||||||
|
> JSON 으로 다시 넣어 성공했다. **실패한 시도의 파일에 성공 출력을 붙여
|
||||||
|
> 인쇄한 것은 잘못이었다.**
|
||||||
|
|
||||||
### 살아 있는 세션에 로그아웃을 걸었다
|
### 살아 있는 세션에 로그아웃을 걸었다
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -200,6 +208,21 @@ app2(oauth2-proxy)는 못 한다. **한 SSO 안에서 로그아웃 전파가 앱
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:50 – 14:53 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-current-state.txt`](evidence/c2-backchannel-logout/01-current-state.txt) | 터미널 원문 |
|
||||||
|
| [`02-configure-idp.txt`](evidence/c2-backchannel-logout/02-configure-idp.txt) | 터미널 원문 |
|
||||||
|
| [`03-logout-attempt.txt`](evidence/c2-backchannel-logout/03-logout-attempt.txt) | 터미널 원문 |
|
||||||
|
| [`04-reachability.txt`](evidence/c2-backchannel-logout/04-reachability.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/c2-backchannel-logout/README.md`](evidence/c2-backchannel-logout/README.md).
|
||||||
|
|
||||||
## 7. 재현 절차 (명령어)
|
## 7. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
| 복구 시간 | **1초** (`15:00:12 → 15:00:13`), **오류 0건** |
|
| 복구 시간 | **1초** (`15:00:12 → 15:00:13`), **오류 0건** |
|
||||||
| 서비스 회복 | **재시작 없이 15초 이내** (`restarts=0`) |
|
| 서비스 회복 | **재시작 없이 15초 이내** (`restarts=0`) |
|
||||||
| 데이터 일치 | **완전 일치** — realms 2 / clients 15 / users 2 / sessions 3 / authclients 1 |
|
| 데이터 일치 | **완전 일치** — realms 2 / clients 15 / users 2 / sessions 3 / authclients 1 |
|
||||||
| **RTO** | 약 **30초** (파괴 감지부터 서비스 복귀까지) |
|
| **RTO** | **41초** (14:59:47 파괴 → 15:00:28 서비스 확인) |
|
||||||
| **RPO** | **마지막 덤프 시점** + A-3 의 `synchronous_commit OFF` 손실 |
|
| **RPO** | **마지막 덤프 시점** + A-3 의 `synchronous_commit OFF` 손실 |
|
||||||
|
|
||||||
**그리고 예상 못 한 것 — 스키마를 통째로 지웠는데 서비스가 `200` 을 계속 냈다.**
|
**그리고 예상 못 한 것 — 스키마를 통째로 지웠는데 서비스가 `200` 을 계속 냈다.**
|
||||||
@@ -169,7 +169,7 @@ volatile 이었다면 세션은 애초에 DB 에 없으므로 **복구해도 전
|
|||||||
15:00:13 복구 완료
|
15:00:13 복구 완료
|
||||||
~15:00:28 서비스 정상 확인
|
~15:00:28 서비스 정상 확인
|
||||||
|
|
||||||
RTO ≈ 30초 (이 규모에서는 대부분이 사람의 판단 시간이다)
|
RTO = 41초 (이 규모에서는 대부분이 사람의 판단 시간이다)
|
||||||
```
|
```
|
||||||
|
|
||||||
### RPO 는 두 겹이다
|
### RPO 는 두 겹이다
|
||||||
@@ -254,6 +254,20 @@ A-4 에서 PVC 가 노드에 묶인 것과 같은 문제이며,
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 14:57 – 14:58 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-backup.txt`](evidence/d1-backup-restore/01-backup.txt) | 터미널 원문 |
|
||||||
|
| [`02-destruction.txt`](evidence/d1-backup-restore/02-destruction.txt) | 터미널 원문 |
|
||||||
|
| [`03-restore.txt`](evidence/d1-backup-restore/03-restore.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/d1-backup-restore/README.md`](evidence/d1-backup-restore/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -7,6 +7,20 @@
|
|||||||
선행: [`D-1`](experiment-d1-backup-restore.md) — **백업이 전제다** ·
|
선행: [`D-1`](experiment-d1-backup-restore.md) — **백업이 전제다** ·
|
||||||
[`A-8`](experiment-a8-rolling-restart.md) — 롤링 재시작이 안전하다는 것이 전제
|
[`A-8`](experiment-a8-rolling-restart.md) — 롤링 재시작이 안전하다는 것이 전제
|
||||||
|
|
||||||
|
> ## ★ 정정 — 이 문서의 결론은 조건부다
|
||||||
|
>
|
||||||
|
> 이 문서는 *"롤백이 안 된다"* 고 단정했다. 나중에
|
||||||
|
> [`후속 문서`](experiment-followup-untested-items.md) 에서 26.7.0 ↔ 26.7.3 을
|
||||||
|
> 시험하니 **롤백이 성공했다.**
|
||||||
|
>
|
||||||
|
> | 버전 차 | `databasechangelog` | 롤백 |
|
||||||
|
> |---|---|---|
|
||||||
|
> | 26.7.0 → 26.0 | 체크섬 불일치 | **불가** |
|
||||||
|
> | 26.7.0 ↔ 26.7.3 | **210 → 210, 변화 없음** | **가능** |
|
||||||
|
>
|
||||||
|
> **판단 기준은 버전 번호가 아니라 `databasechangelog` 의 행 수가 바뀌었는가다.**
|
||||||
|
> 아래 본문은 스키마가 바뀐 경우에 해당한다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0. 결론부터
|
## 0. 결론부터
|
||||||
@@ -176,6 +190,21 @@ kubectl -n keycloak-lab set image statefulset/keycloak keycloak=quay.io/keycloak
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 15:00 – 16:15 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-pre-upgrade.txt`](evidence/d2-version-upgrade/01-pre-upgrade.txt) | 터미널 원문 |
|
||||||
|
| [`02-rollback-attempt.txt`](evidence/d2-version-upgrade/02-rollback-attempt.txt) | 터미널 원문 |
|
||||||
|
| [`03-roll-forward.txt`](evidence/d2-version-upgrade/03-roll-forward.txt) | 터미널 원문 |
|
||||||
|
| [`d2-upgrade-window.png`](evidence/d2-version-upgrade/d2-upgrade-window.png) | 스크린샷 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/d2-version-upgrade/README.md`](evidence/d2-version-upgrade/README.md).
|
||||||
|
|
||||||
## 7. 재현 절차 (명령어)
|
## 7. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -193,6 +193,19 @@ A-0 의 관측 스택에서 `nodes/proxy` 서브리소스를 따로 줘야 했
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 15:05 – 15:06 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-base64-not-encryption.txt`](evidence/d3-secret-management/01-base64-not-encryption.txt) | 터미널 원문 |
|
||||||
|
| [`02-at-rest.txt`](evidence/d3-secret-management/02-at-rest.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/d3-secret-management/README.md`](evidence/d3-secret-management/README.md).
|
||||||
|
|
||||||
## 6. 재현 절차 (명령어)
|
## 6. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -159,6 +159,18 @@ A-1 의 NetworkPolicy, A-3 의 `--grace-period=0`, B-5 의 AOF 모두
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 15:09 – 15:09 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-certificate-state.txt`](evidence/d4-certificate-renewal/01-certificate-state.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/d4-certificate-renewal/README.md`](evidence/d4-certificate-renewal/README.md).
|
||||||
|
|
||||||
## 5. 재현 절차 (명령어)
|
## 5. 재현 절차 (명령어)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -247,3 +247,18 @@ sudo certbot renew --force-renewal
|
|||||||
|
|
||||||
**0.2초 간격으로 재는 이유** — 2절에서 1초 간격으로는 전환을 거의 못 잡았다.
|
**0.2초 간격으로 재는 이유** — 2절에서 1초 간격으로는 전환을 거의 못 잡았다.
|
||||||
nginx reload 는 그보다 훨씬 짧을 것이므로 해상도를 올려야 한다.
|
nginx reload 는 그보다 훨씬 짧을 것이므로 해상도를 올려야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 증거 파일
|
||||||
|
|
||||||
|
**증거 수집 시각: 2026-09-04 15:23 – 16:17 KST** (파일 mtime 기준. 문서 상단의 시각 표기는 작성 시점이라 다를 수 있다.)
|
||||||
|
|
||||||
|
| 파일 | 종류 |
|
||||||
|
|---|---|
|
||||||
|
| [`01-d2-forward-upgrade.txt`](evidence/followup/01-d2-forward-upgrade.txt) | 터미널 원문 |
|
||||||
|
| [`02-d2-rollback-same-schema.txt`](evidence/followup/02-d2-rollback-same-schema.txt) | 터미널 원문 |
|
||||||
|
| [`03-b4-role-propagation.txt`](evidence/followup/03-b4-role-propagation.txt) | 터미널 원문 |
|
||||||
|
| [`04-observability-gap.txt`](evidence/followup/04-observability-gap.txt) | 터미널 원문 |
|
||||||
|
|
||||||
|
파일별 상세는 [`evidence/followup/README.md`](evidence/followup/README.md).
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
| `diagrams/*.svg` | 실험별 구조도 12개 |
|
| `diagrams/*.svg` | 실험별 구조도 12개 |
|
||||||
| `evidence/*/*.png` | Grafana · 브라우저 스크린샷 |
|
| `evidence/*/*.png` | Grafana · 브라우저 스크린샷 |
|
||||||
|
|
||||||
**B층(B-1·B-3·B-4·B-5)에는 Grafana 증거가 없다.** 안 찍은 것이 아니라
|
**스크린샷이 없는 실험은 11개다** — `A-3 A-7 B-3 B-4 B-5 B-6 C-2 D-1 D-3 D-4 후속`.
|
||||||
Prometheus 가 Redis·BFF·PostgreSQL 을 긁지 않는다 —
|
그중 B층은 **Prometheus 가 Redis·BFF·PostgreSQL 을 긁지 않아** 만들 수가 없다 —
|
||||||
[`followup/04-observability-gap.txt`](evidence/followup/04-observability-gap.txt) 에 측정해 두었다.
|
[`followup/04-observability-gap.txt`](evidence/followup/04-observability-gap.txt) 에 측정해 두었다.
|
||||||
|
|
||||||
## 문서 지도
|
## 문서 지도
|
||||||
@@ -51,6 +51,26 @@ Prometheus 가 Redis·BFF·PostgreSQL 을 긁지 않는다 —
|
|||||||
| [`open-questions-coverage.md`](open-questions-coverage.md) | 공개 열린 질문 4개 대조 |
|
| [`open-questions-coverage.md`](open-questions-coverage.md) | 공개 열린 질문 4개 대조 |
|
||||||
| [`session-lab-concepts.md`](session-lab-concepts.md) | 등장 개념 전체 (13층) |
|
| [`session-lab-concepts.md`](session-lab-concepts.md) | 등장 개념 전체 (13층) |
|
||||||
|
|
||||||
|
## 문서가 자기 증거와 어긋났던 곳
|
||||||
|
|
||||||
|
**서브에이전트 감사(2026-09-04)에서 찾아 정정한 것들이다.**
|
||||||
|
|
||||||
|
| 문서 | 무엇이 틀렸나 |
|
||||||
|
|---|---|
|
||||||
|
| C-1 | 세션 수를 `0` 으로 인쇄. 증거는 `4` |
|
||||||
|
| C-2 | `exit code 1` 로 실패한 명령의 성공 출력을 인쇄 |
|
||||||
|
| A-1 | conntrack 삭제에 분단을 귀속. 실제로는 **파드 재시작 4초 뒤** |
|
||||||
|
| A-2 | ④ 의 첫 측정이 오염됐는데 정제된 값만 인쇄 |
|
||||||
|
| A-3 | `wal_writer_delay` 를 재지 않고 "기본값과 맞는다" |
|
||||||
|
| A-6 | 대조군이 −41% 변했는데 "영향 없음" |
|
||||||
|
| A-8 | 표본 9개로 "무중단" |
|
||||||
|
| B-2 | "두 브라우저" — 실제로는 세션만 지웠다. `Liquibase` 오귀속 |
|
||||||
|
| D-1 | RTO 30초 — 실제 41초 |
|
||||||
|
| D-2 | "롤백 불가" 단정 — 조건부였다 |
|
||||||
|
|
||||||
|
**png 6장이 실은 3장**(동일 내용이라 바이트가 같다)이고,
|
||||||
|
`a5/02-injection-verify.txt` 는 0바이트였다. 각 증거 README 에 명시했다.
|
||||||
|
|
||||||
## 반복해서 배운 것 — 주입이 안 걸린 사례
|
## 반복해서 배운 것 — 주입이 안 걸린 사례
|
||||||
|
|
||||||
**아홉 번 있었다. 전부 "아무 일도 없었다" 로 보였다.**
|
**아홉 번 있었다. 전부 "아무 일도 없었다" 로 보였다.**
|
||||||
|
|||||||
Reference in New Issue
Block a user