Spot instans dapat ditarik kembali kapan saja. Saat penarikan kembali akan segera terjadi, CloudMonitor mengirimkan notifikasi ke Simple Message Queue (SMQ), memberi aplikasi Anda waktu untuk menyimpan status dan membersihkan sumber daya. Panduan ini menjelaskan langkah-langkah lengkap pengaturannya: membuat antrian SMQ, berlangganan ke event interupsi ECS, mensimulasikan event, serta menulis penanganan yang mengambil dan memproses notifikasi tersebut.
Cara kerja
Ketika CloudMonitor mendeteksi event interupsi spot instans, notifikasi tersebut didorong ke antrian SMQ yang ditentukan dalam kebijakan langganan Anda. Aplikasi Anda melakukan polling terhadap antrian, mendekode isi pesan yang dikodekan Base64, lalu mengurai muatan JSON untuk mengidentifikasi instans yang terdampak. Setelah menangani event tersebut, hapus pesan dari antrian agar tidak diproses ulang.
Prasyarat
Sebelum memulai, pastikan Anda telah memiliki:
Akun Alibaba Cloud dengan Pengguna RAM yang dikonfigurasi untuk akses programatik. Akun Alibaba Cloud memiliki semua izin atas sumber daya. Jika pasangan AccessKey akun Alibaba Cloud Anda bocor, sumber daya Anda berisiko terpapar. Kami menyarankan Anda menggunakan pasangan AccessKey Pengguna RAM. Untuk informasi lebih lanjut, lihat Buat pasangan AccessKey.
Kebijakan
AliyunMNSFullAccessyang dilampirkan pada Pengguna RAMKredensial AccessKey untuk Pengguna RAM yang disimpan sebagai variabel lingkungan (lihat Konfigurasikan variabel lingkungan di Linux, macOS, dan Windows)
Titik akhir SMQ yang telah dikonfigurasi (lihat Konfigurasikan titik akhir)
Java dan Maven yang telah diinstal
Tambahkan dependensi SDK SMQ
Tambahkan kode berikut ke file pom.xml Anda:
<dependencies>
<!-- Alibaba Cloud SMQ SDK -->
<dependency>
<groupId>com.aliyun.mns</groupId>
<artifactId>aliyun-sdk-mns</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>Untuk metode instalasi lainnya, lihat Instal SDK SMQ untuk Java.
Buat antrian SMQ
Buat antrian untuk menerima notifikasi interupsi spot instans dari CloudMonitor.
Masuk ke Konsol SMQ. Di panel navigasi sebelah kiri, pilih Queue Model > Queues.
Di bilah navigasi atas, pilih wilayah. Pada halaman Queues, klik Create Queue.
Pada panel Create Queue, konfigurasikan parameter yang diperlukan lalu klik OK.

Buat kebijakan langganan
Kebijakan langganan memberi tahu CloudMonitor ke mana notifikasi event harus didorong. Konfigurasikan kebijakan ini agar meneruskan event interupsi spot instans ke antrian yang baru saja Anda buat.
Masuk ke Konsol CloudMonitor. Di panel navigasi sebelah kiri, pilih Event Center > Event Subscription.
Pada tab Subscription Policy, klik Create Subscription Policy.
Atur Subscription Type menjadi System Events.

Konfigurasikan Subscription Scope seperti yang ditunjukkan di bawah ini.

Di bawah Push and Integration, klik Add Channel, lalu klik Increase Channels. Pilih antrian SMQ yang telah Anda buat dan ikuti petunjuk di layar untuk menyelesaikan konfigurasi saluran dorong. Untuk detail opsi saluran dorong, lihat Kelola saluran dorong. Untuk daftar lengkap parameter langganan, lihat Kelola langganan event.
Simulasikan event interupsi
Interupsi spot instans bersifat tidak dapat diprediksi, sehingga CloudMonitor menyediakan alat Debug Event Subscription untuk mensimulasikannya selama pengembangan.
Pada tab Subscription Policy, klik Debug Event Subscription.
Pada panel Create Event Debugging, atur Products menjadi Elastic Compute Service (ECS) dan Name menjadi
Instance:PreemptibleInstanceInterruption. Sistem secara otomatis menghasilkan muatan JSON. Perbarui nilai placeholder dengan informasi instans aktual Anda:Ganti
<Alibaba Cloud account ID>dengan ID akun Alibaba Cloud Anda.Ganti
<resource-id>dan<instanceId>dengan ID spot instans tersebut.Ganti
<Region ID>dengan ID wilayah spot instans tersebut.
Field Description nameJenis event. Periksa field ini untuk memastikan pesan tersebut merupakan event interupsi. content.instanceIdID spot instans yang akan ditarik kembali. content.actionTindakan yang diambil. deleteberarti instans akan dihentikan dan ditarik kembali.levelTingkat keparahan event. Misalnya, WARNmenunjukkan adanya event interupsi.{ "product": "ECS", "resourceId": "acs:ecs:cn-shanghai:<Alibaba Cloud account ID>UID:instance/<resource-id>", "level": "WARN", "instanceName": "instanceName", "regionId": "<Region ID>", "groupId": "0", "name": "Instance:PreemptibleInstanceInterruption", "content": { "instanceId": "<instanceId>", "instanceName": "wor***b73", "action": "delete" }, "status": "Normal" }Field utama dalam muatan event:
Klik OK. CloudMonitor mengirimkan peringatan simulasi ke antrian SMQ Anda.
Ambil dan tanggapi pesan
Contoh Java berikut menunjukkan cara mengambil notifikasi interupsi dari SMQ dan meresponsnya. Contoh ini menggunakan tugas konversi gambar ke skala abu-abu sebagai pengganti beban kerja nyata — pola yang sama berlaku untuk pekerjaan apa pun yang dapat diinterupsi.
Kode contoh lengkap
import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.common.utils.ServiceSettings;
import com.aliyun.mns.model.Message;
import org.json.JSONObject;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Base64;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Pemroses gambar yang dapat diinterupsi dan mendukung shutdown yang mulus saat spot instans ditarik kembali.
*
* Perilaku utama:
* - Menyimpan progres setiap 50 baris diproses (mekanisme checkpoint)
* - Merespons segera ketika event interupsi diterima dari SMQ
* - Menulis hasil parsial ke partial_output.jpg saat terjadi interupsi
*/
public class InterruptibleImageProcessor implements Runnable {
// AtomicBoolean untuk kontrol status aman thread
private final AtomicBoolean running = new AtomicBoolean(true);
// Menyimpan gambar yang sedang diproses
private BufferedImage processedImage;
// Progres pemrosesan (0-100)
private int progress;
/**
* Mengonversi gambar ke skala abu-abu menggunakan rata-rata tertimbang ITU-R BT.601:
* Gray = 0.30*R + 0.59*G + 0.11*B
*
* Menyimpan progres setiap 50 baris untuk meminimalkan kehilangan data saat interupsi.
*/
public void convertToGrayScale(File inputFile, File outputFile) throws Exception {
BufferedImage original = ImageIO.read(inputFile);
int width = original.getWidth();
int height = original.getHeight();
processedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
for (int y = 0; y < height && running.get(); y++) {
for (int x = 0; x < width; x++) {
// Periksa flag interupsi thread pada setiap piksel
if (Thread.interrupted()) {
throw new InterruptedException("Pemrosesan gambar diinterupsi");
}
// Pisahkan saluran ARGB
int rgb = original.getRGB(x, y);
int r = (rgb >> 16) & 0xFF; // Saluran merah
int g = (rgb >> 8) & 0xFF; // Saluran hijau
int b = rgb & 0xFF; // Saluran biru
// Terapkan rata-rata tertimbang
int gray = (int)(0.3 * r + 0.59 * g + 0.11 * b);
// Bangun kembali RGB dari nilai skala abu-abu
processedImage.setRGB(x, y, (gray << 16) | (gray << 8) | gray);
// Perbarui persentase progres (catatan: pembagian integer)
progress = (y * width + x) * 100 / (width * height);
}
// Simpan checkpoint setiap 50 baris
if (y % 50 == 0) {
saveProgress(outputFile);
}
}
// Simpan hasil akhir
ImageIO.write(processedImage, "jpg", outputFile);
}
/**
* Menyimpan status pemrosesan saat ini ke file sementara.
* Menggunakan pendekatan silent-fail agar proses penyimpanan itu sendiri tidak terganggu.
*/
private void saveProgress(File outputFile) {
try {
// Tulis ke file sementara agar tidak menimpa output akhir
ImageIO.write(processedImage, "jpg", new File("partial_output.jpg"));
} catch (Exception e) {
System.err.println("Penyimpanan otomatis gagal: " + e.getMessage());
}
}
/**
* Titik masuk thread.
* Saat diinterupsi: menyimpan progres saat ini, lalu menginterupsi kembali thread
* untuk mempertahankan semantik interupsi bagi pemanggil.
*/
@Override
public void run() {
try {
convertToGrayScale(new File("input.jpg"), new File("output.jpg"));
Thread.sleep(5000); // Mensimulasikan tugas berdurasi panjang
System.out.println("Pemrosesan gambar selesai");
} catch (InterruptedException e) {
System.out.println("Pemrosesan diinterupsi pada " + progress + "%");
saveProgress(new File("partial_output.jpg"));
Thread.currentThread().interrupt(); // Pulihkan status interupsi
} catch (Exception e) {
System.err.println("Menangani error: " + e.getMessage());
}
}
/**
* Memberi sinyal kepada pemroses untuk berhenti setelah baris saat ini selesai.
*/
public void stop() {
running.set(false);
}
/**
* Metode utama: menjalankan pemroses gambar, melakukan polling SMQ untuk event interupsi,
* dan mematikan pemroses secara mulus saat event tersebut diterima.
*/
public static void main(String[] args) throws InterruptedException {
// Inisialisasi klien SMQ menggunakan kredensial dari variabel lingkungan
CloudAccount account = new CloudAccount(
ServiceSettings.getMNSAccessKeyId(),
ServiceSettings.getMNSAccessKeySecret(),
ServiceSettings.getMNSAccountEndpoint());
MNSClient client = account.getMNSClient();
// Jalankan tugas pemrosesan gambar di thread latar belakang
InterruptibleImageProcessor processor = new InterruptibleImageProcessor();
Thread processThread = new Thread(processor);
processThread.start();
try {
// Lakukan polling terhadap antrian SMQ untuk notifikasi interupsi
CloudQueue queue = client.getQueueRef("spot-interruption");
Message popMsg = queue.popMessage();
if (popMsg != null) {
// Isi pesan dari SMQ dikodekan Base64 secara default
System.out.println("Isi pesan mentah: " + popMsg.getMessageBodyAsRawString());
// Dekode dan uraikan muatan JSON
byte[] decodedBytes = Base64.getDecoder().decode(popMsg.getMessageBodyAsRawString());
String decodedString = new String(decodedBytes);
System.out.println("Pesan terdekripsi: " + decodedString);
JSONObject json = new JSONObject(decodedString);
String name = json.getString("name");
// Periksa apakah ini event interupsi spot instans
if ("Instance:PreemptibleInstanceInterruption".equals(name)) {
System.out.println("Spot instans akan segera ditarik kembali. Mematikan sistem...");
// Beri sinyal kepada pemroses untuk berhenti dan tunggu hingga selesai
processor.stop();
processThread.interrupt();
processThread.join();
System.out.println("Shutdown selesai");
// Hapus pesan agar tidak diproses ulang
queue.deleteMessage(popMsg.getReceiptHandle());
}
}
} catch (Exception e) {
System.out.println("Error tak terduga: ");
e.printStackTrace();
}
client.close();
}
}Contoh ini menggunakan tugas konversi gambar ke skala abu-abu untuk menunjukkan pola penanganan interupsi. Gantilah logika pemrosesan gambar dengan beban kerja Anda sendiri. Pola inti — penyimpanan checkpoint, flag stop atomik, dan penghapusan pesan SMQ setelah ditangani — berlaku untuk pekerjaan berdurasi panjang apa pun pada spot instans.
Langkah berikutnya
Untuk membuat Snapshot disk sebelum instans ditarik kembali, lihat CreateSnapshot.
Untuk membuat gambar kustom dari instans sebelum penarikan kembali, lihat CreateImage.
Untuk strategi menyimpan dan memulihkan data yang tersimpan di spot instans, lihat Retain and restore data.