17 Hands on Experience Ii How to Implement a Stateful Service Under a Cloud Function Scenario

17 Hands-On Experience II How to implement a stateful service under a cloud function scenario #

Hello, I’m Jingyuan.

Today, we will have a hands-on experience on implementing a stateful storage solution.

While FaaS (Function as a Service) provides an important Serverless foundation for application development, operation, and management, services do not exist in isolation. A complete application system often relies on third-party services such as authentication, storage, message queues, etc.

On the other hand, with the rise of microservices concept and architecture, business functions and personnel specialization have become more refined. In our work, it is impossible to implement multiple functions under a monolithic application. Therefore, collaboration becomes particularly important. The key to collaboration lies in the ability of third-party media to store transaction state.

Since the first lesson, we have been exploring the technology and practices in the Serverless field from the perspective of FaaS. Today, I will take you to understand the story behind cloud functions and statefulness, and guide you to experience the application of the concept “Serverless = FaaS + BaaS”. We will design and experience a stateful service for inspecting advertising materials.

Limitations of FaaS #

One prominent characteristic of Function-as-a-Service (FaaS) is that the granularity of applications is no longer a monolithic entity encompassing numerous business functionalities, but rather a collection of fine-grained functions. Each function completes a concrete business logic and is executed in response to events or business processing.

This brings about an obvious problem: if there is a need to handle complex functionalities such as multi-threaded data sharing in microservices, state-driven composition, or session persistence, FaaS may appear inadequate.

However, this does not mean that a Serverless architecture under FaaS cannot handle these situations. Think about how many methods we have to address this issue. With this question in mind, let’s move on to the next section.

The Infinite Possibilities of Functions #

Just now we talked about the basic building block of function computing, which is the “function”. Although FaaS itself has certain limitations, the function itself is powerful. Why do we say that?

I believe you must have played with building blocks before. In fact, functions are like Lego bricks. They can exist as products of FaaS, or they can exist as nested functions in microservice modules. The only difference is the granularity.

Functions themselves are the result of the development of service architecture. The development from monolithic applications to microservices involves both horizontal and vertical splitting of functionalities. The implementation of functions from microservices is a sublimation of the entire form and efficiency.

Image

Therefore, functions also exist as the cornerstone of Serverless. You can use the form of function framework to build Serverless applications. For example, Google and Baidu’s search cards can be built using functions. The search function can exist based on Serverless, scaling up and down with traffic.

This also explains an important point: functions are a concrete factor for implementing business. You can use this factor for building FaaS, or you can use it for building other Serverless products. With this understanding, let’s talk about the implementation of two types of stateful functions under the function paradigm.

Two Directions for Stateful Function Services #

The terms “stateful” and “stateless” are actually referring to service architecture. According to Wikipedia, a stateful system in computer science is defined as a system that needs to remember previous events or user interactions. These states generally exist in the form of reusable data, shared addresses, and so on. Examples include data processing in machine learning, message passing in batch processing, and session persistence in interactive access.

Looking at the computation of functions, there are currently two main methods for handling state in stateful scenarios.

One approach is the stateful function programming model. Huawei Cloud Function Compute, for example, mainly records the state of functions through the context field. When the function is executed, it loads the content saved in the context field. It also sets a timeout using setTimeout, and if the state is not updated within the timeout period, the state will be deleted.

This type of stateful service does not rely on external modules, so it has a significant advantage in terms of response speed. This stateful function model is mainly used in four types of scenarios:

  • Iterative computation in large-scale distributed machine learning: In this mode, the number of parameters can range from billions to trillions. Using stateful function services can save storage space for parameters and reduce network communication overhead.
  • Big data computing scenarios: Using stateful function services can avoid I/O with external media during the computation process, greatly reducing latency.
  • Real-time interactive scenarios: For example, multiplayer games with high latency requirements can greatly reduce latency by caching and localizing game states.
  • Multi-user collaboration scenarios: For online document editing, this can rely on user session distribution to the same instance for processing.

In general, when choosing a stateful function service, the priority relationship between computation and data needs to be considered, as well as which data to select as process states.

However, the stored state information is limited. If there are dependencies on upstream and downstream services and persistent storage, such as high-concurrency log messages and video/image verification, it cannot be achieved solely through function state context and is not applicable.

FaaS requires interaction with upstream and downstream services such as message queues and object storage. Therefore, FaaS often needs to combine with BaaS services to achieve serverless capabilities. In other words, user requests still rely on other persistent modules.

This brings me to another approach: the combination of typical FaaS and BaaS, where FaaS provides the business logic layer processing and BaaS provides the capabilities of the infrastructure layer, allowing stateful data, process messages, etc., to be stored in BaaS services.

Depending on the requirements of stateful functions, different BaaS services are often chosen, such as serverless databases and serverless message queues.

Let’s start with serverless databases. Well-known serverless databases in the industry include Alibaba Cloud PolarDB Serverless, Tencent Cloud PostgreSQL for Serverless, and Amazon Aurora Serverless. Serverless databases decouple computing power from storage resources and allocate CPU and memory resources accordingly based on business needs.

For in-memory databases, a large amount of memory resources is required, but CPU resources are used less. For databases with many transaction operations, the resource requirements are the opposite. Serverless databases can significantly reduce costs and are suitable for diversified business scenarios.

Next, let’s discuss serverless message queues. They support the asynchronous execution of function computing, message buffering, and message decoupling. An example commonly used in the industry is Apache Pulsar.

As the thinking construct describes, it is the combination of FaaS and BaaS that truly achieves the serverless architecture. BaaS complements the statelessness of FaaS, which means Serverless = FaaS + BaaS.

A typical use case is when uploading images or videos to cloud object storage, we often need to perform operations on content and format: marking or deleting explicit images/videos, modifying image formats, adding/removing watermarks, etc.

In this case, we can encapsulate the processing logic into functions and deploy them on the FaaS platform, and then create an object storage trigger. When the event of a user uploading an image/video is detected at the cloud object, it triggers the function computing to execute the image/video processing function. After processing, it is saved in the object storage, which is the BaaS, and the upper-level business logic processing is the FaaS.

Through this implementation approach, the separation of computation and storage is achieved. The computation layer is stateless and can scale the number of function instances with traffic. At the same time, due to the storage provided by BaaS, both traffic handling and data security and fault recovery capabilities are ensured.

Image

After reading this use case, you may feel that implementing a stateful service in a serverless function scenario is relatively easy. This is one of the reasons why function computing has become more popular in recent years.

Hands-on Experience #

Next, we will go through a case study to explore how to implement a stateful service in the cloud function scenario.

In the web pages we typically search, we often see various advertising materials. However, these materials may contain illegal ad copies or have problems like URL redirection. Therefore, we need to inspect the advertising materials to ensure their legitimacy.

To deal with such a situation, our usual approach is to start a certain amount of inspection programs to scan the advertising library materials repeatedly. However, if we encounter holidays, the amount of advertising materials will increase significantly, or there will be a large batch of materials every now and then. In that case, how can we ensure a fast scanning completion?

How to decide? #

This is a very typical scenario, similar to content review of articles, transaction reconciliation, etc. Let’s analyze the characteristics of these scenarios:

First, the traffic is not evenly distributed at all times. It fluctuates and has obvious peaks and valleys.

Second, it is not very sensitive to response time. Millisecond-level response is not required.

Third, it is stateful and requires marking of processed content.

Fourth, the processing is not complex and has clear rules.

This aligns with the use of Serverless technology in the form of FaaS to solve the problem. It can deal with traffic peaks and reduce costs. As for the need for stateful marking processing, we can choose to solve it using BaaS-ized cloud storage.

How to design? #

Before the code development, let’s first confirm the overall design framework. For triggering the scanning tasks, we can choose the crontab trigger of Function Compute or a resident task to monitor the status of the advertising library materials. Alternatively, we can use a Kafka trigger. It depends on how you want to implement the earlier part of material acquisition. Our focus is on the stateful storage and business implementation under the FaaS form.

For storage of advertising material data, we choose cloud database. Function Compute is responsible for validating the read material data. The schematic diagram is as follows:

Image

Finally, we can create a flowchart to summarize the process of material inspection. We use the timed trigger of FaaS to trigger the validation task and read the data to be validated from the cloud database: including material information URL, page text, and illegal keywords. Then, we compare the ad copy with the illegal keywords and validate the URL links. After the validation is completed, illegal data and URLs are marked and written back to the cloud database.

Image

How to implement? #

After understanding the design ideas, let’s see how to implement them. For today’s practice, I have chosen Alibaba Cloud Function Compute and Cloud Database RDS.

We need to create a Golang function in Alibaba Cloud FC in advance and download it to the local environment. At the same time, open an RDS MySQL database. Note: it can be opened in Serverless mode.

BaaS storage #

As mentioned earlier, material data and illegal text need to be stored in the cloud database. Let’s see how to design these two data structures.

First is the material data structure, which can be implemented according to the following example:

// Material Storage
type AdvertData struct {
   // User ID
   UserID string
   // User Name
   UserName string
   // User ID Number
   UserIDNumber string
   // URL Link of the advertisement
   AdUrl string
   // Content of the advertisement copy
   AdContent string
   // Is the page text legal
   LegalStatus bool
   // Is the URL link valid
   UrlValidStatus bool
}

This core struct records the information of the user who placed the advertisement and the ad copy and URL data. Meanwhile, the fields “UrlValidStatus” and “LegalStatus” are used to indicate whether the URL link of the user is valid and whether the displayed content on the page is legal.

Next is the illegal keywords, which can also be implemented according to the following example. However, if it is for production environment usage, the fields should be designed according to the complexity of the system:

// Illegal Keywords
type IllegalKeywords struct {
  // Keyword ID
  ID string
  // Keyword
  Keyword string
}

// Illegal keyword storage
type IllegalKeywords struct {
   // Keyword name
   Keyword string
   // Keyword language: Chinese/English
   languages string
   // Illegal level: high/medium/low
   IllegalLevel string
}

With the storage structure in place, let’s take a look at how Function Computing connects to the cloud database.

First, we need to configure the RDS database environment variables in the s.yaml file of the downloaded Golang code. It is worth noting that if the created RDS instance is not in the available zone supported by Function Computing, additional VPC configuration is required.

Next, in the ConnectDb() function of the database initialization code, we can directly read the database configuration information from the environment variables and connect to the RDS database. You can also place ConnectDb() outside the handler outside of function entry processing, so that the database connection instance can continue to be reused before being destroyed, avoiding duplicate creation. As for closing the connection to the RDS database, we can use the CloseDb() function.

Core Process #

Next, let’s look at the core logic of Function Computing processing, which includes obtaining all illegal keywords, obtaining materials, and verifying the legality of materials. For ease of understanding, we will describe the implementation ideas in pseudo-code:

func CheckAllAdvertData() {
   // Get all illegal keywords
   keywords, _ := illegalKeyword.GetAllIllegalKeywords()
   i := 0
   for {
      // Get materials, in a real production environment, you need to consider indexing issues
      advertDataList, _ := ad.GetAdvertData("desc", PAGE_SIZE, i)
      if len(advertDataList) > 0 {
         // Verify the legality of the material
         CheckUrlStatus(advertDataList, keywords)
      }
      i++
   }
   CloseDb()
}

Here, we can focus on the implementation process of the material legality verification function CheckUrlStatus.

func CheckUrlStatus(advertDataList []*AdvertData, keyWords []*IllegalKeywords) error {
   for _, advertData := range advertDataList {
      // Get the data
      resp, _ := http.Get(advertData.AdUrl)
      // The URL link is invalidated
      if resp.StatusCode != 200 {
         newAdvertData := &AdvertData{UrlValidStatus: false}
         err = advertising.UpdateAdvertData(advertData, newAdvertData)
      }
      .....
      body, _ := ioutil.ReadAll(resp.Body)
      bodyString := string(body)
      
      // Check if there are illegal characters in the URL data
      checkResult, _ := checkUrlData(bodyString, keyWords)
      // If the check fails, write it to the database and change the field
      if checkResult {
         newAdvertData := &AdvertData{LegalStatus: false}
         err = advertising.UpdateAdvertData(advertData, newAdvertData)
      }
   }
   fmt.Println("Verification successful")
   return nil
}

The validation function first requests the URL and checks if the response is normal. If the URL link has been invalidated, it will change the UrlValidStatus field in the cloud database and mark it as URL invalid. If the URL is valid, it will analyze whether there are illegal characters in the returned data. If there are illegal characters, it will change the LegalStatus field and mark the material information as illegal.

With this, we have completed the explanation of the main implementation points of a stateful service for advertising material inspection. In reality, the scanning and verification process of advertisement materials and landing pages is much more complex than what we have demonstrated today. However, as long as we grasp the basic flow design and the key design points, I believe you will be able to handle more complex situations in a production environment as well.

Summary #

Finally, let me summarize today’s content.

Firstly, I discussed the limitations of Function as a Service (FaaS) in handling stateful scenarios. However, we can see that functions, as an integral part of serverless architecture, are ubiquitous. In fact, we can even use functions to make the development of more efficient business functions for microservices.

Therefore, we can see two different ways to implement stateful scenarios: using stateful services provided by function computing itself, or combining FaaS with Backend as a Service (BaaS).

Stateful function services are more suitable for iterative calculations in machine learning, data processing, real-time interaction, and collaborative scenarios. On the other hand, FaaS + BaaS is the complete implementation of serverless. When considering the serverless transformation of an application system, we need to consider these two aspects. Currently, major cloud providers have also launched various BaaS services, such as databases, message queues, and caching, aimed at further separating computing and storage to improve elasticity.

Finally, through the case of an advertising material inspection, we have also helped you deepen your understanding of “implementing more complex cloud function functionality based on storage media.” I hope you will have more reference choices in terms of cost reduction and efficiency improvement in your future work.

Reflection Question #

Alright, this lesson is coming to an end, and I have one last question for you to ponder.

In your current or future work, what are some scenarios where FaaS and BaaS could be combined? What BaaS services have you encountered so far, and how do you feel about using them?

Please feel free to share your thoughts and answers in the comments section. Let’s exchange ideas and discuss together. Thank you for reading, and feel free to share this lesson with more friends for further learning and discussion.