Có đủ bằng chứng để chứng minh tầm quan trọng của kiểm tra tự động. Các dự án trong các lĩnh vực mới thường bỏ qua kiểm tra tự động, vì chính tên miền đánh cắp sự chú ý của các nhà phát triển. Tuy nhiên, thiếu kiểm tra ngụ ý 'bây giờ hãy cười, hãy khóc sau'. Một số công cụ xung quanh không gian Dữ liệu lớn đã được kiến ​​trúc xung quanh khả năng kiểm tra - hoặc, ít nhất, cộng đồng đã quan tâm đến nó sau đó. Chúng ta hãy xem Spark, và cụ thể hơn là Spark Streaming, thực hiện trong các khía cạnh khác nhau của thử nghiệm tự động. 

Xử lý luồng là gì?

Xử lý luồng là một mô hình lập trình hoạt động trên các luồng dữ liệu vô hạn và liên tục, áp dụng các hoạt động song song trên chúng. Ý tưởng rất đơn giản nhưng mạnh mẽ và sự phức tạp của việc thực hiện sẽ thay đổi tùy thuộc vào các yêu cầu sau:

  • Phân phối ngữ nghĩa: ít nhất một lần, nhiều nhất một lần hoặc chính xác một lần.
  • Hoạt động nhà nước: nhà nước địa phương hoặc từ xa.
  • Độ trễ: thời gian thực hoặc gần thời gian thực.
  • Độ tin cậy, tính sẵn sàng cao và độ bền.

Spark Streaming là gì?

Spark đã là một cuộc cách mạng trong không gian Dữ liệu lớn . Nó đã thay thế MapReduce của Hadoop làm khung xử lý hàng loạt ưa thích. Những lý do chính là:

Spark Streaming được xây dựng trên đỉnh Spark. Điều đó có nghĩa là bạn có thể sử dụng cơ sở hạ tầng và các khái niệm Spark như YARN , HDFS hoặc RDD . Trên hết, chúng tôi sẽ có bản tóm tắt để giúp chúng tôi xây dựng các tính năng phát trực tuyến như tập hợp hoặc cửa sổ trượt.

Đơn vị kiểm tra là gì?

Đây là một loạt tuyệt vời về quan điểm khác nhau về thử nghiệm đơn vị. Để giữ cho phạm vi của bài đăng này tập trung, chúng tôi sẽ làm việc với các đặc điểm sau:

  • Network Isolation: mã sản xuất được thử nghiệm sẽ liên quan đến mã sống trong một quy trình duy nhất. Không có cuộc gọi mạng được cho phép.
  • Cách ly khung: chúng tôi muốn kiểm tra mã của mình, càng nhiều càng tốt, và không phải là các tương tác với các khung cơ bản.

Cơ sở thử nghiệm Spark để giải cứu

Kiểm soát vòng đời của Spark có thể rất cồng kềnh và tẻ nhạt. May mắn thay, dự án Spark thử nghiệm cơ sở cung cấp cho chúng tôi Scala Traits xử lý các chi tiết cấp thấp đó cho chúng tôi. Truyền phát có một chút phức tạp khi chúng ta cần tạo dữ liệu để nhập dữ liệu một cách kịp thời. Đồng thời, đồng hồ bên trong Spark cần đánh dấu một cách có kiểm soát nếu chúng ta muốn kiểm tra các hoạt động được tính thời gian dưới dạng cửa sổ trượt.

Hãy xem cách kiểm tra ví dụ điển hình của WordCount:

def count(lines: DStream[String]): DStream[(String, Int)] = lines.flatMap(_.split(" ")) .map(word => (word, 1)) .reduceByKey(_ + _) 

Như bạn có thể thấy, đây là một chức năng thuần túy, không có tác dụng phụ hoặc truy cập vào trạng thái bên ngoài. Chúng ta có thể lý do về nó bằng cách xem xét chữ ký của hàm. DStream là sự trừu tượng hóa cơ bản trong Spark Streaming và Spark tests Base sẽ giúp chúng ta đối phó với nó.

class WordCountSpec extends StreamingSuiteBase { test("count words") { val input = List(List("the word the")) val expected = List(List(("the", 2), ("word", 1))) testOperation[String, (String, Int)](input, count _ , expected, ordered = false) } } 

Bạn không cần phải làm việc trực tiếp với bản tóm tắt DStream. Đầu vào sẽ là một chuỗi các bộ sưu tập đầu vào và mọi bộ sưu tập sẽ được sử dụng với một tích tắc của đồng hồ nội bộ Spark Streaming. Bạn có thể tìm thấy nhiều ví dụ về những gì bạn có thể làm với thư viện này ở đây .

Tham gia xử lý truyền phát và hàng loạt

Một kịch bản cổ điển trong Xử lý luồng đang tham gia một luồng với cơ sở dữ liệu để làm phong phú, lọc hoặc biến đổi các sự kiện có trên luồng. Nhờ Spark 2.0Truyền có cấu trúc , Truyền phát và Batch được căn chỉnh và bằng cách nào đó ẩn đi, trong một lớp trừu tượng.

Vì Spark 2.0 đã được phát hành gần đây, hãy tập trung vào một ví dụ về API cũ:

def countWithSpecialWords(lines: DStream[String], specialWords: RDD[String]): DStream[(String, Int)] = { val words = lines.flatMap(_.split(" ")) val bonusWords = words.transform(_.intersection(specialWords)) words.union(bonusWords) .map(word => (word, 1)) .reduceByKey(_ + _) } 

Đây là một ví dụ phức tạp nhưng phục vụ như là một cuộc biểu tình. Hệ thống của chúng tôi giữ một danh sách các từ đặc biệt trong cơ sở dữ liệu bên ngoài. Chúng tôi muốn đếm một từ hai lần trong luồng được chứa trong túi từ đặc biệt đó. Điều quan trọng cần lưu ý là chức năng của chúng tôi không có bất kỳ mối quan tâm nào về cách truy xuất các từ đặc biệt đó. Điều đó được thực hiện bên ngoài chức năng và điều đó cho chúng ta cơ hội để kiểm tra logic.

val lines = ingestEventsFromKafka(ssc, brokers, topic).map(_._2) val specialWords = ssc.sparkContext .cassandraTable(keyspace, specialWordsTable) .map(_.getString("word")) countWithSpecialWords(lines, specialWords) .saveToCassandra(keyspace, wordCountTable) 

Hiện tại, không có hỗ trợ cho loại hoạt động đó trên Spark tests Base, nhưng tôi đã tạo ra một PR sẽ cung cấp chức năng đó.

test("stream and batch transformation") { def intersection(f1: DStream[String], f2: RDD[String]) = f1.transform(_.intersection(f2)) val stream = List(List("hi"), List("holden"), List("bye")) val batch = List("holden") val expected = List(List(), List("holden"), List()) testOperationWithRDD[String, String, String](stream, batch, intersection _, expected, ordered = false) } 

Phần kết luận

Kiểm thử đơn vị Spark Streaming khá dễ dàng nhờ Spark Kiểm tra cơ sở. Tuy nhiên, chúng ta cần phải kiến ​​trúc các hoạt động của mình một cách sạch sẽ, nếu chúng ta muốn tận dụng thư viện này. Trong bài đăng tiếp theo, chúng ta sẽ xem cách thực hiện các bài kiểm tra tích hợp với Spark Streaming, Kafka và Cassandra.