ਆਬਜੈਕਟ ਸਟੋਰੇਜ ਵਿਰੁੱਧ ਡੇਟਾਬੇਸ ਬਲੌਬ: ਫਾਈਲ ਮੈਟਾਡੇਟਾ ਨੂੰ Postgres ਵਿੱਚ ਮਾਡਲ ਕਰੋ, ਬਾਈਟਸ ਨੂੰ object storage ਵਿੱਚ ਰੱਖੋ, ਅਤੇ ਤੇਜ਼ ਡਾਊਨਲੋਡਸ ਨਾਲ ਲਾਗਤ ਪੇਸ਼ਗੀ ਅਨੁਮਾਨਯੋਗ ਰੱਖੋ।

ਯੂਜ਼ਰ ਅਪਲੋਡਸ ਆਸਾਨ ਲੱਗਦੇ ਹਨ: ਇੱਕ ਫਾਈਲ ਲਓ, ਇਸਨੂੰ ਸੇਵ ਕਰੋ, ਬਾਅਦ ਵਿੱਚ ਦਿਖਾਓ। ਛੋਟੇ ਯੂਜ਼ਰ ਅਤੇ ਛੋਟੀਆਂ ਫਾਈਲਾਂ ਨਾਲ ਇਹ ਚੱਲਦਾ ਹੈ। ਫਿਰ ਵੱਧਦਾ ਮਾਤਰਾ, ਫਾਈਲਾਂ ਵੱਡੀਆਂ ਹੋ ਜਾਂਦੀਆਂ ਹਨ, ਅਤੇ ਦਰਦ ਉਹਨਾਂ ਥਾਵਾਂ 'ਤੇ ਆਉਂਦੀ ਹੈ ਜੋ ਅਪਲੋਡ ਬਟਨ ਨਾਲ ਸਿੱਧਾ ਸੰਬੰਧਿਤ ਨਹੀਂ ਹੁੰਦੀਆਂ।
ਡਾਊਨਲੋਡ ਸਲੋ ਹੋ ਜਾਂਦੇ ਹਨ ਕਿਉਂਕਿ ਤੁਹਾਡਾ ਐਪ ਸਰਵਰ ਜਾਂ ਡੇਟਾਬੇਸ ਭਾਰੀ ਕੰਮ ਕਰ ਰਿਹਾ ਹੁੰਦਾ ਹੈ। ਬੈਕਅੱਪ ਵੱਡੇ ਅਤੇ ਸੁਸਤ ਹੋ ਜਾਂਦੇ ਹਨ, ਇਸ ਲਈ ਰੀਸਟੋਰ ਕਰਨ ਵਿੱਚ ਵੇਲਾ ਲੱਗਦਾ ਹੈ ਓਦੋਂ ਹੀ ਜਦੋਂ ਤੁਹਾਨੂੰ ਲੋੜ ਹੁੰਦੀ ਹੈ। ਸਟੋਰੇਜ ਅਤੇ ਬੈਂਡਵਿਡਥ (egress) ਦੇ ਬਿੱਲ ਉੱਠ ਸਕਦੇ ਹਨ ਕਿਉਂਕਿ ਫਾਈਲਾਂ ਅਣਅਧਿਕਾਰਿਤ ਰੂਪ ਨਾਲ ਸਰਵ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਡੁਪਲੀਕੇਟ ਹੁੰਦੀਆਂ ਹਨ ਜਾਂ ਕਦੇ ਸਾਫ਼ ਨਹੀਂ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ।
ਤੁਹਾਨੂੰ ਆਮ ਤੌਰ 'ਤੇ ਬੋਰਿੰਗ ਅਤੇ ਭਰੋਸੇਯੋਗ ਚਾਹੀਦਾ ਹੈ: ਲੋਡ ਹੇਠਾਂ ਤੇਜ਼ ਟਰਾਂਸਫਰ, ਸਪਸ਼ਟ ਐਕਸੈਸ ਨਿਯਮ, ਸਧਾਰਨ ਓਪਰੇਸ਼ਨ (ਬੈਕਅੱਪ, ਰੀਸਟੋਰ, ਕਲੀਨਅਪ), ਅਤੇ ਖਰਚ ਜੋ ਵਰਤੋਂ ਵਧਣ ਨਾਲ ਅਨੁਮਾਨਯੋਗ ਰਹਿਣ।
ਇਸ ਤੱਕ ਪਹੁੰਚਣ ਲਈ, ਉਹ ਦੋ ਚੀਜ਼ਾਂ ਅਲੱਗ ਕਰੋ ਜੋ ਅਕਸਰ ਮਿਲ ਕੇ ਰਹਿ ਜਾਂਦੀਆਂ ਹਨ:
ਮੈਟਾਡੇਟਾ ਉਹ ਛੋਟੀ ਜਾਣਕਾਰੀ ਹੈ ਫਾਈਲ ਬਾਰੇ: ਕਿਸ ਦੀ ਹੈ, ਕੀ ਨਾਮ ਹੈ, ਸਾਈਜ਼, ਟਾਈਪ, ਕਦੋਂ ਅਪਲੋਡ ਹੋਈ, ਅਤੇ ਕਿੱਥੇ ਰਹਿੰਦੀ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਡੇਟਾਬੇਸ (ਜਿਵੇਂ Postgres) ਵਿੱਚ ਰਹਿਣੀ ਚਾਹੀਦੀ ਹੈ ਕਿਉਂਕਿ ਤੁਸੀਂ ਇਸਨੂੰ ਕੁਇਰੀ, ਫਿਲਟਰ ਅਤੇ ਜੋੜ ਕਰਨ ਦੀ ਲੋੜ ਰੱਖਦੇ ਹੋ।
ਫਾਈਲ ਬਾਈਟਸ ਫਾਈਲ ਦੀ ਅਸਲ ਸਮੱਗਰੀ ਹੈ (ਫੋਟੋ, PDF, ਵੀਡੀਓ)। ਡੇਟਾਬੇਸ ਵਿੱਚ ਬਾਈਟਸ ਰੱਖਣਾ ਕਾਮ ਕਰ ਸਕਦਾ ਹੈ, ਪਰ ਇਸ ਨਾਲ ਡੇਟਾਬੇਸ ਭਾਰੀ ਹੋ ਜਾਂਦਾ ਹੈ, ਬੈਕਅੱਪ ਵੱਡੇ ਹੋ ਜਾਂਦੇ ਹਨ ਅਤੇ ਪ੍ਰਦਰਸ਼ਨ ਅਨਪੇਸ਼ਿਤ ਹੋ ਸਕਦਾ ਹੈ। ਬਾਈਟਸ ਨੂੰ object storage ਵਿੱਚ ਰੱਖ ਕੇ ਡੇਟਾਬੇਸ ਉਹੀ ਕੰਮ ਕਰਦਾ ਹੈ ਜਿਸ ਵਿੱਚ ਉਹ ਬੇਹਤਰ ਹੈ, ਜਦਕਿ ਫਾਈਲਾਂ ਉਹਨਾਂ ਸਿਸਟਮਾਂ ਦੁਆਰਾ ਤੇਜ਼ ਅਤੇ ਸਸਤੇ ਤਰੀਕੇ ਨਾਲ ਸਰਵ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ ਜੋ ਇਸ ਕੰਮ ਲਈ ਬਣੇ ਹਨ।
ਜਦੋਂ ਲੋਕ ਕਹਿੰਦੇ ਹਨ "ਅਪਲੋਡ ਡੇਟਾਬੇਸ ਵਿੱਚ ਰੱਖੋ," ਉਹ ਆਮ ਤੌਰ 'ਤੇ ਡੇਟਾਬੇਸ ਬਲੌਬ ਦੀ ਗੱਲ ਕਰ ਰਹੇ ਹੁੰਦੇ ਹਨ: ਜਾਂ ਤਾਂ ਇੱਕ BYTEA ਕਾਲਮ (ਰੋ ਵਿੱਚ ਕਚਾ ਬਾਈਟਸ) ਜਾਂ Postgres "large objects" (ਇੱਕ ਫੀਚਰ ਜੋ ਵੱਡੀਆਂ ਵੈਲਯੂਜ਼ ਨੂੰ ਅਲੱਗ ਰੱਖਦਾ ਹੈ)। ਦੋਹਾਂ ਚੱਲ ਸਕਦੇ ਹਨ, ਪਰ ਦੋਹਾਂ ਨਾਲ ਤੁਹਾਡਾ ਡੇਟਾਬੇਸ ਫਾਈਲ ਬਾਈਟਸ ਸਰਵ ਕਰਨ ਲਈ ਜ਼ਿੰਮੇਵਾਰ ਹੋ ਜਾਂਦਾ ਹੈ।
ਆਬਜੈਕਟ ਸਟੋਰੇਜ ਇਕ ਵੱਖਰਾ ਵਿਚਾਰ ਹੈ: ਫਾਈਲ ਇੱਕ ਬੱਕਟ ਵਿੱਚ ਇੱਕ ਆਬਜੈਕਟ ਵਜੋਂ ਰਹਿੰਦੀ ਹੈ, ਇੱਕ ਕੀ ਨਾਲ ਪਹੁੰਚੀ ਜਾਂਦੀ ਹੈ (ਉਦੇਹਰਨ ਲਈ uploads/2026/01/file.pdf)। ਇਹ ਵੱਡੀਆਂ ਫਾਈਲਾਂ, ਸਸਤੇ ਸਟੋਰੇਜ ਅਤੇ ਸਟ੍ਰੀਮਿੰਗ ਡਾਊਨਲੋਡ ਲਈ ਬਣਿਆ ਹੁੰਦਾ ਹੈ। ਇਹ ਇਕੱਠੇ ਪੱਧਰ 'ਤੇ ਬਹੁਤੀਆਂ ਪੜ੍ਹਾਈਆਂ ਸੰਭਾਲਦਾ ਹੈ ਬਿਨਾਂ ਤੁਹਾਡੇ ਡੇਟਾਬੇਸ ਕਨੈਕਸ਼ਨਾਂ ਨੂੰ ਰੋਕੇ।
Postgres ਕੁਇਰੀਆਂ, ਕੰਸਟ੍ਰੈਂਟਸ ਅਤੇ ਟ੍ਰਾਂਜ਼ੈਕਸ਼ਨਾਂ ਵਿੱਚ ਚਮਕਦਾ ਹੈ। ਇਹ ਮੈਟਾਡੇਟਾ ਲਈ ਵਧੀਆ ਹੈ: ਕਿਸੀ ਦੀ ਫਾਈਲ ਕਿਸਦੀ ਹੈ, ਕੀ ਹੈ, ਕਦੋਂ ਅਪਲੋਡ ਹੋਈ, ਅਤੇ ਕੀ ਡਾਊਨਲੋਡ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ। ਉਹ ਮੈਟਾਡੇਟਾ ਛੋਟੀ ਹੁੰਦੀ ਹੈ, ਇੰਡੈਕਸ ਕਰਨ ਵਿੱਚ ਆਸਾਨ ਹੁੰਦੀ ਹੈ ਅਤੇ ਲਗਾਤਾਰ ਰੱਖਣਾ ਆਸਾਨ ਹੁੰਦਾ ਹੈ।
ਇਕ ਪ੍ਰਾਇਕਟਿਕ ਨਿਯਮ:
ਇੱਕ ਤੁਰੰਤ ਸੈਨੀਟੀ ਚੈੱਕ: ਜੇ ਬੈਕਅੱਪ, ਰਿੱਪਲਿਕਾ ਅਤੇ ਮਾਈਗ੍ਰੇਸ਼ਨ ਫਾਈਲ ਬਾਈਟਸ ਸ਼ਾਮਲ ਹੋਣ ਨਾਲ ਮੁਸ਼ਕਲ ਹੋ ਜਾਣਗੇ, ਤਾਂ ਬਾਈਟਸ ਨੂੰ Postgres ਦੇ ਬਾਹਰ ਰੱਖੋ।
ਜ਼ਿਆਦਾਤਰ ਟੀਮਾਂ ਜੋ ਰਸਤਾ ਲੱਭਦੀਆਂ ਹਨ ਉਹ ਸਿੱਧਾ ਹੈ: ਬਾਈਟਸ ਨੂੰ object storage ਵਿੱਚ ਰੱਖੋ, ਅਤੇ ਫਾਈਲ ਰਿਕਾਰਡ (ਕਿਉਂਕਿ ਕੌਣ ਮਾਲਕ ਹੈ, ਕੀ ਹੈ, ਕਿੱਥੇ ਹੈ) Postgres ਵਿੱਚ ਰੱਖੋ। ਤੁਹਾਡੀ API ਕੋਆਰਡਿਨੇਟ ਕਰਦੀ ਹੈ ਅਤੇ ਮਨਜ਼ੂਰੀ ਦਿੰਦੀ ਹੈ, ਪਰ ਇਹ ਵੱਡੇ ਅਪਲੋਡ ਅਤੇ ਡਾਊਨਲੋਡਸ ਨੂੰ ਪ੍ਰੌਕਸੀ ਨਹੀਂ ਕਰਦੀ।
ਇਸ ਨਾਲ ਤੁਹਾਡੇ ਕੋਲ ਤਿੰਨ ਸਾਫ਼ ਜ਼ਿੰਮੇਵਾਰੀਆਂ ਹੁੰਦੀਆਂ ਹਨ:
file_id, ਮਾਲਕ, ਸਾਈਜ਼, content type, ਅਤੇ object pointer।ਉਹ ਸਥਿਰ file_id ਸਭ ਕੁਝ ਲਈ ਪ੍ਰਾਇਮਰੀ ਕੀ ਬਣ ਜਾਂਦਾ ਹੈ: ਇੱਕ ਟਿੱਪਣੀ ਜੋ ਇੱਕ ਅਟੈਚਮੈਂਟ ਨੂੰ ਦਰਸਾਉਂਦੀ ਹੈ, ਇੱਕ ਇਨਵਾਇਸ ਜੋ PDF ਵੱਲ ਪੁਆਇੰਟ ਕਰਦੀ ਹੈ, ਆਡਿਟ ਲੌਗ ਅਤੇ ਸਹਾਇਤਾ ਟੂਲ। ਯੂਜ਼ਰ ਫਾਈਲ ਦਾ ਨਾਮ ਬਦਲ ਸਕਦੇ ਹਨ, ਤੁਸੀਂ ਇਹਨੂੰ ਬੱਕਟਾਂ ਵਿੱਚ ਹਿਲਾ ਸਕਦੇ ਹੋ, ਪਰ file_id ਇੱਕੋ ਰਹਿੰਦਾ ਹੈ।
ਜਦੋਂ ਸੰਭਵ ਹੋਵੇ, ਸਟੋਰ ਕੀਤੀਆਂ ਆਬਜੈਕਟਾਂ ਨੂੰ ਅਚਲ (immutable) ਵਜੋਂ ਸੋਚੋ। ਜੇ ਯੂਜ਼ਰ ਇੱਕ ਦਸਤਾਵੇਜ਼ ਬਦਲਦਾ ਹੈ, ਤਾਂ ਇੱਕ ਨਵਾਂ ਆਬਜੈਕਟ ਬਣਾਓ (ਅਕਸਰ ਇੱਕ ਨਵਾਂ ਰੋ ਜਾਂ ਨਵਾਂ ਵਰਜ਼ਨ ਰੋ) ਬਣਾਉਣ ਦੀ ਥਾਂ ਤੇ ਜ਼ਗ੍ਹਾ ਤੇ ਓਵਰਰਾਈਟ ਨਾ ਕਰੋ। ਇਹ caching ਨੂੰ ਆਸਾਨ ਬਣਾਉਂਦਾ ਹੈ, "ਪੁਰਾਣਾ ਲਿੰਕ ਨਵੀਂ ਫਾਈਲ ਦਿੰਦਾ ਹੈ" ਵਾਲੀਆਂ ਹੈਰਾਨੀਆਂ ਤੋਂ ਬਚਾਉਂਦਾ ਹੈ, ਅਤੇ ਤੁਹਾਨੂੰ ਸਾਫ਼ ਰੋਲਬੈਕ ਕਹਾਣੀ ਦਿੰਦਾ ਹੈ।
Privacy ਦਾ ਫੈਸਲਾ ਜਲਦੀ ਕਰੋ: ਮੁਲਤਵੀ ਤੌਰ ਤੇ ਨਿੱਜੀ ਰੱਖੋ, ਅਤੇ ਜਦੋਂ ਹੀ ਲੋੜ ਹੋਵੇ ਹੀ ਜਨਤਕ ਕਰੋ। ਇੱਕ ਚੰਗਾ ਨਿਯਮ ਹੈ: ਡੇਟਾਬੇਸ ਫਾਈਲ ਤੱਕ ਪਹੁੰਚ ਕੌਣ ਕਰ ਸਕਦਾ ਹੈ ਦਾ ਸੋਰਸ ਆਫ਼ ਟਰੂਥ ਹੋਵੇ; object storage ਉਸ ਛੋਟੇ ਸਮੇਂ ਦੀ ਪਰਮਿਸ਼ਨ ਲਾਗੂ ਕਰਦਾ ਜੋ ਤੁਹਾਡੀ API ਦਿੰਦੀ ਹੈ।
ਸਾਫ਼ ਵੰਡ ਨਾਲ, Postgres ਫਾਈਲ ਬਾਰੇ ਤੱਥ ਰੱਖਦਾ ਹੈ ਅਤੇ object storage ਬਾਈਟਸ ਰੱਖਦਾ ਹੈ। ਇਸ ਨਾਲ ਤੁਹਾਡਾ ਡੇਟਾਬੇਸ ਛੋਟਾ ਰਹਿੰਦਾ ਹੈ, ਬੈਕਅੱਪ ਤੇਜ਼ ਹੁੰਦੇ ਹਨ ਅਤੇ ਕੁਇਰੀਆਂ ਸਾਦੀਆਂ ਰਹਿਣਦੀਆਂ ਹਨ।
ਇੱਕ ਪ੍ਰਾਇਕਟਿਕ uploads ਟੇਬਲ ਨੂੰ ਕੁਝ ਖੇਤਰਾਂ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ ਤਾਂ ਕਿ ਇਹ ਸਵਾਲਾਂ ਦੇ ਜਵਾਬ ਦੇ ਸਕੇ: "ਇਹ ਕਿਸ ਦੀ ਹੈ?", "ਇਹ ਕਿੱਥੇ ਸਟੋਰ ਹੈ?", ਅਤੇ "ਕੀ ਇਹ ਡਾਊਨਲੋਡ ਕਰਨ ਯੋਗ ਹੈ?"
CREATE TABLE uploads (
id uuid PRIMARY KEY,
owner_id uuid NOT NULL,
bucket text NOT NULL,
object_key text NOT NULL,
size_bytes bigint NOT NULL,
content_type text,
original_filename text,
checksum text,
state text NOT NULL CHECK (state IN ('pending','uploaded','failed','deleted')),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX uploads_owner_created_idx ON uploads (owner_id, created_at DESC);
CREATE INDEX uploads_checksum_idx ON uploads (checksum);
ਕੁਝ ਫੈਸਲੇ ਜੋ ਬਾਅਦ ਵਿੱਚ ਦਰਦ ਬਚਾਉਂਦੇ ਹਨ:
bucket + object_key ਵਰਤੋਂ। ਅਪਲੋਡ ਹੋਣ ਤੋਂ ਬਾਅਦ ਇਸਨੂੰ ਅਚਲ ਰੱਖੋ।pending ਰੋ ਇਨਸਰਟ ਕਰੋ। ਸਿਰਫ਼ ਉਸ ਵਾਰ ਹੀ uploaded ਨੂੰ ਫਲੈਪ ਕਰੋ ਜਦੋਂ ਤੁਹਾਡੀ ਪ੍ਰਣਾਲੀ ਪੁਸ਼ਟੀ ਕਰੇ ਕਿ ਆਬਜੈਕਟ ਮੌਜੂਦ ਹੈ ਅਤੇ ਸਾਈਜ਼ (ਅਤੇ ਸੰਭਵਤ: checksum) ਮਿਲਦੀ ਹੈ।original_filename ਨੂੰ ਸਿਰਫ਼ ਡਿਸਪਲੇ ਲਈ ਰੱਖੋ। ਇਸਨੂੰ ਕਿਸੇ ਟਾਈਪ ਜਾਂ ਸੁਰੱਖਿਆ ਫੈਸਲੇ ਲਈ ਭਰੋਸਾ ਨਾ ਕਰੋ।ਜੇ ਤੁਸੀਂ ਰੀਪਲੇਸਮੈਂਟ ਸਹਿਯੋਗ ਕਰਦੇ ਹੋ (ਜਿਵੇਂ ਯੂਜ਼ਰ ਇੱਕ ਇਨਵਾਇਸ ਦੁਬਾਰਾ ਅਪਲੋਡ ਕਰਦਾ ਹੈ), ਤਾਂ ਇੱਕ ਵੱਖਰੀ upload_versions ਟੇਬਲ ਸ਼ਾਮਲ ਕਰੋ ਜਿਸ ਵਿੱਚ upload_id, version, object_key, ਅਤੇ created_at ਹੋਵੇ। ਇਸ ਤਰ੍ਹਾਂ ਤੁਸੀਂ ਇਤਿਹਾਸ ਰੱਖ ਸਕਦੇ ਹੋ, ਗਲਤੀਆਂ ਰੋਲਬੈਕ ਕਰ ਸਕਦੇ ਹੋ, ਅਤੇ ਪੁਰਾਣੀਆਂ ਰੇਫਰੰਸਾਂ ਨੂੰ ਨਾ ਤੋੜੋ।
ਆਪਣੀ API ਨੂੰ ਕੋਆਰਡੀਨੇਸ਼ਨ ਸੰਭਾਲਣੀ ਦਿਓ, ਨਾ ਕਿ ਫਾਈਲ ਬਾਈਟਸ। ਤੁਹਾਡਾ ਡੇਟਾਬੇਸ ਰੇਸਪਾਂਸਿਵ ਰਹੇਗਾ, ਜਦਕਿ object storage ਬੈਂਡਵਿਡਥ ਸਹਾਰੇਗਾ।
ਸ਼ੁਰੂਆਤ ਕਰੋ ਇੱਕ ਅਪਲੋਡ ਰਿਕਾਰਡ ਬਣਾਉਣ ਨਾਲ ਓਸ ਤੋਂ ਪਹਿਲਾਂ ਕਿ ਕੁਝ ਵੀ ਭੇਜਿਆ ਜਾਵੇ। ਤੁਹਾਡੀ API ਇੱਕ upload_id ਵਾਪਸ ਕਰੇਗੀ, ਜਿੱਥੇ ਫਾਈਲ ਰਹੇਗੀ (object_key), ਅਤੇ ਇਕ ਛੋਟੇ ਸਮੇਂ ਦੀ ਅਪਲੋਡ ਪਰਮਿਸ਼ਨ।
ਇੱਕ ਆਮ ਫਲੋ:
pending ਰੋ ਬਣਾਉਂਦੀ ਹੈ, ਉਮੀਦ ਕੀਤੀ ਸਾਈਜ਼ ਅਤੇ ਮਨਜ਼ੂਰ ਕੀਤੀ ਸਮੱਗਰੀ ਟਾਈਪ ਦੇ ਨਾਲ।upload_id ਅਤੇ ਸਟੋਰੇਜ ਰਿਸਪਾਂਸ ਫੀਲਡ (ਜਿਵੇਂ ETag) ਨਾਲ ਤੁਹਾਡੀ API ਨੂੰ ਕਾਲ ਕਰਦਾ ਹੈ। ਤੁਹਾਡਾ ਸਰਵਰ ਸਾਈਜ਼, ਚੈਕਸਮ (ਜੇ ਤੁਸੀਂ ਵਰਤਦੇ ਹੋ) ਅਤੇ ਸਮੱਗਰੀ ਟਾਈਪ ਦੀ ਪੁਸ਼ਟੀ ਕਰਦਾ ਹੈ, ਫਿਰ ਰੋ ਨੂੰ uploaded ਮਾਰਕ ਕਰਦਾ ਹੈ।failed ਮਾਰਕ ਕਰੋ ਅਤੇ ਚਾਹੇ ਤਾਂ ਆਬਜੈਕਟ ਮਿਟਾ ਦਿਓ।ਰੀਟ੍ਰਾਈ ਅਤੇ ਡੁਪਲਿਕੇਟ ਆਮ ਹਨ। ਫਾਈਨਲਾਈਜ਼ ਕਾਲ ਨੂੰ idempotent ਬਣਾਓ: ਜੇ ਉਹੀ upload_id ਦੁਬਾਰਾ ਫਾਈਨਲਾਈਜ਼ ਕੀਤਾ ਜਾਵੇ, ਤਾਂ ਬਦਲਾਅ ਕੀਤੇ ਬਿਨਾਂ ਸਫਲਤਾ ਵਾਪਸ ਕਰੋ।
ਰੀਟ੍ਰਾਈਆਂ ਅਤੇ ਮੁੜ-ਅਪਲੋਡ ਨੂੰ ਘਟਾਉਣ ਲਈ, ਇੱਕ ਚੈਕਸਮ ਸਟੋਰ ਕਰੋ ਅਤੇ "ਉਹੀ ਮਾਲਕ + ਉਹੀ ਚੈਕਸਮ + ਉਹੀ ਸਾਈਜ਼" ਨੂੰ ਇਕੋ ਫਾਈਲ ਸਮਝੋ।
ਇੱਕ ਚੰਗੀ ਡਾਊਨਲੋਡ ਫਲੋ ਤੁਹਾਡੇ ਐਪ ਵਿੱਚ ਇੱਕ ਸਥਿਰ URL ਨਾਲ ਸ਼ੁਰੂ ਹੁੰਦੀ ਹੈ, ਭਾਵੇਂ ਬਾਈਟਸ ਕਿੱਥੇ ਵੀ ਹੋਣ। ਸੋਚੋ: /files/{file_id}। ਤੁਹਾਡੀ API file_id ਨਾਲ Postgres ਵਿੱਚ ਮੈਟਾਡੇਟਾ ਲੂੰਦੀ ਹੈ, ਪਰਵਾਨਗੀ ਜਾਂਚਦੀ ਹੈ, ਫਿਰ ਫੈਸਲਾ ਕਰਦੀ ਹੈ ਕਿ ਫਾਈਲ ਕਿਵੇਂ ਦਿੱਤੀ ਜਾਵੇ।
file_id ਨਾਲ ਬੇਨਤੀ ਕਰਦਾ ਹੈ।uploaded ਹੈ।Redirects ਪਬਲਿਕ ਜਾਂ ਅਰਧ-ਜਨਤਕ ਫਾਈਲਾਂ ਲਈ ਸਧਾਰਨ ਅਤੇ ਤੇਜ਼ ਹਨ। ਨਿੱਜੀ ਫਾਈਲਾਂ ਲਈ, ਪ੍ਰੀਸਾਇਨਡ GET URLs ਸਟੋਰੇਜ ਨੂੰ ਨਿੱਜੀ ਰੱਖਦੇ ਹੋਏ ਬਰਾਊਜ਼ਰ ਨੂੰ ਸੀਧਾ ਡਾਊਨਲੋਡ ਕਰਨ ਦਿੰਦੇ ਹਨ।
ਵੀਡੀਓ ਅਤੇ ਵੱਡੀਆਂ ਡਾਊਨਲੋਡਸ ਲਈ ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਹਾਡੀ object storage (ਅਤੇ ਕੋਈ ਵੀ ਪ੍ਰਾਕਸੀ ਲੇਅਰ) Range ਹੇਡਰ ਸਮਰਥਨ ਕਰਦੀ ਹੈ। ਇਹ ਸੀਕਿੰਗ ਅਤੇ ਰੇਜ਼ਯੂਮੇਬਲ ਡਾਊਨਲੋਡ ਦੀ ਸਹਾਇਤਾ ਕਰਦਾ ਹੈ। ਜੇ ਤੁਸੀਂ ਬਾਈਟਸ ਆਪਣੇ API ਰਾਹੀਂ ਫੰਨਲ ਕਰਦੇ ਹੋ, ਤਾਂ Range ਸਹਾਇਤਾ ਅਕਸਰ ਟੁੱਟ ਜਾਂ ਮਹਿੰਗੀ ਹੋ ਜਾਂਦੀ ਹੈ।
Caching ਹੀ ਸਪੀਡ ਦਾ ਸਰੋਤ ਹੈ। ਤੁਹਾਡਾ ਸਥਿਰ /files/{file_id} ਐਂਡਪਾਇੰਟ ਆਮ ਤੌਰ 'ਤੇ non-cacheable ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ (ਇਹ ਇੱਕ auth gate ਹੈ), ਜਦਕਿ object storage ਦਾ ਪ੍ਰਤੀਕ੍ਰਿਆ ਸਮੱਗਰੀ ਦੇ ਆਧਾਰ 'ਤੇ ਕੈਸ਼ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ। ਜੇ ਫਾਈਲਾਂ ਅਚਲ ਹਨ (ਨਵੀਂ ਅਪਲੋਡ = ਨਵੀਂ ਕੀ), ਤਾਂ ਤੁਸੀਂ ਲੰਬਾ cache lifetime ਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ। ਜੇ ਤੁਸੀਂ ਫਾਈਲਾਂ ਓਵਰਰਾਈਟ ਕਰਦੇ ਹੋ, ਤਾਂ cache ਸਮੇਂ ਛੋਟੇ ਰੱਖੋ ਜਾਂ ਵਰਜ਼ਨ ਕੀਜ਼ ਵਰਤੋਂ।
ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਬਹੁਤ ਸਾਰੇ ਗਲੋਬਲ ਯੂਜ਼ਰ ਜਾਂ ਵੱਡੀਆਂ ਫਾਈਲਾਂ ਹੁੰਦੀਆਂ ਹਨ, ਇੱਕ CDN ਮਦਦਗਾਰ ਹੁੰਦਾ ਹੈ। ਜੇ ਤੁਹਾਡੀ ਦਰਸ਼ਕ ਸਮੂਹ ਛੋਟਾ ਜਾਂ ਇੱਕ ਖੇਤਰ ਤੱਕ ਸੀਮਤ ਹੈ, ਤਾਂ object storage ਅਕਸਰ ਕਾਫ਼ੀ ਅਤੇ ਸਸਤਾ ਹੁੰਦਾ ਹੈ।
ਹੈਰਾਨੀ ਵਾਲੇ ਬਿੱਲ ਆਮ ਤੌਰ 'ਤੇ ਡਾਊਨਲੋਡ ਅਤੇ churn (ਦੁਹਰਾਈ) ਤੋਂ ਆਉਂਦੇ ਹਨ, ਨਾਂ ਕਿ ਸਿਰਫ਼ ਡਿਸਕ 'ਤੇ ਪਈਆਂ ਬਾਈਟਸ ਤੋਂ।
ਉਹ ਚਾਰ ਡ੍ਰਾਈਵਰਾਂ ਨੂੰ ਕੀਮਤ ਲੱਗਣ ਵਿੱਚ ਧਿਆਨ ਦਿਓ: ਤੁਸੀਂ ਕਿੰਨਾ ਸਟੋਰ ਕਰਦੇ ਹੋ, ਕਿੰਨਾ ਅਕਸੈਸ (ਰੀਕਵੇਸਟ) ਹੁੰਦਾ ਹੈ, ਕਿੰਨਾ ਡੇਟਾ ਬਾਹਰ ਜਾਂਦਾ ਹੈ (egress), ਅਤੇ ਕੀ ਤੁਸੀਂ ਕਈ ਵਾਰੀ origine ਤੋਂ CDN ਵਰਤਦੇ ਹੋ। ਇੱਕ ਛੋਟੀ ਫਾਈਲ ਜੋ 10,000 ਵਾਰੀ ਡਾਊਨਲੋਡ ਹੁੰਦੀ ਹੈ, ਉਹ ਕਿਸੇ ਵੱਡੀ ਫਾਈਲ ਦੀ तुलना ਵਿੱਚ ਮਹਿੰਗੀ ਪੈ ਸਕਦੀ ਹੈ ਜੇ ਉਹ ਕਦੇ ਵੀ ਡਾਊਨਲੋਡ ਨਾ ਕੀਤੀ ਹੋਵੇ।
ਖਰਚੇ ਨੂੰ ਕਾਬੂ ਵਿੱਚ ਰੱਖਣ ਵਾਲੇ ਨਿਯੰਤਰਣ:
ਲਾਈਫਸਾਈਕਲ ਨਿਯਮ ਆਮ ਤੌਰ 'ਤੇ ਸਭ ਤੋਂ ਆਸਾਨ ਜਿੱਤ ਹੁੰਦੀ ਹੈ। ਉਦਾਹਰਣ ਲਈ: ਮੁਲਤਵੀ ਤੌਰ 'ਤੇ ਅਸਲ ਫੋਟੋਆਂ 30 ਦਿਨ "ਹੌਟ" ਰੱਖੋ, ਫਿਰ ਉਹਨਾਂ ਨੂੰ ਇੱਕ ਸਸਤੇ ਸਟੋਰੇਜ ਕਲਾਸ ਵਿੱਚ ਮੂਵ ਕਰੋ; ਇਨਵਾਇਸ 7 ਸਾਲ ਲਈ ਰੱਖੋ; failed upload ਹਿੱਸਿਆਂ ਨੂੰ 7 ਦਿਨਾਂ ਬਾਅਦ ਹਟਾ ਦਿਓ। ਇਹ ਬੇਸਿਕ ਰੀਟੇਂਸ਼ਨ ਨੀਤੀਆਂ ਸਟੋਰੇਜ ਕਾਰਮ ਨੂੰ ਰੋਕਦੀਆਂ ਹਨ।
ਡਿਡੂਪਲੀਕੇਸ਼ਨ ਸਧਾਰਨ ਹੋ ਸਕਦੀ ਹੈ: ਫਾਈਲ ਮੈਟਾਡੇਟਾ ਟੇਬਲ ਵਿੱਚ ਇੱਕ ਸਮੱਗਰੀ ਹੈਸ਼ (ਜਿਵੇਂ SHA-256) ਸਟੋਰ ਕਰੋ ਅਤੇ ਮਾਲਕ ਪ੍ਰਤੀ ਯੂਨਿਕਨੈੱਸ ਲਗਾਉ। ਜਦੋਂ ਇੱਕ ਯੂਜ਼ਰ ਇੱਕੋ PDF ਦੁਬਾਰਾ ਅਪਲੋਡ ਕਰਦਾ ਹੈ, ਤੁਸੀਂ ਮੌਜੂਦਾ ਆਬਜੈਕਟ ਦੁਬਾਰਾ ਵਰਤ ਸਕਦੇ ਹੋ ਅਤੇ ਸਿਰਫ਼ ਨਵਾਂ ਮੈਟਾਡੇਟਾ ਰੋ ਬਣਾਉ।
ਅਖੀਰ ਵਿੱਚ, ਉਪਯੋਗਤਾ ਦੇ ਆਕੜੇ ਉਨ੍ਹਾਂ ਥਾਵਾਂ ਉੱਤੇ ਰੱਖੋ ਜਿੱਥੇ ਤੁਸੀਂ ਪਹਿਲਾਂ ਹੀ ਖਾਤਾਬੰਦੀ ਕਰਦੇ ਹੋ: Postgres। ਪ੍ਰਤੀ-ਯੂਜ਼ਰ ਜਾਂ ਵਰਕਸਪੇਸ bytes_uploaded, bytes_downloaded, object_count, ਅਤੇ last_activity_at ਰੱਖੋ। ਇਸ ਨਾਲ UI ਵਿੱਚ ਸੀਮਾਵਾਂ ਦਿਖਾਉਣਾ ਅਤੇ ਬਿੱਲ ਤੋਂ ਪਹਿਲਾਂ ਅਲਰਟ ਜਾਰੀ ਕਰਨਾ ਆਸਾਨ ਹੁੰਦਾ ਹੈ।
ਅਪਲੋਡਸ ਲਈ ਸੁਰੱਖਿਆ ਮੁਢਲੀ ਤੌਰ 'ਤੇ ਦੋ ਚੀਜ਼ਾਂ 'ਤੇ ਨਿਰਭਰ ਕਰਦੀ ਹੈ: ਫਾਈਲ ਤੱਕ ਕੌਣ ਪਹੁੰਚ ਸਕਦਾ ਹੈ, ਅਤੇ ਜੇ ਕੁਝ ਗਲਤ ਹੋਈ ਤਾਂ ਤੁਸੀਂ ਬਾਅਦ ਵਿੱਚ ਕੀ ਸਾਬਤ ਕਰ ਸਕਦੇ ਹੋ।
ਇਕ ਸਪਸ਼ਟ ਐਕਸੈਸ ਮਾਡਲ ਨਾਲ ਸ਼ੁਰੂ ਕਰੋ ਅਤੇ ਉਸਨੂੰ Postgres ਮੈਟਾਡੇਟਾ ਵਿੱਚ ਐਨਕੋਡ ਕਰੋ, ਨਾ ਕਿ ਸੇਵਾਵਾਂ ਵਿੱਚ ਵੱਖ-ਵੱਖ ਫੈਲ੍ਹੇ ਨਿਯਮਾਂ ਵਿੱਚ।
ਇੱਕ ਸਧਾਰਣ ਮਾਡਲ ਜੋ ਜ਼ਿਆਦਾਤਰ ਐਪਸ ਨੂੰ ਕਵਰ ਕਰਦਾ ਹੈ:
ਨਿੱਜੀ ਫਾਈਲਾਂ ਲਈ, ਰਾ
Postgres ਨੂੰ ਉਹ ਮੈਟਾਡੇਟਾ ਦੇਣ ਜੋ ਤੁਸੀਂ ਕੁਇਰੀ ਅਤੇ ਸੁਰੱਖਿਆ ਲਈ ਲੋੜੀਂਦਾ ਹੈ (owner, permissions, state, checksum, pointer)। ਬਾਈਟਸ ਨੂੰ object storage ਵਿੱਚ ਰੱਖੋ ਤਾਂ ਕਿ ਡਾਊਨਲੋਡ ਅਤੇ ਵੱਡੇ ਟ੍ਰਾਂਸਫਰ ਡੇਟਾਬੇਸ ਕਨੈਕਸ਼ਨਾਂ ਨੂੰ ਘੇਰ ਨਾ ਲੈਣ ਅਤੇ ਬੈਕਅੱਪ ਵੱਡੇ ਨਾ ਹੋਣ।
ਇਹ ਤੁਹਾਡੇ ਡੇਟਾਬੇਸ ਨੂੰ ਫਾਈਲ ਸਰਵਰ ਵਾਂਗ ਵਰਤਣ ਲਗਦਾ ਹੈ। ਟੇਬਲ ਸਾਈਜ਼ ਵੱਧਦਾ ਹੈ, ਬੈਕਅੱਪ ਅਤੇ ਰੀਸਟੋਰ ਸਲੇਟੇ ਹੋ ਜਾਂਦੇ ਹਨ, ਰਿਪਲਿਕੇਸ਼ਨ ਲੋਡ ਵੱਧ ਜਾਂਦਾ ਹੈ, ਅਤੇ ਜਦੋਂ ਬਹੁਤ ਸਾਰੇ ਯੂਜ਼ਰ ਇੱਕੋ ਸਮੇਂ ਡਾਊਨਲੋਡ ਕਰਦੇ ਹਨ ਤਾਂ ਪ੍ਰਦਰਸ਼ਨ ਘਟ ਸਕਦਾ ਹੈ।
ਹਾਂ। ਐਪ ਵਿੱਚ ਇੱਕ ਸਥਿਰ file_id ਰੱਖੋ, ਮੈਟਾਡੇਟਾ Postgres ਵਿੱਚ ਸਟੋਰ ਕਰੋ, ਅਤੇ ਬਾਈਟਸ object storage ਵਿੱਚ ਰੱਖੋ ਜਿਹੜੇ bucket ਅਤੇ object_key ਨਾਲ ਪਹੁੰਚੇ ਜਾਂ। ਤੁਹਾਡੀ API ਐਕਸੈਸ ਅਧਿਕਾਰ ਦਿੰਦੀ ਹੈ ਅਤੇ ਛੋਟੇ ਸਮੇਂ ਵਾਲੀਆਂ ਅਪਲੋਡ/ਡਾਊਨਲੋਡ ਪਰਮਿਸ਼ਨ ਦਿੰਦੀ ਹੈ, ਬਾਈਟਸ ਨੂੰ ਪ੍ਰੌਕਸੀ ਨਹੀਂ ਕਰਦੀ।
ਪਹਿਲਾਂ ਇੱਕ pending ਰੋਡ ਬਣਾਓ, ਇਕ ਯੂਨੀਕ object_key ਜਨਰੇਟ ਕਰੋ, ਫਿਰ ਕਲਾਇਂਟ ਨੂੰ ਛੋਟੇ ਸਮੇਂ ਵਾਲੀ ਪਰਮਿਸ਼ਨ ਨਾਲ ਸਟੋਰੇਜ 'ਤੇ ਸੀਧਾ ਅਪਲੋਡ ਕਰਨ ਦਿਓ। ਅਪਲੋਡ ਮੁਕੰਮਲ ਹੋਣ 'ਤੇ ਕਲਾਇਂਟ ਇੱਕ ਫਾਈਨਲਾਈਜ਼ ਕਾਲ ਕਰੇ ਤਾਂ ਕਿ ਸਰਵਰ ਸਾਈਜ਼ ਅਤੇ ਚੈਕਸਮ ਜਾਂਚ ਕੇ ਰੋਡ ਨੂੰ uploaded ਕਰ ਦੇਵੇ।
ਅਸਲ ਦਰਅਸਲ ਅਪਲੋਡ ਅਸਫਲ ਅਤੇ ਰੀਟ੍ਰਾਈ ਹੁੰਦੇ ਹਨ। ਇੱਕ state ਫੀਲਡ ਤੋਂ ਤੁਹਾਨੂੰ ਇਹ ਪਤਾ ਲੱਗਦਾ ਹੈ ਕਿ ਕਿਹੜੀਆਂ ਫਾਈਲਾਂ ਉਮੀਦ ਕੀਤੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ ਪਰ ਮੌਜੂਦ ਨਹੀਂ (pending), ਕਿਹੜੀਆਂ ਮੁਕੰਮਲ ਹੋਈਆਂ (uploaded), ਕਿਹੜੀਆਂ ਖ਼ਰਾਬ ਹੋਈਆਂ (failed) ਅਤੇ ਕਿਹੜੀਆਂ ਹਟਾਈਆਂ ਗਈਆਂ (deleted) — ਇਸ ਨਾਲ UI, ਕਲੀਨਅਪ ਨੌਕਰੀਆਂ ਅਤੇ ਸਪੋਰਟ ਟੂਲ ਸਹੀ ਤਰੀਕੇ ਨਾਲ ਕੰਮ ਕਰਦੇ ਹਨ।
original_filename ਨੂੰ ਸਿਰਫ ਡਿਸਪਲੇ ਲਈ ਰੱਖੋ। ਸਟੋਰੇਜ ਲਈ ਇੱਕ ਯੂਨੀਕ ਕੀ (ਅਕਸਰ UUID-ਆਧਾਰਤ ਪਾਥ) ਜਨਰੇਟ ਕਰੋ ਤਾਂ ਕਿ ਟਕਰਾਵ, ਅਜੀਬ ਅੱਖਰ ਅਤੇ ਸੁਰੱਖਿਆ ਸਮੱਸਿਆਵਾਂ ਤੋਂ ਬਚਿਆ ਜਾ ਸਕੇ। ਤੁਸੀਂ UI ਵਿੱਚ ਅਸਲ ਨਾਮ ਦਿਖਾ ਸਕਦੇ ਹੋ ਪਰ ਸਟੋਰੇਜ ਪੈਥ ਸਾਫ਼ ਤੇ ਪੇਸ਼ਗੋਈਯੋਗ ਰੱਖੋ।
ਇੱਕ ਸਥਿਰ ਐਪ URL ਜਿਵੇਂ /files/{file_id} ਨੂੰ ਪਰਮਿਸ਼ਨ ਗੇਟ ਰੱਖੋ। Postgres ਵਿੱਚ ਐਕਸੈਸ ਦੀ ਜਾਂਚ ਕਰਨ ਤੋਂ ਬਾਅਦ, redirect ਭੇਜੋ ਜਾਂ ਨਿੱਜੀ ਫਾਈਲਾਂ ਲਈ ਛੋਟੇ ਸਮੇਂ ਵਾਲਾ signed GET URL दें, ਤਾਂ ਕਿ ਕਲਾਇਂਟ ਸੀਧਾ object storage ਤੋਂ ਡਾਊਨਲੋਡ ਕਰੇ ਅਤੇ ਤੁਹਾਡੀ API ਹਾਟ ਪਾਥ ਵਿੱਚ ਨਾ ਫੈਂਸੀ।
ਜ਼ਿਆਦਾਤਰ ਖਰਚਾ ਡਾਊਨਲੋਡ ਅਤੇ ਦੁਹਰਾਈ ਵਾਲੀਆਂ ਰਿਕਵੇਸਟਾਂ ਤੋਂ ਆਉਂਦਾ ਹੈ, ਨਾ ਕਿ ਸਿਰਫ ਡਿਸਕ 'ਤੇ ਪਈਆਂ ਫਾਈਲਾਂ ਤੋਂ। ਫਾਈਲ ਸਾਈਜ਼ ਸੀਮਤ ਕਰੋ ਅਤੇ ਯੂਜ਼ਰ-ਅਨੁਸਾਰ ਕੋਟਾ ਰੱਖੋ, ਰੀਟੇਨਸ਼ਨ ਨੀਤੀਆਂ ਵਰਤੋ, ਚੈਕਸਮ ਦੇ ਨਾਲ ਡਿਡੂਪਲਿਕੇਟ ਕਰੋ ਜਿੱਥੇ ਲੋੜ ਹੋਵੇ ਅਤੇ ਉਪਯੋਗਤਾ ਗਿਣਤੀਆਂ Postgres ਵਿੱਚ ਰੱਖੋ ਤਾਂ ਕਿ ਤੁਸੀਂ ਬਿੱਲ ਬਾਰੇ ਚੇਂਤਾਵਾਂ ਪਹਿਲਾਂ ਹੀ ਦੇਖ ਸਕੋ।
ਆਧਾਰਿਕ ਚੀਜ਼ਾਂ: permissions ਅਤੇ visibility ਨੂੰ Postgres ਵਿੱਚ ਸੋਰਸ ਆਫ਼ ਟਰੂਥ ਵਜੋਂ ਰੱਖੋ; ਸਟੋਰੇਜ ਨੂੰ ਮੂਲ ਰੂਪ ਵਿੱਚ ਨਿੱਜੀ ਰੱਖੋ; ਅਪਲੋਡ ਤੋਂ ਪਹਿਲਾਂ ਅਤੇ ਬਾਅਦ type ਤੇ size ਵੈਰੀਫਾਈ ਕਰੋ; HTTPS ਇੰਡੀ-ਟੂ-ਇੰਡੀ ਰੱਖੋ; at-rest ਇਨਕ੍ਰਿਪਸ਼ਨ ਯਕੀਨੀ ਬਣਾਓ; ਅਤੇ ਆਡਿਟ ਫੀਲਡ (ਜਿਵੇਂ uploaded_by, ip, user_agent, last_accessed_at) ਰੱਖੋ ਤਾਂ ਕਿ ਤੁਸੀਂ ਘਟਨਾਵਾਂ ਦੀ ਜਾਂਚ ਕਰ ਸਕੋ।
ਇੱਕ ਮੈਟਾਡੇਟਾ ਟੇਬਲ, ਇਕ direct-to-storage ਅਪਲੋਡ ਫਲੋ ਅਤੇ ਇੱਕ ਡਾਊਨਲੋਡ ਗੇਟ ਏਂਡਪਾਇੰਟ ਨਾਲ ਸ਼ੁਰੂ ਕਰੋ। ਫਿਰ orphaned objects ਲਈ ਕਲੀਨਅਪ ਨੌਕਰੀਆਂ ਅਤੇ soft-delete ਹੇਠਾਂ cleanup ਸ਼ਾਮਲ ਕਰੋ। React/Go/Postgres ਸਟੈਕ 'ਤੇ ਤੁਰੰਤ ਪ੍ਰੋਟੋਟਾਈਪ ਲਈ Koder.ai (koder.ai) ਤੁਹਾਡੇ ਲਈ ਸਕੈਫੋਲਡ ਜਨਰੇਟ ਕਰ ਸਕਦਾ ਹੈ ਅਤੇ ਬਹੁਤ ਸਾਰਾ ਬੁਨਿਆਦੀ ਕੰਮ ਬਚਾ ਸਕਦਾ ਹੈ।