Saat file ZIP diunggah ke Object Storage Service (OSS), Function Compute dapat secara otomatis mendekompresinya dan menulis file hasil ekstraksi ke lokasi yang ditentukan dalam bucket yang sama. Hal ini menghilangkan kebutuhan untuk menjalankan infrastruktur dekompresi dan memungkinkan skala sesuai dengan volume unggahan Anda.
Cara kerja
File ZIP yang diunggah ke bucket OSS memicu notifikasi event OSS.
Pemicu OSS memanggil fungsi Function Compute dan meneruskan muatan event yang mencakup nama bucket, kunci objek, dan wilayah.
Fungsi tersebut mengunduh file ZIP langsung dari OSS sebagai objek streaming, mendekompresinya di memori, lalu mengunggah setiap file hasil ekstraksi ke awalan output yang dikonfigurasi dalam bucket yang sama.
Catatan penggunaan
Gunakan encoding UTF-8 atau GB2312 untuk nama file dan folder guna menghindari teks rusak selama dekompresi.
Pulihkan objek Archive atau Cold Archive sebelum mendekompresinya.
Tugas dekompresi yang melebihi 2 jam akan gagal. Pastikan ukuran file individual dalam file ZIP tetap di bawah 1 GB untuk menghindari kegagalan dekompresi.
Atur timeout fungsi lebih dari 2 jam, tetapi tidak lebih dari 24 jam.
Buat fungsi di wilayah yang sama dengan bucket OSS.
Jika awalan output pemicu OSS tumpang tindih dengan awalan input, setiap unggahan file hasil ekstraksi akan memicu fungsi lagi, menyebabkan loop tak berujung. Gunakan awalan yang berbeda untuk input dan output — misalnya, src/ untuk file ZIP masuk dan processed/ untuk output hasil ekstraksi.
Prasyarat
Sebelum memulai, pastikan Anda telah:
Mengaktifkan layanan Function Compute. Lihat Prasyarat.
Mengaktifkan layanan OSS dan membuat bucket. Lihat Memulai dengan Konsol OSS.
Langkah 1: Buat fungsi
Login ke Konsol Function Compute. Di panel navigasi kiri, klik Functions.
Di bilah navigasi atas, pilih wilayah. Pada halaman Functions, klik Create Function.
Pada halaman Create Function, konfigurasikan item kunci berikut, lalu klik Create. Untuk item lainnya, lihat Buat fungsi.
Runtime: Pilih Python 3.10.
Function Role: Pilih peran RAM yang sudah ada atau buat yang baru. Sambungkan kebijakan AliyunOSSFullAccess untuk memberikan akses fungsi ke bucket OSS.
Pada halaman detail fungsi, klik tab Code. Di editor kode, buat file berikut dan tempel kode yang sesuai, lalu klik Deploy.
index.py
Fungsi handler adalah titik masuk. Fungsi ini membaca event OSS untuk mendapatkan nama bucket, wilayah, dan kunci objek, kemudian melakukan streaming file ZIP dari OSS dan mengunggah setiap file hasil ekstraksi ke awalan output.
<details> <summary>Klik untuk melihat contoh kode</summary>
# -*- coding: utf-8 -*-
'''
Pernyataan:
Fungsi ini menamai dan mengencode file serta folder sebagai berikut:
1. Untuk MAC/Linux, encoding UTF-8 digunakan secara default.
2. Untuk Windows, encoding GB2312 atau UTF-8 digunakan secara default.
Untuk encoding lainnya, deteksi encoding dilakukan menggunakan library chardet;
namun, akurasi 100% tidak dijamin.
Tulis ulang fungsi ini hanya jika diperlukan, dan pastikan lolos debugging.
'''
import helper
import oss2
import json
import os
import time
import logging
import chardet
"""
Ketika objek dengan awalan source/ ditempatkan di bucket OSS, diharapkan objek tersebut akan didekompresi lalu disimpan di bucket dengan awalan processed/.
Misalnya, source/a.zip akan diproses menjadi processed/a/...
"Source /", "processed/" dapat diubah sesuai kebutuhan.
"""
# Nonaktifkan log info yang dicetak oleh SDK OSS
logging.getLogger("oss2.api").setLevel(logging.ERROR)
logging.getLogger("oss2.auth").setLevel(logging.ERROR)
LOGGER = logging.getLogger()
# Dekorator untuk mencetak waktu eksekusi fungsi
def print_excute_time(func):
def wrapper(*args, **kwargs):
local_time = time.time()
ret = func(*args, **kwargs)
LOGGER.info('current Function [%s] excute time is %.2f' %
(func.__name__, time.time() - local_time))
return ret
return wrapper
def get_zipfile_name(origin_name): # Mengatasi masalah teks Cina yang rusak
name = origin_name
try:
name_bytes = origin_name.encode(encoding="cp437")
except:
name_bytes = origin_name.encode(encoding="utf-8")
# Jika string yang akan dideteksi cukup panjang, akurasi hasil deteksi lebih tinggi
detect = chardet.detect(name_bytes)
confidence = detect["confidence"]
detect_encoding = detect["encoding"]
if confidence > 0.75 and (detect_encoding.lower() in ["gb2312", "gbk", "gb18030", "ascii", "utf-8"]):
try:
if detect_encoding.lower() in ["gb2312", "gbk", "gb18030"]:
detect_encoding = "gb18030"
name = name_bytes.decode(detect_encoding)
except:
name = name_bytes.decode(encoding="gb18030")
else:
try:
name = name_bytes.decode(encoding="gb18030")
except:
name = name_bytes.decode(encoding="utf-8")
# Perbaiki \\ windows sebagai segmen direktori
name = name.replace("\\", "/")
return name
@print_excute_time
def handler(event, context):
"""
Objek dari OSS akan didekompresi secara otomatis.
param: event: String JSON event OSS, termasuk URI objek OSS dan informasi lainnya.
param: context: Konteks fungsi, termasuk kredensial dan informasi waktu proses.
"""
evt_lst = json.loads(event)
creds = context.credentials
auth = oss2.StsAuth(
creds.access_key_id,
creds.access_key_secret,
creds.security_token)
evt = evt_lst['events'][0]
bucket_name = evt['oss']['bucket']['name']
endpoint = 'oss-' + evt['region'] + '-internal.aliyuncs.com'
bucket = oss2.Bucket(auth, endpoint, bucket_name)
object_name = evt['oss']['object']['key']
if "ObjectCreated:PutSymlink" == evt['eventName']:
object_name = bucket.get_symlink(object_name).target_key
if object_name == "":
raise RuntimeError('{} adalah file symlink yang tidak valid'.format(
evt['oss']['object']['key']))
file_type = os.path.splitext(object_name)[1]
if file_type != ".zip":
raise RuntimeError('{} bukan file zip'.format(object_name))
LOGGER.info("mulai mendekompresi file zip = {}".format(object_name))
lst = object_name.split("/")
zip_name = lst[-1]
PROCESSED_DIR = os.environ.get("PROCESSED_DIR", "")
RETAIN_FILE_NAME = os.environ.get("RETAIN_FILE_NAME", "")
if PROCESSED_DIR and PROCESSED_DIR[-1] != "/":
PROCESSED_DIR += "/"
if RETAIN_FILE_NAME == "false":
newKey = PROCESSED_DIR
else:
newKey = PROCESSED_DIR + zip_name
zip_fp = helper.OssStreamFileLikeObject(bucket, object_name)
newKey = newKey.replace(".zip", "/")
with helper.zipfile_support_oss.ZipFile(zip_fp) as zip_file:
for name in zip_file.namelist():
with zip_file.open(name) as file_obj:
name = get_zipfile_name(name)
bucket.put_object(newKey + name, file_obj)</details>
helper.py
File helper.py membungkus bucket OSS sebagai objek mirip file sehingga library ZIP dapat membaca langsung dari OSS tanpa mengunduh seluruh file terlebih dahulu.
<details> <summary>Klik untuk melihat contoh kode</summary>
# -*- coding: utf-8 -*-
import oss2
from oss2 import utils, models
import ossZipfile as zipfile
zipfile_support_oss = zipfile
# Mendukung unggah ke OSS sebagai objek mirip file
def make_crc_adapter(data, init_crc=0):
data = utils.to_bytes(data)
# Objek mirip file
if hasattr(data, 'read'):
return utils._FileLikeAdapter(data, crc_callback=utils.Crc64(init_crc))
utils.make_crc_adapter = make_crc_adapter
class OssStreamFileLikeObject(object):
def __init__(self, bucket, key):
super(OssStreamFileLikeObject, self).__init__()
self._bucket = bucket
self._key = key
self._meta_data = self._bucket.get_object_meta(self._key)
@property
def bucket(self):
return self._bucket
@property
def key(self):
return self._key
@property
def filesize(self):
return self._meta_data.content_length
def get_reader(self, begin, end):
begin = begin if begin >= 0 else 0
end = end if end > 0 else self.filesize - 1
end = end if end < self.filesize else self.filesize - 1
begin = begin if begin < end else end
return self._bucket.get_object(self._key, byte_range=(begin, end))
def get_content_bytes(self, begin, end):
reader = self.get_reader(begin, end)
return reader.read()
def get_last_content_bytes(self, offset):
return self.get_content_bytes(self.filesize-offset, self.filesize-1)</details>
ossZipfile.py
File ossZipfile.py adalah versi modifikasi dari modul zipfile standar Python yang mendukung pembacaan entri ZIP sebagai rentang byte dari OSS, bukan dari file lokal. Salin seluruh isi ossZipfile.py dari dokumen sumber dan tempelkan ke file ini di editor kode.
Langkah 2: Buat pemicu OSS
Pada halaman detail fungsi, klik tab Configurations, lalu klik Triggers di panel navigasi kiri.
Klik Create Trigger. Di panel yang terbuka, pilih jenis pemicu OSS dan konfigurasikan item kunci berikut, lalu klik OK. Untuk item lainnya, lihat Konfigurasi pemicu OSS native.
Item Nilai contoh Bucket Name Pilih bucket yang telah Anda buat Object Prefix srcObject Suffix zipTrigger Event oss:ObjectCreated:PutObject,oss:ObjectCreated:PostObject,oss:ObjectCreated:CompleteMultipartUpload,oss:ObjectCreated:PutSymlinkRole Name Pilih peran RAM dengan kebijakan AliyunFCFullAccess
Setelah pemicu dibuat, pemicu tersebut akan muncul di halaman Triggers.
Langkah 3: Uji dan verifikasi
Gunakan salah satu metode berikut untuk memastikan pipeline berfungsi dari ujung ke ujung.
Metode 1: Unggah file melalui Konsol OSS
Login ke Konsol Object Storage Service.
Unggah file ZIP (misalnya,
code.zip) ke awalansrc/bucket yang Anda pilih di Langkah 2.Setelah unggahan selesai, buka daftar file bucket dan pastikan file hasil ekstraksi muncul di direktori root (atau di awalan output yang Anda konfigurasi).
Metode 2: Picu fungsi dengan event uji
Gunakan metode ini untuk menguji logika fungsi tanpa mengunggah file nyata — berguna saat melakukan iterasi pada kode fungsi.
Pada halaman detail fungsi, klik tab Code. Klik ikon
di samping Test Function dan pilih Configure Test Parameters.Di panel Configure Test Parameters, pilih Event Template, masukkan Event Name, tempel muatan event berikut, lalu klik OK.
PentingFile ZIP yang ditentukan oleh
object.keyharus sudah ada di bucket. Jika tidak, pemanggilan fungsi akan gagal.Parameter Format Tempat menemukannya bucket.arnacs:oss:<region>:<account_id>:<bucket_name>ID Akun terdapat di halaman Overview Konsol Function Compute bucket.nameNama bucket Anda Konsol OSS bucket.ownerIdentityID akun Alibaba Cloud Anda Pusat akun object.keyJalur ke file ZIP yang ada di bucket, misalnya src/test.zipKonsol OSS regionWilayah tempat Anda membuat fungsi, misalnya cn-hangzhouKonsol Function Compute userIdentity.principalIdID akun Alibaba Cloud Anda Pusat akun { "events": [ { "eventName": "ObjectCreated:PutObject", "eventSource": "acs:oss", "eventTime": "2023-08-13T06:45:43.000Z", "eventVersion": "1.0", "oss": { "bucket": { "arn": "acs:oss:cn-hangzhou:10343546824****:bucket****", "name": "bucket****", "ownerIdentity": "10343546824****" }, "object": { "deltaSize": 122539, "eTag": "688A7BF4F233DC9C88A80BF985AB****", "key": "src/test.zip", "size": 122539 }, "ossSchemaVersion": "1.0", "ruleId": "9adac8e253828f4f7c0466d941fa3db81161****" }, "region": "cn-hangzhou", "requestParameters": { "sourceIPAddress": "140.205.XX.XX" }, "responseElements": { "requestId": "58F9FF2D3DF792092E12044C" }, "userIdentity": { "principalId": "10343546824****" } } ] }Ganti placeholder berikut dengan nilai aktual Anda: Untuk daftar lengkap parameter event, lihat Langkah 2: (Opsional) Konfigurasi parameter input.
Klik Test Function di tab Code.
Setelah fungsi selesai dijalankan, login ke Konsol Object Storage Service dan verifikasi bahwa file ZIP target (misalnya,
src/test.zip) telah didekompresi ke dalam bucket. Lihat Gunakan Konsol OSS untuk mengkueri objek.
Pembersihan
Jika Anda tidak lagi memerlukan pengaturan ini, hapus sumber daya berikut untuk menghindari biaya berkelanjutan:
Fungsi Function Compute
Pemicu OSS yang dilampirkan ke fungsi
Peran RAM yang dibuat untuk fungsi (jika dibuat khusus untuk tutorial ini)
Langkah selanjutnya
Untuk mempelajari lebih lanjut tentang pemicu OSS, lihat Ikhtisar.
Untuk menggunakan Function Compute guna mengemas dan mengunduh file dari OSS, lihat Unduh beberapa objek sebagai paket.
Untuk informasi lebih lanjut tentang bucket dan objek OSS, lihat Bucket dan Objek.