Lập trình hướng sự kiện (event-based programming) là một trong những mô hình được sử dụng nhiều trong các giải pháp phầm mềm hiện nay và thậm chí nó còn là một trong những mô hình mà nhiều bạn lập trình viên sử dụng khi mới bắt tay vào lập trình phần mềm. Lấy ví dụ với lập trình ứng dụng Windows Forms, các bạn được học cách viết những đoạn code xử lý khi có sự kiện một Button
được click hay sự kiện người dùng nhập dữ liệu vào một TextBox
. Hay với lập trình ứng dụng Web, các bạn được học cách xử lý khi có sự kiện một trang webpage được tải xong hay sự kiện khi một Form
được gửi đi thành công.
Ở bài viết ngày hôm nay, mình sẽ chia sẻ với các bạn về một dịch vụ hoàn toàn mới trên Azure, hỗ trợ các bài toán xử lý theo mô hình lập trình hướng sự kiện có tên gọi Azure Event Grid, vừa được Microsoft công bố vào ngày 16/08/2017. Azure Event Grid có gì thú vị? Hãy cùng mình khám phá trong bài viết này!
Tuy nhiên, trước hết hãy cùng mình tìm hiểu ở mức cơ bản khái niệm event-based programming là gì?
event-based programming
event-based programming hiểu đơn giản là một mô hình lập trình áp dụng cơ chế lắng nghe sự kiện và thực hiện xử lý khi có sự kiện xảy ra. Cùng xem biểu đồ sau:
Trên là biểu đồ biểu diễn đơn giản một luồng hoạt động của mô hình event-based programming. Trong luồng này có sự tham gia của những thành phần sau:
- event: là một gói tin thường có kích thước nhỏ, chứa dữ liệu liên quan đến sự kiện. Trong gói tin đó có thể chứa các thông tin như nguồn gốc của sự kiện, thời gian sự kiện xảy ra, mã định danh (id), cũng như các thông tin cụ thể cho từng loại sự kiện riêng biệt như sự kiện thông báo có tập tin bị xóa thì có thông tin về tên tập tin bị xóa, thời gian xóa hay sự kiện một máy ảo được khởi động lại thì có thông tin về tên máy ảo, thời gian khởi động lại, …
- publisher/event source: nguồn gốc của sự kiện, nơi mà sự kiện diễn ra và gửi đi (publish).
- subscriber/event handler: nơi mà sẽ lắng nghe (subscribe) & xử lý sự kiện nhận được.
- topic: thông thường một event source thường có nhiều kiểu sự kiện do vậy chúng cần phải được phân loại theo từng topic, mỗi topic sẽ tương ứng với 1 kiểu sự kiện. Để lắng nghe & xử lý một sự kiện nào đấy, subscriber sẽ dựa vào topic để chọn ra sự kiện mong muốn. Topic cũng bao gồm các thông tin về schema (cấu trúc dữ liệu của sự kiện) để subscriber biết được cách xử lý phù hợp cho từng kiểu sự kiện.
Azure Event Grid
Là một dịch vụ về định tuyến sự kiện (event routing), Azure Event Grid hỗ trợ việc xây dựng giải pháp cho các bài toán ứng dụng kiến trúc event-based một cách dễ dàng. Azure Event Grid giúp kết nối tới các event source mà bạn muốn subscribe để nhận sự kiện và hỗ trợ định tuyến sự kiện tới các event handler để xử lý sự kiện.
Azure Event Grid hỗ trợ tích hợp sẵn event source và event handler là các dịch vụ của Azure như:
- event source: Azure Blob Storage, Azure Event Hub hay Azure Resource Groups
- event handler: Azure Functions, Azure Logic Apps hay Azure Automation
Không chỉ hỗ trợ các dịch vụ Azure được tích hợp sẵn kể trên, Event Grid còn linh hoạt trong việc hỗ trợ bạn tạo ra các sự kiện riêng và publish chúng trực tiếp tới cho Event Grid để thực hiện định tuyến sau đó thông qua Event Grid Topic. Ngoài ra, Event Grid cung cấp khả năng linh hoạt trong việc xử lý sự kiện với việc hỗ trợ định tuyến & publish sự kiện tới các dịch vụ khác của Azure cũng như các dịch vụ thuộc bên thứ 3 thông qua WebHook.
Azure Event Grid có gì hay?
Ngoài khả năng linh hoạt kể trên, bộ lọc (filter) cũng là một tính năng đáng chú ý trong Event Grid, nó cho phép điều hướng những sự kiện mong muốn theo kiểu sự kiện hoặc theo prefix/suffix vào endpoint của các subscriber khác nhau. Ngoài ra, Event Grid cũng hỗ trợ publish cùng một sự kiện tới nhiều endpoint cùng lúc.
Để tăng tính đáng tin cậy của sự kiện được gửi đi, Event Grid sử dụng thuật toán exponential backoff để đảm bảo sự kiện được gửi đi thành công. Event Grid sử dụng mã phản hồi HTTP để xác định xem sự kiện đã được event handler nhận thành công hay chưa. Với các mã 200 hoặc 202, Event Grid sẽ xác định rằng sự kiện đã được event handler nhận thành công, với các mã HTTP khác như 40x (400, 401, ..), 414 hay 50x (500, 503, …), hoặc event handler không có phản hồi lại trong 60 giây sau lần gửi đầu tiên, Event Grid sẽ xác định rằng sự kiện chưa được event handler nhận thành công và sẽ thực hiện gửi lại (retry). Việc retry sẽ được thực hiện theo chu kỳ 10 giây, 30 giây, 1 phút, 5 phút, 10 phút, 30 phút hoặc 1 tiếng một lần. Việc lựa chọn chu kỳ sẽ do Event Grid lựa chọn ngẫu nhiên. Tổng thời gian cho việc retry sẽ được thực hiện tối đa trong 24 tiếng.
Ngoài ra, theo trên trang tài liệu của Azure Event Grid, dịch vụ này có khả năng xử lý được hàng triệu sự kiện trong một giây. Con số cụ thể thì mình chưa tìm thấy ở đâu để chia sẻ trong bài viết này.
Azure Event Grid ứng dụng vào những bài toán nào?
Với tính ứng dụng cao của mô hình event-based programming, Event Grid có thể được ứng dụng vào rất nhiều các bài toán hiện nay. Có thể lấy ví dụ với bài toán yêu cầu tích hợp các hệ thống/ứng dụng với nhau, với bài toán này mô hình event-based programming phát huy lợi thế của mình, bạn có thể sử dụng Event Grid đóng vai trò là một lớp định tuyến sự kiện giữa các hệ thống/ứng dụng nhằm tận dụng khả năng chịu tải cao cũng như sự ổn định mà Event Grid cung cấp.
Ngoài ra, Event Grid cũng có thể được ứng dụng trong các bài toán về tự động hóa việc vận hành hệ thống cụ thể là với các hệ thống chạy trên Azure. Lấy ví dụ bạn có thể sử dụng Event Grid để lắng nghe sự thay đổi của các tài nguyên trên Azure như máy ảo được tạo mới, SQL Database được bật nhằm thực hiện các công việc như kiểm tra xem cấu hình của máy ảo có phù hợp hay không, thực hiện lưu thông tin metadata của máy ảo vào database của công cụ quản lý, …
Một ứng dụng cũng rất nổi bật đó là sử dụng cùng với dịch vụ serverless – Azure Functions. Ngoài các trigger được Azure Functions hỗ trợ sẵn, sử dụng Event Grid cho phép mở rộng khả năng lắng nghe tới các sự kiện bên ngoài của function, từ đó dễ dàng sử dụng Azure Functions để xây dựng các giải pháp serverless event handler.
Chi phí sử dụng Event Grid như thế nào?
Event Grid cũng áp dụng mô hình tính phí dùng bao nhiêu trả bấy nhiêu cụ thể ở đây là số lượng thao tác được thực hiện. Các thao tác ở đây không chỉ là những hoạt động gửi sự kiện mà nó còn bao gồm các thao tác lọc sự kiện, số lần thử gửi sự kiện cũng như số các lời gọi tới API để quản lý Event Grid.
Ở thời điểm viết bài viết này, Event Grid cung cấp miễn phí 100,000 thao tác trong 1 tháng và sau hạn mức miễn phí đấy thì dịch vụ này tính phí $0.3 cho 1 triệu thao tác tiếp theo.
Bắt đầu làm quen với Azure Event Grid
Cách tốt nhất để làm quen với một công nghệ mới không gì khác là thử làm với nó. Mình sẽ cùng các bạn xây dựng một ứng dụng serverless đơn giản sử dụng Azure Functions, đóng vai trò là event handler để xử lý sự kiện được gửi về từ Azure Event Grid. Sự kiện được publish từ Azure Event Grid là sự kiện tùy chỉnh, trong mỗi sự kiện có chứa một gói tin quan trọng và ứng dụng serverless trên Azure Functions sẽ nhận gói tin quan trọng này để xử lý & lưu lại vào database trên Azure Cosmos DB.
Bước 1: Khởi tạo Azure Cosmos DB
Azure Cosmos DB là một dịch vụ về NoSQL database mới của Azure, hỗ trợ nhiều data model khác nhau cũng như có khả năng scale toàn cầu. Bài viết không tập trung vào dịch vụ này (bạn có thể tìm hiểu về Cosmos DB ở một bài viết khác của mình tại đây) nên mình sẽ bỏ qua các bước khởi tạo Cosmos DB và mặc địch coi rằng các bạn đã có sẵn một database trên Azure Cosmos DB & sẵn sàng để sử dụng.
Bước 2: Khởi tạo Azure Event Grid Topic
Như có giới thiệu ở trên, Event Grid Topic hỗ trợ publish các sự kiện riêng của bạn trực tiếp tới cho Event Grid để thực hiện định tuyến sau đó. Để khởi tạo Event Grid Topic, các bạn có thể khởi tạo thông qua Azure Portal hoặc qua Azure CLI. Bài viết này mình sẽ dùng Azure CLI.
Lưu ý: Bạn cần phải sử dụng phiên bản Azure CLI tối thiểu là 2.0.14 để có thể khởi tạo được Event Grid Topic.
Như mọi dịch vụ Azure khác, bạn cần phải có một Resource Group để làm nơi quản lý các dịch vụ trên Azure. Nếu bạn chưa có một Resource Group phù hợp, đoạn mã sau sử dụng mã lệnh az group create
để giúp bạn tạo ra một Resource Group mới:
az group create --name <tên_resource_group> --location <mã_vị_trí>
Sau khi có Resource Group, bạn khởi tạo Event Grid Topic thông qua mã lệnh az eventgrid topic create
như sau:
az eventgrid topic create --name <tên_topic> -l <mã_vị_trí> -g <tên_resource_group>
Bước 3: Khởi tạo Azure Functions
Azure Functions là một dịch vụ rất hay trên Azure dành cho các bài toán ứng dụng mô hình serverless. Do không phải là nhân vật chính của bài viết này (bạn có thể tìm hiểu thêm về Azure Functions ở một bài viết trước của mình tại đây) nên mình sẽ không đi sâu vào các bước khởi tạo của Azure Functions mà mặc định coi rằng các bạn đã có một function app trên Azure Functions & sẵn sàng để sử dụng.
Công việc trong bước này tập trung vào việc tạo 1 function trong function app trên Azure Functions để tạo thành 1 serverless event handler.
Binding trigger từ Azure Event Grid cho function
Để function có thể nhận trigger từ Azure Event Grid để thực hiện xử lý sự kiện được publish từ dịch vụ này, bạn cần binding trigger cho function sử dụng EventGridTrigger
. Nếu bạn đang tạo mới function, bạn có thể dễ dàng tạo được function sử dụng EventGridTrigger
thông qua template có sẵn của Azure Functions.
Sau khi binding EventGridTrigger
thành công, tại giao diện code editor của function, bạn chọn Add Event Grid subscription ở góc phải phía trên giao diện để mở cửa sổ khai báo thông tin đăng ký nhận sự kiện từ Event Grid. Quá trình khai báo này được gọi là event subscription, nó cho phép bạn tùy chọn được việc nhận sự kiện từ topic nào trong Event Grid, cũng như tùy chọn chỉ nhận những sự kiện cụ thể nào từ một topic thông qua bộ lọc. Các thông tin cấu hình về event handler cũng được khai báo trong quá trình này.
Tại cửa sổ khai báo thông tin về event subscription, bạn điền các thông tin cần thiết theo hướng dẫn sau:
- Name: Khai báo tên của event subscription
- Topic Type: Bạn chọn Event Grid Topics
- Resource Group: Lựa chọn Azure Resource Group chứa Event Grid Topic được khai báo ở bước 2
- Instance: Lựa chọn Event Grid Topic mà bạn đã khai báo ở bước 2
- Subscriber Endpoint: Đường dẫn của function được khai báo ở bước 3 (Azure sẽ tự động điền cho bạn)
- Prefix Filter/Suffix Filter: Giá trị bộ lọc sự kiện
Binding output data tới Azure Cosmos DB
Để lưu trữ gói tin nhận được từ sự kiện vào database sử dụng dịch vụ Azure Cosmos DB, function được tạo cần phải binding tới Cosmos DB dưới dạng output data của function.
Tại giao diện quản lý function app của Azure Functions, bạn chọn mục Integrate của function vừa được khởi tạo ở trên rồi sau đó khai báo các thông tin cần thiết của Azure Cosmos DB trong phần cấu hình output binding.
Viết code để thực hiện xử lý sự kiện
Sau khi binding trigger tới Event Grid và output data tới Cosmos DB thành công, bạn quay trở lại giao diện code editor của function. Tại đây, bạn có thể viết những đoạn code để xử lý khi nhận được sự kiện từ Event Grid nhằm thực hiện bóc tách & lưu dữ liệu trong sự kiện vào Cosmos DB.
Dưới đây là đoạn code mẫu viết bằng C# để lấy thông tin từ thuộc tính Data
trong sự kiện được gửi từ Event Grid và lưu nó lại vào database trên Cosmos DB:
#r "Microsoft.Azure.WebJobs.Extensions.EventGrid" #r "Newtonsoft.Json" using Microsoft.Azure.WebJobs.Extensions.EventGrid; using Newtonsoft.Json; public static void Run(EventGridEvent eventGridEvent, out object outputDocument, TraceWriter log) { log.Info("Received an event from Event Grid with following data:"); // Log lại thông tin của sự kiện nhận được log.Info(eventGridEvent.ToString()); // Lấy gói tin từ sự kiện nhận được var data = eventGridEvent.Data; // Lưu gói tin vào database trong Cosmos DB outputDocument = data; log.Info("Save data to database succeeded!"); }
Gửi sự kiện thông qua Event Grid Topic
Ở bước này chúng ta đã:
- Tạo thành công một serverless event handler dưới dạng function sử dụng Azure Functions.
- Tạo thành công Event Grid Topic để định tuyến sự kiện bên ngoài với Event Grid.
- Tạo thành công một event subscription đăng ký lắng nghe sự kiện gửi qua Event Grid Topic và điều hướng sự kiện nhận được tới subscriber là function được tạo.
Mỗi Event Grid Topic bạn tạo Azure sẽ cung cấp cho bạn một endpoint để tương tác với topic đấy. Bạn có thể tìm thấy thông tin về endpoint này tại phần Overview của trang quản lý Event Grid Topic.
Để publish được sự kiện tới endpoint của Event Grid Topic, bạn chỉ cần thực hiện HTTP POST tới endpoint đó kèm theo HTTP header aeg-sas-key
với giá trị là authentication key hoặc SAS token để thực hiện xác thực. authentication key là phương thức xác thực sẽ được sử dụng trong bài viết này vì tính đơn giản của nó.
Dưới đây là 1 ví dụ sử dụng authentication key:
aeg-sas-key: AGbGWce53249Mt8wuotr0GPmyJ/nDT4hgdEj9DpBeRr38arnnm5OFg==
Bạn có thể tìm thấy giá trị của authentication key của Event Grid Topic cũng tại phần Overview của trang quản lý Event Grid Topic đấy.

Body của HTTP POST sẽ chứa dữ liệu của sự kiện và được thể hiện dưới dạng một array
của các event object
viết bằng JSON. Một gói tin gửi đi có thể chứa nhiều event object, trong trường hợp chỉ có 1 event object, bạn vẫn phải khai báo gói tin dưới dạng array và thể hiện dưới dạng array chỉ có 1 phần tử.
Các event object phải tuân thủ cấu trúc được quy định theo schema mà Azure đưa ra. Về cơ bản, 1 event object bắt buộc chứa 6 thuộc tính sau:
Thuộc tính | Kiểu | Ý nghĩa |
---|---|---|
topic | string | Chứa thông tin của event source dưới dạng đường dẫn đầy đủ. Thuộc tính này sẽ do Event Grid khai báo. |
subject | string | Thông tin liên quan đến sự kiện, được sử dụng để thực hiện lọc sự kiện. |
eventType | string | Kiểu sự kiện. Phụ thuộc vào event source, giá trị này có thể được lấy từ 1 danh sách được định nghĩa sẵn hoặc do bạn tự định nghĩa. |
eventTime | string | Thời gian sự kiện xảy ra ở múi giờ UTC. |
id | string | Mã định danh riêng của sự kiện. |
data | object | Chứa thông tin về dữ liệu được đính kèm theo sự kiện. |
Dưới đây là gói tin mẫu của một sự kiện tùy chỉnh gửi qua Event Grid Topic:
[ { "topic": "/subscriptions/{subscription-id}/resourceGroups/LionPham/providers/Microsoft.EventGrid/topics/LionEventGrid", "subject": "/lionpham/blog/posts", "id": "5CB32CEF-30CE-4EB1-AF83-B5C3224ED345", "eventType": "newPostPublished", "eventTime": "2017-08-09T18:41:00.9584103Z", "data":{ "name": "Tìm hiểu về Azure Cosmos DB", "url": "https://blog.lionpham.com/2017/08/09/microsoft-azure-cosmos-db/" } } ]
Mình sẽ sử dụng Azure CLI để thực hiện HTTP POST với gói tin mẫu trên như sau:
Trước tiên, sử dụng câu lệnh az eventgrid topic show
để lấy thông tin về endpoint và az eventgrid topic key list
để lấy thông tin về key của Event Grid Topic và gán vào 2 biến endpoint
và key
tương ứng:
endpoint=$(az eventgrid topic show --name <tên_topic> -g <tên_resource_group> --query "endpoint" --output tsv) key=$(az eventgrid topic key list --name <tên_topic> -g <tên_resource_group> --query "key1" --output tsv)
Sau đó, truyền dữ liệu của gói tin của sự kiện cần gửi vào biến body
. Ở đây, gói tin của sự kiện được mình lưu lại dưới dạng 1 tập tin .txt
và mình sử dụng câu lệnh curl
của Bash để thực hiện tải về nội dung của gói tin trong tập tin đó:
body=$(eval echo "'$(curl https://cdn.blob.lionpham.com/uploads/2017/08/customevent.txt)'")
Tiếp theo, thực hiện HTTP POST với các biến dữ liệu vừa được khai báo ở trên thông qua câu lệnh curl
:
curl -X POST -H "aeg-sas-key: $key" -d "$body" $endpoint
Ngay lập tức function của bạn sẽ được trigger và thực hiện đoạn code lưu dữ liệu vào database trên Cosmos DB.

Như vậy chúng ta đã xây dựng thành công được một serverless event handler dưới dạng function đơn giản sử dụng Azure Functions để subscribe & xử lý khi có sự kiện được publish từ Azure Event Grid thông qua Event Grid Topic. Dữ liệu đi kèm theo sự kiện được event handler xử lý để lưu trữ vào database trên Azure Cosmos DB với khả năng scale ở phạm vị toàn cầu.
Kết luận
Với đặc điểm giảm sự phụ thuộc giữa các module trong hệ thống (decoupling), mô hình event-based programming được ưa chuộng trong các bài toán cần tích hợp các hệ thống độc lập với nhau ví dụ như những bài toán sử dụng mô hình microservice. Khi áp dụng mô hình event-based programming, việc xây dựng một hệ thống định tuyến sự kiện giữa các thành phần với khả năng chịu tải lớn để đảm bảo các sự kiện được điều hướng kịp thời, không bị nghẽn, cũng như khả năng bảo mật cao, đảm bảo không xảy ra tình trạng subscribe & publish sự kiện trái phép là điều cần được quan tâm hơn cả. Azure Event Grid cung cấp giải pháp định tuyến sự kiện trên nền tảng điện toán đám mây Azure, được Microsoft phát triển nhằm biến sự kiện trở thành một first-class object trên Azure, cung cấp khả năng chịu tải cao (throughput lớn), cơ chế xác thực cho cả quá trình publish & subscribe sự kiện cũng như các tính năng nâng cao khác như cơ chế retry gửi sự kiện khi subscriber chưa nhận thành công, bộ lọc linh hoạt trong việc điều hướng sự kiện.
Với nhiều câu hỏi đặt ra cho mình về việc làm thế nào để biết được khi máy ảo trên Azure bị tắt hoặc khởi động lại hay làm thế nào để biết khi có một dịch vụ được tạo mới trên Azure, … giờ đây những câu hỏi như vậy mình đều có thể đưa ra cùng 1 câu trả lời rằng: “Bạn cần sử dụng Azure Event Grid!”.
Ở thời điểm viết bài viết này, Azure Event Grid đang ở phiên bản Preview. Dự kiến trong năm nay, Microsoft sẽ bổ sung thêm các dịch vụ Azure Active Directory, API Management, IoT Hub, Service Bus, Azure Data Lake Store, Azure Cosmos DB, Azure Data Factory và Storage Queues vào trong danh sách các event source, event handler được tích hợp sẵn. Các bạn có thể tìm hiểu thêm thông tin về Azure Event Grid tại đây.
Mình không tìm thấy cách để tạo topic từ Azure Storage. Mong bạn chỉ giáo!
Bạn tham khảo đường dẫn sau nha: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-event-overview
Video hay về dịch vụ này: https://www.youtube.com/watch?v=p8ia7J4Y7tI
Thanks bạn!