Design and Evolution of a Cloud Video Surveillance Storage Service (Versions 2.0–4.0)
This article details the architecture, chunked upload strategy, event handling, Redis caching, database sharding, and performance optimizations of a cloud‑based video surveillance storage system that evolved through versions 2.0, 3.0, and 4.0 to handle high‑concurrency alarm video uploads.
In December 2015 the team launched a cloud video storage service for surveillance applications, enabling devices such as cameras, phones, and drones to capture video, detect motion, trigger alarms, and upload the recorded alarm clips to Amazon S3 for later playback.
The system consists of a client, a web server, a database, and an S3 file‑storage server; S3 was chosen for its low cost compared to self‑hosted storage. To achieve near‑real‑time upload of alarm videos (≈30 seconds), the team implemented a chunked‑upload mechanism that pre‑calculates a chunk size (about 10 seconds of video), fills incomplete chunks with empty data, and records I‑frame positions for accurate seeking.
Upload interaction follows three steps: (1) the client requests an EVENTID from the web server to uniquely identify the alarm; (2) for each chunk the client obtains a signed upload URI from the web server (the client never holds AWS credentials), e.g., http://xxxxxxxxxxxxxxxxxxxxxxxx/eventid/index.avi , where index increments per chunk; (3) after each chunk upload the client reports the event metadata (trigger time, type, duration, resolution, audio sample rate, and the current index) to the web server, allowing the playback side to list incomplete videos and enabling immediate image capture on alarm.
Version 2.0 added a simple Redis cache that stored only the daily event count per client, reducing MySQL read pressure for the recent‑30‑day statistics.
Version 3.0 decoupled video data from events: files are stored independently, and a mapping table records the start and end positions of each event within a file. This reduced database UPDATE operations, allowed multiple events to share a single file, and introduced richer Redis caching of event details (timestamp, duration, icon) keyed by date, client ID, and type, eliminating many database reads. A “condensed video” feature compressed a day’s footage into a short clip, but its batch upload at midnight caused a sudden spike of requests that temporarily overwhelmed the single MySQL instance.
Version 4.0 focused on alleviating database load: per‑day sharding of event, file, and mapping tables, using the event‑ID prefix to encode the trigger date for direct routing, and planning asynchronous writes and eventual sharding across multiple databases. Horizontal scaling of the web tier is handled by Nginx load balancing, while the database remains a bottleneck that will require further partitioning and possibly a move to a distributed architecture.
The overall lesson emphasizes that before adopting clusters or distributed systems, solid single‑node performance, efficient data models, and thoughtful caching are essential for sustainable high‑concurrency services.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.