Deteksi gangguan spot instance melalui ECS SDK, instance metadata, atau Cloud Monitor, lalu tanggapi dengan graceful shutdown atau persistensi data.
Deteksi gangguan
Kueri menggunakan ECS SDK
Panggil operasi DescribeInstances untuk mengkueri detail instans. Periksa bidang OperationLocks dalam respons untuk menentukan apakah instans telah memasuki status pending release.
-
Jika respons kosong, instans masih tersedia.
-
Jika
LockReasonbernilaiRecycling, spot instance terganggu dan menunggu rilis.
Contoh penggunaan SDK
Prasyarat
-
Buat AccessKey
Akun Alibaba Cloud memiliki izin penuh atas semua resource. Jika AccessKey dikompromikan, resource Anda berisiko tinggi. Gunakan AccessKey Pengguna RAM dengan izin minimal yang diperlukan. Lihat Buat AccessKey.
-
Berikan izin ECS kepada Pengguna RAM
Berikan izin kepada Pengguna RAM untuk mengelola resource ECS. Kode contoh ini memerlukan izin untuk mengkueri informasi instans. Berikan kebijakan sistem berikut:
Produk Cloud
Izin yang diberikan
Elastic Compute Service (ECS)
Kebijakan sistem: AliyunECSFullAccess
-
Konfigurasikan kredensial akses
Kode contoh membaca AccessKey dari variabel lingkungan sistem untuk mengotentikasi permintaan. Lihat Konfigurasikan variabel lingkungan pada Linux, macOS, dan Windows.
-
Instal ECS SDK
Dapatkan ECS SDK. Contoh ini menggunakan Maven. Untuk metode instalasi lainnya, lihat Instal ECS Java SDK.
Inisialisasi client
SDK Alibaba Cloud mendukung beberapa jenis kredensial untuk inisialisasi client, seperti AccessKey dan token STS. Untuk opsi lainnya, lihat Kelola kredensial akses. Contoh ini menginisialisasi client dengan AccessKey.
import com.aliyun.ecs20140526.Client;
import com.aliyun.teaopenapi.models.Config;
public class Sample {
private static Client createClient() throws Exception {
Config config = new Config()
// Wajib diisi. Pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID telah disetel.
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// Wajib diisi. Pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah disetel.
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
// Referensi endpoint: https://api.aliyun.com/product/Ecs
.setEndpoint("ecs.cn-hangzhou.aliyuncs.com");
return new Client(config);
}
}
Buat objek permintaan
Sebelum membuat permintaan, lihat dokumentasi API untuk detail parameter.
// Buat objek permintaan
DescribeInstancesRequest request = new DescribeInstancesRequest().setRegionId("cn-hangzhou");
Lakukan pemanggilan
Saat memanggil operasi OpenAPI, Anda dapat mengonfigurasi parameter waktu proses seperti timeout dan pengaturan proxy. Lihat Konfigurasi lanjutan.
// Setel opsi waktu proses
RuntimeOptions runtime = new RuntimeOptions();
// Panggil operasi DescribeInstances
DescribeInstancesResponse response = client.describeInstancesWithOptions(request, runtime);
System.out.println(response.body.toMap());
Tangani exception
SDK Java mengkategorikan exception menjadi TeaUnretryableException dan TeaException:
-
TeaUnretryableException: Biasanya disebabkan oleh masalah jaringan setelah jumlah maksimum retry tercapai.
-
TeaException: Terutama disebabkan oleh error terkait bisnis.
Terapkan penanganan exception yang tepat, seperti menyebarkan exception, mencatat error, atau mencoba pemulihan, untuk memastikan ketangguhan sistem.
Contoh lengkap
import com.aliyun.ecs20140526.Client;
import com.aliyun.ecs20140526.models.DescribeInstancesRequest;
import com.aliyun.ecs20140526.models.DescribeInstancesResponse;
import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody;
import com.aliyun.tea.TeaException;
import com.aliyun.tea.TeaUnretryableException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.alibaba.fastjson.JSONArray;
import java.util.Arrays;
public class Sample {
private static Client createClient() throws Exception {
Config config = new Config()
// Wajib diisi. Pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID telah disetel.
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// Wajib diisi. Pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah disetel.
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
// Referensi endpoint: https://api.aliyun.com/product/Ecs
.setEndpoint("ecs.cn-hangzhou.aliyuncs.com");
return new Client(config);
}
public static void main(String[] args) {
try {
Client client = Sample.createClient();
// Buat objek permintaan
// Tentukan satu atau beberapa ID Instance ECS untuk dikueri.
JSONArray instanceIds = new JSONArray();
instanceIds.addAll(Arrays.asList("i-bp145cvd0exyqj****","i-bp1gehfgfrrk4lah****"));
DescribeInstancesRequest request = new DescribeInstancesRequest()
.setRegionId("cn-hangzhou")
.setInstanceIds(instanceIds.toJSONString());
// Setel opsi waktu proses
RuntimeOptions runtime = new RuntimeOptions();
while (!instanceIds.isEmpty()) {
// Panggil operasi DescribeInstances
DescribeInstancesResponse response = client.describeInstancesWithOptions(request, runtime);
// Dapatkan detail instans dari respons.
DescribeInstancesResponseBody responseBody = response.getBody();
DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances instanceList = responseBody.getInstances();
// Periksa detail instans dan evaluasi nilai lockReason.
if (instanceList != null && instanceList.getInstance()!= null && !instanceList.getInstance().isEmpty()) {
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : instanceList.getInstance()) {
// Cetak ID instans dan ID zona yang dikueri.
System.out.println("result:instance:" + instance.getInstanceId() + ",az:" + instance.getZoneId());
if (instance.getOperationLocks() != null ) {
DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstanceOperationLocks operationLocks = instance.getOperationLocks();
if(operationLocks.getLockReason()!=null && !operationLocks.getLockReason().isEmpty()){
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstanceOperationLocksLockReason lockReason : operationLocks.getLockReason()) {
// Jika instans terkunci, cetak ID-nya dan alasan penguncian.
System.out.println("instance:" + instance.getInstanceId() + "-->lockReason:" + lockReason.getLockReason() + ",vmStatus:" + instance.getStatus());
if ("Recycling".equals(lockReason.getLockReason())) {
// Cetak ID instans yang dijadwalkan untuk segera dirilis.
System.out.println("spot instance will be recycled immediately, instance id:" + instance.getInstanceId());
instanceIds.remove(instance.getInstanceId());
}
}
}
}
}
// Jika belum ada spot instance yang terkunci, kueri lagi setiap dua menit.
System.out.print("try describeInstances again later ...");
Thread.sleep(2 * 60 * 1000);
} else {
break;
}
}
} catch (TeaUnretryableException ue) {
// Hanya untuk demonstrasi. Jangan pernah mengabaikan exception dalam kode produksi.
ue.printStackTrace();
// Cetak pesan error
System.out.println(ue.getMessage());
// Cetak detail permintaan untuk debugging
System.out.println(ue.getLastRequest());
} catch (TeaException e) {
// Hanya untuk demonstrasi. Jangan pernah mengabaikan exception dalam kode produksi.
e.printStackTrace();
// Cetak kode error
System.out.println(e.getCode());
// Cetak pesan error (termasuk RequestId)
System.out.println(e.getMessage());
// Cetak konten error detail sisi server
System.out.println(e.getData());
} catch (Exception e) {
// Hanya untuk demonstrasi. Jangan pernah mengabaikan exception dalam kode produksi.
e.printStackTrace();
}
}
}
Hasil yang dikembalikan
Saat rilis dipicu, output-nya adalah:
result:instance:i-bp1i9c3qiv1qs6nc****,az:cn-hangzhou-i
instance:i-bp1i9c3qiv1qs6nc****-->lockReason:Recycling,vmStatus:Stopped
spot instance will be recycled immediately, instance id:i-bp1i9c3qiv1qs6nc****
Kueri dari dalam instans melalui metadata
Akses layanan instance metadata dari dalam Instance ECS untuk memeriksa kapan spot instance akan dihentikan. Lihat Instance metadata.
Jalur metadata untuk waktu terminasi spot instance: instance/spot/termination-time
Hasil:
-
Jika responsnya 404, instans masih tersedia.
-
Jika respons mengembalikan timestamp UTC seperti
2015-01-05T18:02:00Z, instans akan ditarik kembali pada waktu tersebut.
Contoh:
Instans Linux
# Dapatkan token layanan metadata untuk autentikasi
TOKEN=`curl -X PUT "http://100.100.100.200/latest/api/token" -H "X-aliyun-ecs-metadata-token-ttl-seconds:<metadata service token TTL>"`
# Periksa apakah spot instance dijadwalkan untuk gangguan
curl -H "X-aliyun-ecs-metadata-token: $TOKEN" http://100.100.100.200/latest/meta-data/instance/spot/termination-time
Instans Windows
# Dapatkan token layanan metadata untuk autentikasi
$token = Invoke-RestMethod -Headers @{"X-aliyun-ecs-metadata-token-ttl-seconds" = "<metadata service token TTL>"} -Method PUT -Uri http://100.100.100.200/latest/api/token
# Periksa apakah spot instance dijadwalkan untuk gangguan
Invoke-RestMethod -Headers @{"X-aliyun-ecs-metadata-token" = $token} -Method GET -Uri http://100.100.100.200/latest/meta-data/instance/spot/termination-time
Kueri dengan Cloud Monitor SDK
Event ECS disinkronkan ke Cloud Monitor. Panggil operasi DescribeSystemEventAttribute untuk mengkueri event gangguan spot instance (Instance:PreemptibleInstanceInterruption). Jika bidang content berisi delete, spot instance dijadwalkan untuk ditarik kembali.
Contoh penggunaan SDK
Prasyarat
-
Buat AccessKey
Akun Alibaba Cloud memiliki izin penuh atas semua resource. Jika AccessKey dikompromikan, resource Anda berisiko tinggi. Gunakan AccessKey Pengguna RAM dengan izin minimal yang diperlukan. Lihat Buat AccessKey.
-
Berikan izin Cloud Monitor kepada Pengguna RAM
Berikan izin kepada Pengguna RAM untuk mengelola Cloud Monitor (CMS). Kode contoh ini memerlukan izin untuk mengkueri event sistem. Berikan kebijakan berikut:
Produk cloud
Izin yang diberikan
Cloud Monitor (CMS)
AliyunCloudMonitorFullAccess
-
Konfigurasikan kredensial akses
Kode contoh membaca AccessKey dari variabel lingkungan sistem untuk mengotentikasi permintaan. Lihat Konfigurasikan variabel lingkungan pada Linux, macOS, dan Windows.
-
Instal CMS SDK
Dapatkan CMS SDK. Contoh ini menggunakan Maven. Untuk metode instalasi lainnya, lihat Instal CMS Java SDK.
Inisialisasi client
SDK Alibaba Cloud mendukung beberapa jenis kredensial untuk inisialisasi client, seperti AccessKey dan token STS. Untuk opsi lainnya, lihat Kelola kredensial akses. Contoh ini menginisialisasi client dengan AccessKey.
import com.aliyun.cms20190101.Client;
import com.aliyun.teaopenapi.models.Config;
public class Sample {
private static Client createClient() throws Exception {
Config config = new Config()
// Wajib diisi. Pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID telah disetel.
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// Wajib diisi. Pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah disetel.
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
// Referensi endpoint: https://api.aliyun.com/product/Ecs
.setEndpoint("metrics.cn-hangzhou.aliyuncs.com");
return new Client(config);
}
}
Buat objek permintaan
Konfigurasikan parameter kueri untuk event gangguan spot instance. Untuk parameter lainnya, lihat DescribeSystemEventAttribute.
|
API |
Parameter |
Nilai contoh |
|
Product |
Singkatan layanan: ECS |
|
|
EventType |
Jenis event: StatusNotification |
|
|
Name |
Nama event: Instance:PreemptibleInstanceInterruption |
// Buat objek permintaan
DescribeSystemEventAttributeRequest request = new DescribeSystemEventAttributeRequest()
.setProduct("ECS")
.setEventType("StatusNotification")
.setName("Instance:PreemptibleInstanceInterruption");
Lakukan pemanggilan
Saat memanggil operasi OpenAPI, Anda dapat mengonfigurasi parameter waktu proses seperti timeout dan pengaturan proxy. Lihat Konfigurasi lanjutan.
// Setel opsi waktu proses
RuntimeOptions runtime = new RuntimeOptions();
// Panggil operasi DescribeSystemEventAttribute
DescribeSystemEventAttributeResponse response = client.describeSystemEventAttributeWithOptions(request, runtime);
System.out.println(response.body.toMap());
Tangani exception
SDK Java mengkategorikan exception menjadi TeaUnretryableException dan TeaException:
-
TeaUnretryableException: Biasanya disebabkan oleh masalah jaringan setelah jumlah maksimum retry tercapai.
-
TeaException: Terutama disebabkan oleh error terkait bisnis.
Terapkan penanganan exception yang tepat, seperti menyebarkan exception, mencatat error, atau mencoba pemulihan, untuk memastikan ketangguhan sistem.
Contoh lengkap
import com.aliyun.cms20190101.Client;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.cms20190101.models.DescribeSystemEventAttributeRequest;
import com.aliyun.cms20190101.models.DescribeSystemEventAttributeResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.tea.TeaUnretryableException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
public class Sample {
private static Client createClient() throws Exception {
Config config = new Config()
// Wajib diisi. Pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID telah disetel.
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// Wajib diisi. Pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah disetel.
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
// Referensi endpoint: https://api.aliyun.com/product/Ecs
.setEndpoint("metrics.cn-hangzhou.aliyuncs.com");
return new Client(config);
}
public static void main(String[] args) {
try {
Client client = Sample.createClient();
// Buat objek permintaan
DescribeSystemEventAttributeRequest request = new DescribeSystemEventAttributeRequest()
.setProduct("ECS")
.setEventType("StatusNotification")
.setName("Instance:PreemptibleInstanceInterruption");
// Setel opsi waktu proses
RuntimeOptions runtime = new RuntimeOptions();
// Panggil operasi DescribeSystemEventAttribute
DescribeSystemEventAttributeResponse response = client.describeSystemEventAttributeWithOptions(request, runtime);
System.out.println(response.body.toMap());
} catch (TeaUnretryableException ue) {
// Hanya untuk demonstrasi. Jangan pernah mengabaikan exception dalam kode produksi.
ue.printStackTrace();
// Cetak pesan error
System.out.println(ue.getMessage());
// Cetak detail permintaan untuk debugging
System.out.println(ue.getLastRequest());
} catch (TeaException e) {
// Hanya untuk demonstrasi. Jangan pernah mengabaikan exception dalam kode produksi.
e.printStackTrace();
// Cetak kode error
System.out.println(e.getCode());
// Cetak pesan error (termasuk RequestId)
System.out.println(e.getMessage());
// Cetak konten error detail sisi server
System.out.println(e.getData());
} catch (Exception e) {
// Hanya untuk demonstrasi. Jangan pernah mengabaikan exception dalam kode produksi.
e.printStackTrace();
}
}
}
Hasil
Interpretasikan respons untuk mengidentifikasi event gangguan spot instance.
Notifikasi event dalam format JSON:
{
"ver": "1.0",
"id": "2256A988-0B26-4E2B-820A-8A********E5",
"product": "ECS",
"resourceId": "acs:ecs:cn-hangzhou:169070********30:instance/i-bp1ecr********5go2go",
"level": "INFO",
"name": "Instance:PreemptibleInstanceInterruption",
"userId": "169070********30",
"eventTime": "20190409T121826.922+0800",
"regionId": "cn-hangzhou",
"content": {
"instanceId": "i-bp1ecr********5go2go",
"action": "delete"
}
}
Bidang content dijelaskan di bawah ini. Untuk detail parameter, lihat DescribeSystemEventAttribute.
|
Bidang |
Deskripsi |
Nilai contoh |
|
instanceId |
ID spot instance. |
i-bp1ecr********5go2go |
|
action |
Event operasi. Nilai delete menunjukkan bahwa instans terganggu dan akan ditarik kembali secara paksa. |
delete |
Berlangganan event Cloud Monitor
Berlangganan event Cloud Monitor untuk memantau gangguan spot instance secara real time. Notifikasi dapat dikirim melalui saluran seperti pesan teks, email, Function Compute, Simple Message Queue, atau webhook.
Alur kerja
Prosedur
-
Siapkan saluran penerima
Lightweight Message Queue
Di panel navigasi kiri, pilih .
Di bilah navigasi atas, pilih wilayah.
Di halaman Queues, klik Create Queue.
Di panel Create Queue, konfigurasikan parameter berikut lalu klik OK:
Name: nama antrian.
Maximum Message Length: panjang maksimum pesan yang dikirim ke antrian.
Long Polling Period: durasi maksimum permintaan long polling ditahan setelah operasi ReceiveMessage dipanggil.
Visibility Timeout Period: durasi pesan berada dalam status Inactive setelah pesan diterima dari antrian.
Message Retention Period: durasi maksimum pesan ada dalam antrian. Setelah periode retensi yang ditentukan, pesan dihapus terlepas dari apakah pesan telah diterima atau belum.
Message Delay Period: periode setelah semua pesan yang dikirim ke antrian dikonsumsi.
Enable Logging Feature: menentukan apakah fitur logging diaktifkan.
Setelah antrian dibuat, antrian tersebut ditampilkan di halaman Queues.
Webhook
PentingDeploy layanan webhook pada server yang dapat diakses Internet. Pastikan lalu lintas masuk diizinkan pada port respons.
Kode contoh Java:
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class WebhookController { @PostMapping("/callback") public ResponseEntity<String> receiveWebhook(@RequestBody String payload) { // Proses muatan, seperti mencatat log atau menjalankan logika bisnis System.out.println("Received webhook payload: " + payload); // Kembalikan respons sukses return ResponseEntity.ok("Webhook received"); } } -
Buat kebijakan langganan
-
Masuk ke Konsol Cloud Monitor.
-
Di panel navigasi kiri, pilih .
-
Di tab Subscription Policies, klik Create Subscription Policy.
-
Di halaman Create Subscription Policy, konfigurasikan parameter kebijakan.
Contoh ini hanya mencakup parameter yang relevan dengan event gangguan spot instance. Untuk semua parameter, lihat Kelola langganan event (disarankan).
-
Basic Information: Masukkan Name dan Description untuk kebijakan langganan.
-
Alert Subscription:
-
Subscription Type: Pilih System Events.
-
Subscription Scope:
-
Service: Pilih ECS.
-
Event Type: Pilih Status Notification.
-
Event Name: Pilih Spot Instance Interruption Notification.
-
Event Severity: Pilih Warning.
-
Application Groups, Event Content, dan Event Resource: Biarkan parameter ini kosong untuk berlangganan semua event sistem ECS dengan nama Spot Instance Interruption Notification di seluruh kelompok aplikasi dalam akun Anda.
-
-
Noise Reduction: Gunakan default.
-
Notification: The Custom Notification Method menggunakan metode default.
-
Push and Integration: Klik Add Channel. Di jendela pop-up, klik Add Channel, pilih saluran yang disiapkan di Langkah 1 sebagai Target Type, lalu lengkapi bidang lainnya. Untuk detail saluran push, lihat Kelola saluran push.
-
-
-
Simulasikan event gangguan
Gangguan spot instance bersifat pasif, sehingga sulit untuk melakukan debug kode penanganan gangguan. Gunakan fitur Debug Event Subscription untuk mensimulasikan event gangguan spot instance.
-
Di tab Subscription Policies, klik Debug Event Subscription.
-
Di panel Create Event Debug, atur Service ke ECS dan Name ke Spot Instance Interruption Notification.
Sistem menghasilkan muatan debug dalam format JSON. Ganti placeholder terkait resource dengan nilai aktual untuk spot instance yang akan disimulasikan.
-
Ganti
UID Akun Alibaba Clouddengan UID Akun Alibaba Cloud Anda. -
Ganti
<resource-id>dan<instanceId>dengan ID spot instance. -
Ganti
<region ID>dengan ID wilayah spot instance.{ "product": "ECS", "resourceId": "acs:ecs:cn-shanghai:UID Akun Alibaba Cloud:instance/<resource-id>", "level": "WARN", "instanceName": "instanceName", "regionId": "<region ID>", "groupId": "0", "name": "Instance:PreemptibleInstanceInterruption", "content": { "instanceId": "i-2zeg014dfo4y892z***", "instanceName": "wor***b73", "action": "delete" }, "status": "Normal" }
-
-
Klik OK.
Sistem menampilkan pesan The operation is successful. dan mengirim notifikasi peringatan uji berdasarkan kebijakan langganan Anda.
-
-
Terima dan lihat notifikasi
Lightweight Message Queue
-
Masuk ke Konsol Simple Message Queue (sebelumnya MNS). Di panel navigasi kiri, klik Queues.
-
Di bilah navigasi atas, pilih wilayah. Di halaman Queues, temukan antrian target Anda lalu klik Action > Send Messages.
-
Opsional: Pada halaman Send/Receive Messages Quick Experience, klik Edit Parameters of Receiving Messages. Di panel Edit Parameters of Receiving Messages, atur Receive Times dan Polling Period, lalu klik OK.
-
Di halaman Queue Send/Receive Messages Quick Experience, klik Receive Message. Daftar pesan muncul di bagian Received Messages.
-
Opsi: Di daftar pesan, temukan pesan target Anda, klik Details di kolom Actions, lalu lihat konten pesan di kotak dialog Message Details.
Webhook
Anda dapat memeriksa log pemanggilan dan konten notifikasi di aplikasi webhook yang telah di-deploy.
-
Tanggapi gangguan
Strategi respons Anda bergantung pada skenario bisnis Anda. Uji aplikasi Anda untuk memastikan dapat menangani gangguan spot instance secara mulus. Pertimbangkan pendekatan berikut:
-
Penanganan gangguan yang mulus
Tanggapi segera sinyal gangguan dengan menyimpan progres tugas, membersihkan resource, dan menghentikan eksekusi tugas.
-
Persistensi data dan checkpoint
Simpan secara berkala progres tugas dan hasil antara ke penyimpanan persisten, seperti file lokal atau database, untuk mempertahankan data bisnis kritis. Lihat Retensi dan pemulihan data untuk spot instance.
-
Uji keberhasilan integrasi
Picu event uji di Cloud Monitor untuk memverifikasi bahwa program Anda merespons sesuai harapan. Lihat Deteksi dan tanggapi event gangguan spot instance menggunakan Simple Message Queue.