All Products
Search
Document Center

Elastic Compute Service:Tangani gangguan spot instans dengan Simple Message Queue

Last Updated:May 16, 2026

Gunakan Simple Message Queue (formerly MNS) untuk menerima notifikasi gangguan spot instans dan memicu logika shutdown yang mulus sebelum reclaim.

Ikhtisar alur kerja

Prasyarat

  1. Buat AccessKey

    Gunakan AccessKey dari Pengguna RAM dengan izin minimum yang diperlukan, bukan akun root. Lihat Buat AccessKey.

  2. Berikan izin kepada Pengguna RAM

    Berikan izin berikut kepada Pengguna RAM untuk mengonsumsi pesan dari Simple Message Queue (MNS):

    Produk Cloud

    Berikan izin

    Simple Message Queue (SMQ, formerly MNS)

    AliyunMNSFullAccess

  3. Konfigurasikan kredensial akses dan titik akhir

    Kode contoh membaca kredensial akses dan titik akhir dari variabel lingkungan.

  4. Instal SDK SMQ

    Instal SDK SMQ Java dengan menambahkan dependensi Maven. Untuk metode lainnya, lihat Instal SDK SMQ.

    Tambahkan dependensi Maven berikut:

    <dependencies>
        <!-- Alibaba Cloud Simple Message Queue SDK -->
        <dependency>
          <groupId>com.aliyun.mns</groupId>
          <artifactId>aliyun-sdk-mns</artifactId>
          <version>1.2.0</version>
        </dependency>
    </dependencies>

Prosedur

  1. Buat Antrian Pesan Sederhana

    Buat antrian untuk menerima notifikasi gangguan spot instans.

    1. Login ke Konsol Simple Message Queue (formerly MNS). Di panel navigasi kiri, pilih Queue Model > Queues.

    2. Di bilah menu atas, pilih wilayah. Di halaman Queues, klik Create Queue.

    3. Di panel Create Queue, konfigurasikan parameter dan klik OK.

      image

  2. Buat kebijakan langganan

    Cloud Monitor mengirim notifikasi gangguan spot instans melalui saluran push yang ditentukan dalam kebijakan langganan.

    1. Login ke Konsol Cloud Monitor. Di panel navigasi kiri, pilih Event Hub > Event Subscriptions.

    2. Di tab Subscription Policies, klik Create Subscription Policy. Klik Next dan konfigurasikan parameter.

      Hanya parameter utama yang dijelaskan di sini. Untuk parameter lainnya, lihat Kelola langganan event (disarankan).

      • Subscription Type: Pilih System Events.

        image

      • Subscription Scope: Konfigurasikan seperti yang ditunjukkan di bawah ini.

        image

      • Push and Integration: Klik + Add Channel > Add Channel, pilih antrian yang dibuat pada Langkah 1, lalu lengkapi bidang lainnya. Lihat Kelola Saluran Push.

  3. Simulasikan event gangguan

    Gunakan Test Event Subscription untuk mensimulasikan event gangguan, karena gangguan spot instans dipicu secara pasif dan sulit direproduksi selama pengembangan.

    1. Di tab Subscription Policies, klik Test Event Subscription.

    2. Di panel Create Event Debugging, atur Service menjadi ECS dan Name menjadi Spot Instance Interruption Notification.

      Sistem akan menghasilkan konten debugging JSON. Ganti bidang yang terkait resource dengan informasi spot instans Anda.

      • Ganti Alibaba Cloud account UID dengan UID akun Anda.

      • Ganti <resource-id> dan <instanceId> dengan ID spot instans Anda.

      • Ganti <region-id> dengan ID wilayah spot instans Anda.

        {
            "product": "ECS",
            "resourceId": "acs:ecs:cn-shanghai:Alibaba Cloud account 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"
        }
    3. Klik OK. Sistem menampilkan The operation is successful., dan Cloud Monitor mengirim notifikasi uji coba ke antrian Anda.

  4. Ambil dan tanggapi pesan

    Ambil notifikasi gangguan dari antrian dan tanggapi dengan logika kustom. Kode contoh berikut menunjukkan penanganan event gangguan menggunakan program konversi gambar ke skala abu-abu:

    1. Gunakan tugas thread untuk mensimulasikan program konversi gambar.

      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;
      
      /**
       * Prosesor gambar yang dapat diinterupsi dan mendukung konversi ke skala abu-abu.
       * Menggunakan variabel atomik dan flag interupsi thread untuk deteksi.
       * Fitur:
       * 1. Pemrosesan per bagian (chunked) dengan penyimpanan progres otomatis
       * 2. Respons langsung terhadap gangguan spot instans
       * 3. Pembuatan file hasil parsial setelah interupsi
       */
      public class InterruptibleImageProcessor implements Runnable {
          /**
           * Kontrol status aman-thread menggunakan Boolean atomik
           */
          private final AtomicBoolean running = new AtomicBoolean(true);
          /**
           * Menyimpan data gambar yang sedang diproses
           */
          private BufferedImage processedImage;
          /**
           * Persentase progres pemrosesan (0–100)
           */
          private int progress;
          /**
           * Titik masuk thread
           * **Logika interupsi**:
           * 1. Simpan progres saat ini setelah menangkap InterruptedException
           * 2. Pulihkan status interupsi thread (pertahankan semantik)
           */
          @Override
          public void run() {
              try {
                  convertToGrayScale(new File("input.jpg"), new File("output.jpg"));
                  // Simulasikan penundaan post-processing
                  Thread.sleep(5000); 
                  System.out.println("Pemrosesan gambar selesai");
              } catch (InterruptedException e) {
                  System.out.println("Pemrosesan diinterupsi. Progres tersimpan pada " + progress + "%");
                  saveProgress(new File("partial_output.jpg"));
                  Thread.currentThread().interrupt(); // Pulihkan status interupsi
              } catch (Exception e) {
                  System.err.println("Kesalahan pemrosesan: " + e.getMessage());
              }
          }
      
          /**
           * Metode pemicu interupsi eksternal
           * **Mekanisme koordinasi**:
           * Bekerja bersama flag interupsi thread untuk deteksi ganda
           */
          public void stop() {
              running.set(false);
          }
      }
      
    2. Metode konversi gambar ke skala abu-abu.

      /**
       * Konversi gambar input ke skala abu-abu dan simpan
       * @param inputFile Objek file gambar sumber
       * @param outputFile Objek file output
       * @throws Exception Termasuk exception I/O dan interupsi
       *
       * **Algoritma**:
       * Konversi skala abu-abu rata-rata tertimbang sesuai persepsi luminansi manusia:
       * Gray = 0.30*R + 0.59*G + 0.11*B
       * Referensi: standar ITU-R BT.601
       */
      public void convertToGrayScale(File inputFile, File outputFile) throws Exception {
          // Baca gambar sumber
          BufferedImage original = ImageIO.read(inputFile);
          int width = original.getWidth();
          int height = original.getHeight();
          // Buat buffer gambar skala abu-abu
          processedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
      
          // Proses per bagian untuk mendukung penyimpanan progres
          for (int y = 0; y < height && running.get(); y++) {
              // Proses piksel per piksel
              for (int x = 0; x < width; x++) {
                  // Pemeriksaan interupsi pertama: flag interupsi thread
                  if (Thread.interrupted()) {
                      throw new InterruptedException("Pemrosesan gambar diinterupsi");
                  }
                  /* Algoritma inti skala abu-abu */
                  int rgb = original.getRGB(x, y);
                  // Ekstrak saluran RGB (format ARGB)
                  // Saluran merah
                  int r = (rgb >> 16) & 0xFF;
                  // Saluran hijau
                  int g = (rgb >> 8) & 0xFF;
                  // Saluran biru
                  int b = rgb & 0xFF;
                  // Hitung nilai skala abu-abu (rata-rata tertimbang)
                  int gray = (int)(0.3 * r + 0.59 * g + 0.11 * b);
                  // Rekonstruksi RGB (nilai skala abu-abu diduplikasi di semua saluran)
                  processedImage.setRGB(x, y, (gray << 16) | (gray << 8) | gray);
                  // Perbarui persentase progres (perhatikan pembagian integer)
                  progress = (y * width + x) * 100 / (width * height);
              }
              // Simpan progres otomatis setiap 50 baris (mekanisme checkpoint)
              if (y % 50 == 0) {
                  saveProgress(outputFile);
              }
          }
          // Simpan hasil akhir
          ImageIO.write(processedImage, "jpg", outputFile);
      }
    3. Simpan progres pemrosesan gambar.

      /**
       * Simpan progres pemrosesan ke file yang ditentukan
       * @param outputFile Objek file output
       *
       * **Catatan**:
       * 1. Gunakan kegagalan diam untuk menghindari mengganggu proses penyimpanan
       * 2. Hasilkan file sementara bernama partial_output.jpg
       */
      private void saveProgress(File outputFile) {
          try {
              // Gunakan nama file sementara untuk menghindari menimpa file akhir
              ImageIO.write(processedImage, "jpg", new File("partial_output.jpg"));
          } catch (Exception e) {
              System.err.println("Penyimpanan otomatis gagal: " + e.getMessage());
          }
      }
    4. Uji penanganan respons.

      Uji prosesor gambar untuk mendeteksi dan menanggapi gangguan spot instans saat berjalan.

      /**
       * Metode utama (untuk pengujian)
       * **Skenario uji**:
       * 1. Mulai thread pemrosesan
       * 2. Ambil pesan notifikasi gangguan
       * 3. Tunggu hingga thread berhenti
       */
      public static void main(String[] args) throws InterruptedException {
          // Inisialisasi klien MNS
          CloudAccount account = new CloudAccount(
                  ServiceSettings.getMNSAccessKeyId(),
                  ServiceSettings.getMNSAccessKeySecret(),
                  ServiceSettings.getMNSAccountEndpoint());
          MNSClient client = account.getMNSClient();
          // Periksa apakah pesan cocok dengan event gangguan spot instans
          boolean isMatch = false;
          // Mulai prosesor gambar
          InterruptibleImageProcessor processor = new InterruptibleImageProcessor();
          Thread processThread = new Thread(processor);
          processThread.start();
          try{
              // Ambil pesan dari antrian
              CloudQueue queue = client.getQueueRef("spot-interruption");
              Message popMsg = queue.popMessage();
              if (popMsg != null){
                  // Isi pesan secara default dienkripsi Base64
                  System.out.println("isi pesan: " + popMsg.getMessageBodyAsRawString());
                  // Dekode Base64
                  byte[] decodedBytes = Base64.getDecoder().decode(popMsg.getMessageBodyAsRawString());
                  String decodedString = new String(decodedBytes);
                  System.out.println("konten pesan: " + decodedString);
                  // Parsing string JSON
                  JSONObject json = new JSONObject(decodedString);
                  // Dapatkan nama event dari bidang "name"
                  String name = json.getString("name");
                  isMatch = "Instance:PreemptibleInstanceInterruption".equals(name);
                  // Tangani event gangguan spot instans
                  if(isMatch){
                      System.out.println("Spot instans akan diinterupsi dan direclaim");
                      // Hentikan prosesor gambar
                      processor.stop();
                      processThread.interrupt();
                      System.out.println("Program dihentikan");
                      processThread.join();
                      // Hapus pesan
                      queue.deleteMessage(popMsg.getReceiptHandle());
                  }
              }
          }catch (Exception e){
              System.out.println("Terjadi exception yang tidak dikenal!");
              e.printStackTrace();
          }
          client.close();
      }

    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;
    
    /**
     * Prosesor gambar yang dapat diinterupsi dan mendukung konversi ke skala abu-abu.
     * Menggunakan variabel atomik dan flag interupsi thread untuk deteksi.
     * Fitur:
     * 1. Pemrosesan per bagian (chunked) dengan penyimpanan progres otomatis
     * 2. Respons langsung terhadap gangguan spot instans
     * 3. Pembuatan file hasil parsial setelah interupsi
     */
    public class InterruptibleImageProcessor implements Runnable {
        /**
         * Kontrol status aman-thread menggunakan Boolean atomik
         */
        private final AtomicBoolean running = new AtomicBoolean(true);
        /**
         * Menyimpan data gambar yang sedang diproses
         */
        private BufferedImage processedImage;
        /**
         * Persentase progres pemrosesan (0–100)
         */
        private int progress;
    
        /**
         * Konversi gambar input ke skala abu-abu dan simpan
         * @param inputFile Objek file gambar sumber
         * @param outputFile Objek file output
         * @throws Exception Termasuk exception I/O dan interupsi
         *
         * **Algoritma**:
         * Konversi skala abu-abu rata-rata tertimbang sesuai persepsi luminansi manusia:
         * Gray = 0.30*R + 0.59*G + 0.11*B
         * Referensi: standar ITU-R BT.601
         */
        public void convertToGrayScale(File inputFile, File outputFile) throws Exception {
            // Baca gambar sumber
            BufferedImage original = ImageIO.read(inputFile);
            int width = original.getWidth();
            int height = original.getHeight();
            // Buat buffer gambar skala abu-abu
            processedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
    
            // Proses per bagian untuk mendukung penyimpanan progres
            for (int y = 0; y < height && running.get(); y++) {
                // Proses piksel per piksel
                for (int x = 0; x < width; x++) {
                    // Pemeriksaan interupsi pertama: flag interupsi thread
                    if (Thread.interrupted()) {
                        throw new InterruptedException("Pemrosesan gambar diinterupsi");
                    }
                    /* Algoritma inti skala abu-abu */
                    int rgb = original.getRGB(x, y);
                    // Ekstrak saluran RGB (format ARGB)
                    // Saluran merah
                    int r = (rgb >> 16) & 0xFF;
                    // Saluran hijau
                    int g = (rgb >> 8) & 0xFF;
                    // Saluran biru
                    int b = rgb & 0xFF;
                    // Hitung nilai skala abu-abu (rata-rata tertimbang)
                    int gray = (int)(0.3 * r + 0.59 * g + 0.11 * b);
                    // Rekonstruksi RGB (nilai skala abu-abu diduplikasi di semua saluran)
                    processedImage.setRGB(x, y, (gray << 16) | (gray << 8) | gray);
                    // Perbarui persentase progres (perhatikan pembagian integer)
                    progress = (y * width + x) * 100 / (width * height);
                }
                // Simpan progres otomatis setiap 50 baris (mekanisme checkpoint)
                if (y % 50 == 0) {
                    saveProgress(outputFile);
                }
            }
            // Simpan hasil akhir
            ImageIO.write(processedImage, "jpg", outputFile);
        }
    
        /**
         * Simpan progres pemrosesan ke file yang ditentukan
         * @param outputFile Objek file output
         *
         * **Catatan**:
         * 1. Gunakan kegagalan diam untuk menghindari mengganggu proses penyimpanan
         * 2. Hasilkan file sementara bernama partial_output.jpg
         */
        private void saveProgress(File outputFile) {
            try {
                // Gunakan nama file sementara untuk menghindari menimpa file akhir
                ImageIO.write(processedImage, "jpg", new File("partial_output.jpg"));
            } catch (Exception e) {
                System.err.println("Penyimpanan otomatis gagal: " + e.getMessage());
            }
        }
    
        /**
         * Titik masuk thread
         * **Logika interupsi**:
         * 1. Simpan progres saat ini setelah menangkap InterruptedException
         * 2. Pulihkan status interupsi thread (pertahankan semantik)
         */
        @Override
        public void run() {
            try {
                convertToGrayScale(new File("/Users/shaoberlin/Desktop/idea_workspace/aliyun/src/main/resources/input.jpg"), new File("output.jpg"));
                // Simulasikan penundaan post-processing
                Thread.sleep(5000); 
                System.out.println("Pemrosesan gambar selesai");
            } catch (InterruptedException e) {
                System.out.println("Pemrosesan diinterupsi. Progres tersimpan pada " + progress + "%");
                saveProgress(new File("partial_output.jpg"));
                Thread.currentThread().interrupt(); // Pulihkan status interupsi
            } catch (Exception e) {
                System.err.println("Kesalahan pemrosesan: " + e.getMessage());
            }
        }
    
        /**
         * Metode pemicu interupsi eksternal
         * **Mekanisme koordinasi**:
         * Bekerja bersama flag interupsi thread untuk deteksi ganda
         */
        public void stop() {
            running.set(false);
        }
    
        /**
         * Metode utama (untuk pengujian)
         * **Skenario uji**:
         * 1. Mulai thread pemrosesan
         * 2. Picu interupsi setelah 5000 ms
         * 3. Tunggu hingga thread berhenti
         */
        public static void main(String[] args) throws InterruptedException {
            // Inisialisasi klien MNS
            CloudAccount account = new CloudAccount(
                    ServiceSettings.getMNSAccessKeyId(),
                    ServiceSettings.getMNSAccessKeySecret(),
                    ServiceSettings.getMNSAccountEndpoint());
            MNSClient client = account.getMNSClient();
            // Periksa apakah pesan cocok dengan event gangguan spot instans
            boolean isMatch = false;
            // Mulai prosesor gambar
            InterruptibleImageProcessor processor = new InterruptibleImageProcessor();
            Thread processThread = new Thread(processor);
            processThread.start();
            try{
                // Ambil pesan dari antrian
                CloudQueue queue = client.getQueueRef("spot-interruption");
                Message popMsg = queue.popMessage();
                if (popMsg != null){
                    // Isi pesan secara default dienkripsi Base64
                    System.out.println("isi pesan: " + popMsg.getMessageBodyAsRawString());
                    // Dekode Base64
                    byte[] decodedBytes = Base64.getDecoder().decode(popMsg.getMessageBodyAsRawString());
                    String decodedString = new String(decodedBytes);
                    System.out.println("konten pesan: " + decodedString);
                    // Parsing string JSON
                    JSONObject json = new JSONObject(decodedString);
                    // Dapatkan nama event dari bidang "name"
                    String name = json.getString("name");
                    isMatch = "Instance:PreemptibleInstanceInterruption".equals(name);
                    // Tangani event gangguan spot instans
                    if(isMatch){
                        System.out.println("Spot instans akan diinterupsi dan direclaim");
                        // Hentikan prosesor gambar
                        processor.stop();
                        processThread.interrupt();
                        System.out.println("Program dihentikan");
                        processThread.join();
                        // Hapus pesan
                        queue.deleteMessage(popMsg.getReceiptHandle());
                    }
                }
            }catch (Exception e){
                System.out.println("Terjadi exception yang tidak dikenal!");
                e.printStackTrace();
            }
            client.close();
        }
    }
    
Catatan

Referensi

Jika spot instans Anda menyimpan data atau konfigurasi penting, lihat Pertahankan dan pulihkan data untuk spot instans guna mencegah kehilangan data.