Chạy quy trình xử lý văn bản dữ liệu lớn trong Cloud Dataflow

1. Tổng quan

Cloud-Dataflow.png

Dataflow là gì?

Dataflow là một dịch vụ được quản lý để thực thi nhiều mẫu xử lý dữ liệu. Tài liệu trên trang web này hướng dẫn bạn cách triển khai các quy trình xử lý dữ liệu hàng loạt và truyền trực tuyến bằng Dataflow, bao gồm cả hướng dẫn sử dụng các tính năng của dịch vụ.

Apache Beam SDK là một mô hình lập trình nguồn mở cho phép bạn phát triển cả quy trình xử lý hàng loạt và quy trình truyền trực tuyến. Bạn tạo các quy trình bằng chương trình Apache Beam rồi chạy chúng trên dịch vụ Dataflow. Tài liệu về Apache Beam cung cấp thông tin khái niệm chuyên sâu và tài liệu tham khảo cho mô hình lập trình, SDK và các trình chạy khác của Apache Beam.

Phân tích dữ liệu truyền trực tuyến với tốc độ cao

Dataflow cho phép phát triển quy trình truyền dữ liệu trực tuyến nhanh chóng, đơn giản với độ trễ dữ liệu thấp hơn.

Đơn giản hoá hoạt động và quản lý

Cho phép các nhóm tập trung vào việc lập trình thay vì quản lý các cụm máy chủ vì phương pháp không máy chủ của Dataflow giúp loại bỏ chi phí vận hành cho các khối lượng công việc kỹ thuật dữ liệu.

Giảm tổng chi phí sở hữu

Tính năng tự động cấp tài nguyên bổ sung kết hợp với khả năng xử lý hàng loạt được tối ưu hoá chi phí có nghĩa là Dataflow cung cấp dung lượng gần như không giới hạn để quản lý các khối lượng công việc theo mùa và đột biến mà không tốn quá nhiều chi phí.

Các tính năng chính

Quản lý tài nguyên tự động và cân bằng lại công việc một cách linh động

Dataflow tự động cung cấp và quản lý các tài nguyên xử lý để giảm thiểu độ trễ và tối đa hoá mức sử dụng, nhờ đó bạn không cần khởi động các phiên bản hoặc đặt trước các phiên bản theo cách thủ công. Việc phân vùng công việc cũng được tự động hoá và tối ưu hoá để cân bằng lại động các công việc bị trễ. Không cần tìm kiếm "phím nóng" hoặc xử lý trước dữ liệu đầu vào.

Tự động mở rộng quy mô theo chiều ngang

Tính năng tự động mở rộng quy mô theo chiều ngang của tài nguyên worker để có được kết quả thông lượng tối ưu, giúp cải thiện hiệu suất tổng thể so với giá.

Mức giá của tính năng hẹn lịch tài nguyên linh hoạt cho quy trình xử lý hàng loạt

Để xử lý với thời gian lập lịch linh hoạt cho công việc, chẳng hạn như công việc qua đêm, tính năng lập lịch tài nguyên linh hoạt (FlexRS) cung cấp mức giá thấp hơn cho việc xử lý hàng loạt. Những công việc linh hoạt này được đưa vào một hàng đợi và đảm bảo sẽ được truy xuất để thực thi trong vòng 6 giờ.

Hướng dẫn này được điều chỉnh từ https://cloud.google.com/dataflow/docs/quickstarts/quickstart-java-maven

Kiến thức bạn sẽ học được

  • Cách tạo dự án Maven bằng Apache Beam, sử dụng Java SDK
  • Chạy một quy trình mẫu bằng Bảng điều khiển Google Cloud Platform
  • Cách xoá bộ chứa Cloud Storage được liên kết và nội dung trong đó

Bạn cần có

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc Đọc và hoàn thành bài tập

Bạn đánh giá thế nào về trải nghiệm sử dụng các dịch vụ của Google Cloud Platform?

Người mới bắt đầu Trung cấp Thành thạo

2. Thiết lập và yêu cầu

Thiết lập môi trường theo tốc độ của riêng bạn

  1. Đăng nhập vào Cloud Console rồi tạo một dự án mới hoặc sử dụng lại một dự án hiện có. (Nếu chưa có tài khoản Gmail hoặc G Suite, bạn phải tạo một tài khoản.)

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

Hãy nhớ mã dự án, một tên duy nhất trên tất cả các dự án trên Google Cloud (tên ở trên đã được sử dụng và sẽ không hoạt động đối với bạn, xin lỗi!). Sau này trong lớp học lập trình này, chúng ta sẽ gọi nó là PROJECT_ID.

  1. Tiếp theo, bạn cần bật tính năng thanh toán trong Cloud Console để sử dụng các tài nguyên của Google Cloud.

Việc thực hiện lớp học lập trình này sẽ không tốn nhiều chi phí, nếu có. Hãy nhớ làm theo mọi hướng dẫn trong phần "Dọn dẹp" để biết cách tắt các tài nguyên nhằm tránh bị tính phí ngoài phạm vi hướng dẫn này. Người dùng mới của Google Cloud đủ điều kiện tham gia chương trình Dùng thử miễn phí trị giá 300 USD.

Bật các API

Nhấp vào biểu tượng trình đơn ở trên cùng bên trái màn hình.

2bfc27ef9ba2ec7d.png

Chọn API và dịch vụ > Trang tổng quan trong trình đơn thả xuống.

5b65523a6cc0afa6.png

Chọn + Bật API và dịch vụ.

81ed72192c0edd96.png

Tìm "Compute Engine" trong hộp tìm kiếm. Nhấp vào "Compute Engine API" trong danh sách kết quả xuất hiện.

3f201e991c7b4527.png

Trên trang Google Compute Engine, hãy nhấp vào Bật

ac121653277fa7bb.png

Sau khi bật, hãy nhấp vào mũi tên để quay lại.

Bây giờ, hãy tìm kiếm các API sau đây và bật chúng:

  • Cloud Dataflow
  • Stackdriver
  • Cloud Storage
  • JSON của Cloud Storage
  • BigQuery
  • Cloud Pub/Sub
  • Lưu trữ dữ liệu trên đám mây
  • API Cloud Resource Manager

3. Tạo bộ chứa mới trên Cloud Storage

Trong Bảng điều khiển Google Cloud Platform, hãy nhấp vào biểu tượng Trình đơn ở trên cùng bên trái màn hình:

2bfc27ef9ba2ec7d.png

Di chuyển xuống rồi chọn Cloud Storage > Browser (Bộ nhớ đám mây > Trình duyệt) trong mục phụ Bộ nhớ:

2b6c3a2a92b47015.png

Giờ đây, bạn sẽ thấy Trình duyệt Cloud Storage. Giả sử bạn đang sử dụng một dự án hiện không có bộ chứa Cloud Storage nào, bạn sẽ thấy lời mời tạo một bộ chứa mới. Nhấn vào nút Tạo vùng chứa để tạo một vùng chứa:

a711016d5a99dc37.png

Nhập tên cho nhóm của bạn. Như hộp thoại lưu ý, tên bộ chứa phải là duy nhất trên toàn bộ Cloud Storage. Vì vậy, nếu chọn một tên dễ nhận biết, chẳng hạn như "test", có thể bạn sẽ thấy rằng người khác đã tạo một vùng chứa có tên đó và bạn sẽ nhận được lỗi.

Ngoài ra, có một số quy tắc liên quan đến những ký tự được phép dùng trong tên nhóm. Nếu tên nhóm của bạn bắt đầu và kết thúc bằng một chữ cái hoặc chữ số, đồng thời chỉ sử dụng dấu gạch ngang ở giữa, thì bạn sẽ không gặp vấn đề gì. Nếu bạn cố gắng sử dụng các ký tự đặc biệt hoặc cố gắng bắt đầu hoặc kết thúc tên nhóm lưu trữ bằng một ký tự không phải là chữ cái hoặc số, hộp thoại sẽ nhắc bạn về các quy tắc.

3a5458648cfe3358.png

Nhập tên riêng biệt cho nhóm của bạn rồi nhấn vào Tạo. Nếu chọn một tên đã được sử dụng, bạn sẽ thấy thông báo lỗi như trên. Sau khi tạo thành công một vùng chứa, bạn sẽ được chuyển đến vùng chứa mới, trống trong trình duyệt:

3bda986ae88c4e71.png

Tên nhóm mà bạn thấy chắc chắn sẽ khác, vì tên nhóm phải là duy nhất trên tất cả các dự án.

4. Khởi động Cloud Shell

Kích hoạt Cloud Shell

  1. Trong Cloud Console, hãy nhấp vào Kích hoạt Cloud Shell H7JlbhKGHITmsxhQIcLwoe5HXZMhDlYue4K-SPszMxUxDjIeWfOHBfxDHYpmLQTzUmQ7Xx8o6OJUlANnQF0iBuUyfp1RzVad_4nCa0Zz5LtwBlUZFXFCWFrmrWZLqg1MkZz2LdgUDQ.

zlNW0HehB_AFW1qZ4AyebSQUdWm95n7TbnOr7UVm3j9dFcg6oWApJRlC0jnU1Mvb-IQp-trP1Px8xKNwt6o3pP6fyih947sEhOFI4IRF0W7WZk6hFqZDUGXQQXrw21GuMm2ecHrbzQ

Nếu chưa từng khởi động Cloud Shell, bạn sẽ thấy một màn hình trung gian (bên dưới phần hiển thị đầu tiên) mô tả về Cloud Shell. Nếu vậy, hãy nhấp vào Tiếp tục (và bạn sẽ không bao giờ thấy màn hình này nữa). Sau đây là giao diện của màn hình xuất hiện một lần:

kEPbNAo_w5C_pi9QvhFwWwky1cX8hr_xEMGWySNIoMCdi-Djx9AQRqWn-__DmEpC7vKgUtl-feTcv-wBxJ8NwzzAp7mY65-fi2LJo4twUoewT1SUjd6Y3h81RG3rKIkqhoVlFR-G7w

Quá trình cung cấp và kết nối với Cloud Shell chỉ mất vài giây.

pTv5mEKzWMWp5VBrg2eGcuRPv9dLInPToS-mohlrqDASyYGWnZ_SwE-MzOWHe76ZdCSmw0kgWogSJv27lrQE8pvA5OD6P1I47nz8vrAdK7yR1NseZKJvcxAZrPb8wRxoqyTpD-gbhA

Máy ảo này được trang bị tất cả các công cụ phát triển mà bạn cần. Nền tảng này cung cấp một thư mục chính có dung lượng 5 GB và chạy trong Google Cloud, giúp tăng cường đáng kể hiệu suất mạng và hoạt động xác thực. Bạn có thể thực hiện hầu hết, nếu không muốn nói là tất cả, công việc trong lớp học lập trình này chỉ bằng một trình duyệt hoặc Chromebook.

Sau khi kết nối với Cloud Shell, bạn sẽ thấy rằng mình đã được xác thực và dự án đã được đặt thành mã dự án của bạn.

  1. Chạy lệnh sau trong Cloud Shell để xác nhận rằng bạn đã được xác thực:
gcloud auth list

Đầu ra của lệnh

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
gcloud config list project

Đầu ra của lệnh

[core]
project = <PROJECT_ID>

Nếu không, bạn có thể đặt nó bằng lệnh sau:

gcloud config set project <PROJECT_ID>

Đầu ra của lệnh

Updated property [core/project].

5. Tạo dự án Maven

Sau khi Cloud Shell khởi động, hãy bắt đầu bằng cách tạo một dự án Maven bằng Java SDK cho Apache Beam.

Apache Beam là một mô hình lập trình nguồn mở cho các quy trình dữ liệu. Bạn xác định các quy trình này bằng chương trình Apache Beam và có thể chọn một trình chạy, chẳng hạn như Dataflow, để thực thi quy trình của mình.

Chạy lệnh mvn archetype:generate trong giao diện dòng lệnh của bạn như sau:

  mvn archetype:generate \
     -DarchetypeGroupId=org.apache.beam \
     -DarchetypeArtifactId=beam-sdks-java-maven-archetypes-examples \
     -DarchetypeVersion=2.46.0 \
     -DgroupId=org.example \
     -DartifactId=first-dataflow \
     -Dversion="0.1" \
     -Dpackage=org.apache.beam.examples \
     -DinteractiveMode=false

Sau khi chạy lệnh, bạn sẽ thấy một thư mục mới có tên là first-dataflow trong thư mục hiện tại. first-dataflow chứa một dự án Maven bao gồm Cloud Dataflow SDK cho Java và các quy trình mẫu.

6. Chạy quy trình xử lý văn bản trên Cloud Dataflow

Hãy bắt đầu bằng cách lưu mã dự án và tên nhóm Cloud Storage dưới dạng các biến môi trường. Bạn có thể thực hiện việc này trong Cloud Shell. Nhớ thay thế <your_project_id> bằng mã dự án của riêng bạn.

 export PROJECT_ID=<your_project_id>

Bây giờ, chúng ta sẽ làm tương tự cho bộ chứa Cloud Storage. Hãy nhớ thay thế <your_bucket_name> bằng tên duy nhất mà bạn đã dùng để tạo vùng chứa ở bước trước.

 export BUCKET_NAME=<your_bucket_name>

Thay đổi thành thư mục first-dataflow/.

 cd first-dataflow

Chúng ta sẽ chạy một quy trình có tên là WordCount, quy trình này đọc văn bản, mã hoá các dòng văn bản thành các từ riêng lẻ và thực hiện việc đếm tần suất của từng từ đó. Trước tiên, chúng ta sẽ chạy quy trình và trong khi quy trình đang chạy, chúng ta sẽ xem xét những gì đang diễn ra ở từng bước.

Khởi động quy trình bằng cách chạy lệnh mvn compile exec:java trong shell hoặc cửa sổ dòng lệnh. Đối với các đối số --project, --stagingLocation,--output, lệnh bên dưới sẽ tham chiếu đến các biến môi trường mà bạn đã thiết lập trước đó trong bước này.

 mvn compile exec:java \
      -Pdataflow-runner compile exec:java \
      -Dexec.mainClass=org.apache.beam.examples.WordCount \
      -Dexec.args="--project=${PROJECT_ID} \
      --stagingLocation=gs://${BUCKET_NAME}/staging/ \
      --output=gs://${BUCKET_NAME}/output \
      --runner=DataflowRunner \
      --region=us-central1 \
      --gcpTempLocation=gs://${BUCKET_NAME}/temp"

Trong khi công việc đang chạy, hãy tìm công việc đó trong danh sách công việc.

Mở Giao diện người dùng web Cloud Dataflow trong Bảng điều khiển Google Cloud Platform. Bạn sẽ thấy công việc đếm từ của mình có trạng thái Đang chạy:

3623be74922e3209.png

Bây giờ, hãy xem các thông số của quy trình. Bắt đầu bằng cách nhấp vào tên công việc của bạn:

816d8f59c72797d7.png

Khi chọn một công việc, bạn có thể xem biểu đồ thực thi. Biểu đồ thực thi của một quy trình biểu thị từng phép biến đổi trong quy trình dưới dạng một hộp chứa tên phép biến đổi và một số thông tin trạng thái. Bạn có thể nhấp vào dấu mũ ở góc trên cùng bên phải của mỗi bước để xem thêm thông tin chi tiết:

80a972dd19a6f1eb.png

Hãy xem quy trình chuyển đổi dữ liệu ở từng bước như thế nào:

  • Đọc: Ở bước này, quy trình đọc từ một nguồn đầu vào. Trong trường hợp này, đó là một tệp văn bản trên Cloud Storage chứa toàn bộ văn bản của vở kịch Vua Lear của Shakespeare. Quy trình của chúng tôi đọc tệp từng dòng và xuất ra từng PCollection, trong đó mỗi dòng trong tệp văn bản là một phần tử trong bộ sưu tập.
  • CountWords: Bước CountWords có hai phần. Trước tiên, nó sử dụng một hàm do song song (ParDo) có tên là ExtractWords để mã hoá từng dòng thành các từ riêng lẻ. Đầu ra của ExtractWords là một PCollection mới, trong đó mỗi phần tử là một từ. Bước tiếp theo, Count, sử dụng một phép biến đổi do Java SDK cung cấp. Phép biến đổi này trả về các cặp khoá, giá trị, trong đó khoá là một từ duy nhất và giá trị là số lần từ đó xuất hiện. Dưới đây là phương thức triển khai CountWords và bạn có thể xem toàn bộ tệp WordCount.java trên GitHub:
 /**
   * A PTransform that converts a PCollection containing lines of text into a PCollection of
   * formatted word counts.
   *
   * <p>Concept #3: This is a custom composite transform that bundles two transforms (ParDo and
   * Count) as a reusable PTransform subclass. Using composite transforms allows for easy reuse,
   * modular testing, and an improved monitoring experience.
   */
  public static class CountWords
      extends PTransform<PCollection<String>, PCollection<KV<String, Long>>> {
    @Override
    public PCollection<KV<String, Long>> expand(PCollection<String> lines) {

      // Convert lines of text into individual words.
      PCollection<String> words = lines.apply(ParDo.of(new ExtractWordsFn()));

      // Count the number of times each word occurs.
      PCollection<KV<String, Long>> wordCounts = words.apply(Count.perElement());

      return wordCounts;
    }
  }
  • MapElements: Thao tác này gọi FormatAsTextFn (được sao chép bên dưới), định dạng từng cặp khoá-giá trị thành một chuỗi có thể in.
  /** A SimpleFunction that converts a Word and Count into a printable string. */
  public static class FormatAsTextFn extends SimpleFunction<KV<String, Long>, String> {
    @Override
    public String apply(KV<String, Long> input) {
      return input.getKey() + ": " + input.getValue();
    }
  }
  • WriteCounts: Trong bước này, chúng ta sẽ ghi các chuỗi có thể in vào nhiều tệp văn bản được phân đoạn.

Chúng ta sẽ xem xét kết quả đầu ra từ quy trình này sau vài phút nữa.

Bây giờ, hãy xem trang Thông tin về công việc ở bên phải biểu đồ, bao gồm các tham số của quy trình mà chúng ta đã đưa vào lệnh mvn compile exec:java.

9723815a1f5bf08b.png

208a7f0d6973acf6.png

Bạn cũng có thể xem Bộ đếm tuỳ chỉnh cho quy trình, trong trường hợp này, bộ đếm cho biết số lượng dòng trống đã gặp phải cho đến nay trong quá trình thực thi. Bạn có thể thêm các bộ đếm mới vào quy trình để theo dõi các chỉ số dành riêng cho ứng dụng.

a2e2800e2c6893f8.png

Bạn có thể nhấp vào biểu tượng Nhật ký ở cuối bảng điều khiển để xem thông báo lỗi cụ thể.

23c64138a1027f8.png

Theo mặc định, bảng này sẽ hiện các thông báo trong Nhật ký công việc, báo cáo trạng thái của công việc nói chung. Bạn có thể dùng bộ chọn Mức độ nghiêm trọng tối thiểu để lọc tiến trình công việc và thông báo trạng thái.

94ba42015fdafbe2.png

Khi bạn chọn một bước trong quy trình trên biểu đồ, chế độ xem sẽ thay đổi thành nhật ký do mã của bạn tạo và mã được tạo đang chạy trong bước của quy trình.

Để quay lại Nhật ký công việc, hãy bỏ chọn bước bằng cách nhấp vào bên ngoài biểu đồ hoặc dùng nút Đóng trong bảng điều khiển bên phải.

Bạn có thể sử dụng nút Worker Logs (Nhật ký của Worker) trong thẻ nhật ký để xem nhật ký của worker cho các phiên bản Compute Engine chạy quy trình của bạn. Nhật ký Worker bao gồm các dòng nhật ký do mã của bạn và mã do Dataflow tạo ra để chạy mã đó.

Nếu bạn đang cố gắng gỡ lỗi cho một lỗi trong quy trình, thì thường sẽ có thêm nhật ký trong Nhật ký của Worker giúp giải quyết vấn đề. Xin lưu ý rằng các nhật ký này được tổng hợp trên tất cả các worker và có thể được lọc và tìm kiếm.

5a53c244f28d5478.png

Giao diện giám sát Dataflow chỉ cho thấy các thông báo nhật ký gần đây nhất. Bạn có thể xem tất cả nhật ký bằng cách nhấp vào đường liên kết Google Cloud Observability ở bên phải ngăn nhật ký.

2bc704a4d6529b31.png

Sau đây là thông tin tóm tắt về các loại nhật ký mà bạn có thể xem trên trang Giám sát → Nhật ký:

  • Nhật ký job-message chứa các thông báo cấp công việc do nhiều thành phần của Dataflow tạo. Ví dụ: cấu hình tự động mở rộng quy mô, thời điểm nhân viên bắt đầu hoặc tắt, tiến trình của bước công việc và lỗi công việc. Các lỗi ở cấp trình chạy bắt nguồn từ mã người dùng gặp sự cố và có trong nhật ký worker cũng sẽ lan truyền lên nhật ký job-message.
  • Nhật ký worker do các worker Dataflow tạo ra. Worker thực hiện hầu hết công việc trong quy trình (ví dụ: áp dụng ParDo cho dữ liệu). Nhật ký worker chứa các thông báo do mã và Dataflow của bạn ghi lại.
  • Nhật ký worker-startup có trong hầu hết các công việc Dataflow và có thể ghi lại các thông báo liên quan đến quy trình khởi động. Quá trình khởi động bao gồm việc tải các tệp jar của một công việc xuống từ Cloud Storage, sau đó khởi động các worker. Nếu có vấn đề khi khởi động worker, thì nhật ký này là nơi phù hợp để xem xét.
  • Nhật ký shuffler chứa các thông báo từ những worker hợp nhất kết quả của các thao tác song song trong quy trình.
  • Nhật ký dockerkubelet chứa các thông báo liên quan đến những công nghệ công khai này, được dùng trên các worker Dataflow.

Trong bước tiếp theo, chúng ta sẽ kiểm tra xem công việc của bạn có thành công hay không.

7. Kiểm tra để đảm bảo rằng công việc của bạn đã thành công

Mở Giao diện người dùng web Cloud Dataflow trong Bảng điều khiển Google Cloud Platform.

Bạn sẽ thấy công việc đếm từ của mình có trạng thái Running (Đang chạy) lúc đầu, sau đó là Succeeded (Đã hoàn tất):

4c408162416d03a2.png

Công việc này sẽ mất khoảng 3 đến 4 phút để chạy.

Bạn có nhớ khi chạy quy trình và chỉ định một nhóm đầu ra không? Hãy xem kết quả (bởi vì bạn có muốn biết mỗi từ trong Vua Lear xuất hiện bao nhiêu lần không?!). Chuyển về Cloud Storage Browser trong Bảng điều khiển Google Cloud Platform. Trong vùng lưu trữ, bạn sẽ thấy các tệp đầu ra và tệp dàn dựng mà tác vụ của bạn đã tạo:

25a5d3d4b5d0b567.png

8. Tắt tài nguyên

Bạn có thể tắt các tài nguyên của mình trên Bảng điều khiển Google Cloud Platform.

Mở trình duyệt Cloud Storage trong Bảng điều khiển Google Cloud Platform.

2b6c3a2a92b47015.png

Đánh dấu vào hộp bên cạnh nhóm bạn đã tạo rồi nhấp vào XOÁ để xoá vĩnh viễn nhóm và nội dung của nhóm.

2f7780bdf10b69ba.png

8051ef293a8e5cfe.png

9. Xin chúc mừng!

Bạn đã tìm hiểu cách tạo một dự án Maven bằng Cloud Dataflow SDK, chạy một quy trình ví dụ bằng Google Cloud Platform Console, đồng thời xoá vùng lưu trữ Cloud Storage được liên kết và nội dung của vùng lưu trữ đó.

Tìm hiểu thêm

Giấy phép

Tác phẩm này được cấp phép theo giấy phép Ghi công theo Creative Commons 3.0 và giấy phép Apache 2.0.