01 Exploring the Three Major Features of Open Resty

01 Exploring the Three Major Features of OpenResty #

Hello, I’m Wen Ming.

As mentioned in the opening, the advantages of OpenResty are obvious. However, before diving into the specific learning, let’s take a moment to briefly review the development process of OpenResty. This will help you better understand the content that follows.

Development of OpenResty #

Unlike other programming languages that start from scratch, OpenResty is built on mature open source components - NGINX and LuaJIT. OpenResty was born in 2007, but its first version did not choose Lua. Instead, it used Perl, which was influenced by the technical preferences of its author, Yichun “agentzh” Zhang.

However, Perl’s performance was far from satisfactory. So in the second version, Perl was replaced by Lua. However, in the official OpenResty project, Perl still plays an important role. Perl is used to build OpenResty’s engineering aspects, such as testing framework, linter, CLI, etc., which we will gradually introduce later.

Later, Yichun Zhang left Taobao and joined the CDN company Cloudflare in the United States. Because OpenResty’s high performance and dynamic advantages are well suited for CDN business needs, OpenResty quickly became the technical standard for CDNs. Through the rich lua-resty library, OpenResty began to gradually break away from the shadow of NGINX and formed its own ecosystem. It is widely used in areas such as API gateways and software WAFs.

In fact, I often say that OpenResty is a widely used technology, but it cannot be considered a popular technology. This may sound contradictory, so what does it really mean?

When I say it is widely used, it is because OpenResty is now the fifth-ranked web server globally. The popular features we often use, such as the ticket inquiry function of 12306 or the product details page of JD.com, are actually powered by OpenResty behind the scenes.

When I say it is not popular, it is because the proportion of using OpenResty to build business systems is not high. Most users use OpenResty to handle incoming traffic and do not go deep into the business itself. Therefore, their usage of OpenResty is usually superficial, as long as it meets their current needs. This is also related to the fact that OpenResty does not have mature web frameworks and ecosystems like Java and Python.

After discussing all this, the next step is to focus on several aspects of the OpenResty open source project that are commendable and worth learning.

The Three Major Features of OpenResty #

Detailed Documentation and Test Cases #

That’s right, documentation and testing are key indicators of the reliability of an open-source project, even ranking above code quality and performance.

The documentation of OpenResty is very detailed, with the author including every important detail in the documentation. In most cases, we can solve problems by carefully reading the documentation without having to search on Google or dig into the source code. To make things easier, OpenResty also comes with a command-line tool called restydoc that allows you to view the documentation directly from the shell, avoiding interruptions during the coding process.

However, the documentation only contains one or two generic code snippets and does not provide complete and complex examples. Where can we find such examples?

For OpenResty, the answer lies in the /t directory, which contains all the test cases. Each test case includes complete NGINX configurations, Lua code, as well as input and expected output data for testing. However, OpenResty uses a testing framework that is completely different from other assertion-style testing frameworks, which I will discuss in a separate section later.

Synchronous Non-blocking #

Coroutine is a feature added to many scripting languages in recent years to improve performance. However, their implementations are not perfect, some being just syntax sugar, while others require explicit keyword declaration.

OpenResty, on the other hand, has no historical burdens and supported coroutines from the very beginning, implementing a programming model called “synchronous non-blocking”. This is important because programmers are human beings and the code should be more in line with human thinking habits. Explicit callbacks and asynchronous keywords can interrupt the flow of thought and make debugging difficult.

Let me explain what synchronous non-blocking means. First, let’s talk about synchronous, which is straightforward - it means executing the code in sequential order. For example, consider the following pseudocode:

local res, err = query-mysql(sql)
local value, err = query-redis(key)

If we have to wait for the MySQL query result to return before continuing to query Redis within the same request connection, that’s synchronous. If we can continue to query Redis without waiting for the return of MySQL, that’s asynchronous. For OpenResty, the majority of operations are synchronous, and only operations related to background timers like ngx.timer are asynchronous.

Now let’s talk about non-blocking, which can easily be confused with “asynchronous”. Here, we are referring to “blocking” specifically in the context of blocking operating system threads. Continuing with the previous example, let’s assume that querying MySQL takes 1 second. If during this 1 second, the operating system’s resources (CPU) are idle and waiting for the return, that’s blocking; if the CPU takes advantage of this time to process requests from other connections, that’s non-blocking. Non-blocking is also the key to achieving high concurrency in scenarios like C10K and C100K.

Understanding the concept of synchronous non-blocking is important, and I recommend you to carefully ponder over it. I believe it is best not to interpret this concept through analogies, as an inappropriate analogy might only make things more confusing.

In OpenResty, the above pseudocode can be implemented as synchronous non-blocking without using any explicit keywords. This once again reflects the principle of making it easier for developers to use OpenResty.

Dynamic #

OpenResty has a significant advantage that has not been fully explored, which is its dynamic nature.

Traditional web servers, such as NGINX, require modifying configuration files on disk and reloading them to take effect whenever any changes occur. This is because they do not provide APIs to control runtime behavior. As a result, in the field of microservices where frequent changes are required, NGINX has made multiple attempts but achieved little success. On the other hand, the rising star Envoy poses a threat to NGINX by leveraging dynamic control APIs like xDS.

Different from NGINX and Envoy, OpenResty is controlled by Lua, a scripting language, and dynamic is the inherent advantage of Lua. Through the Lua API provided by the lua-nginx-module module in OpenResty, we can dynamically control routing, upstreams, SSL certificates, requests, responses, and more. What’s more, you can even modify business logic without restarting OpenResty, not limited to the Lua API provided by OpenResty.

Here’s a suitable analogy to help you understand the above explanation about dynamic nature. You can think of a web server as a car speeding on a highway. NGINX needs to stop to change tires or paint color, Envoy can change tires and color on the go, while OpenResty, in addition to possessing the capabilities of the former, can directly transform a regular car into a sports car without stopping.

Clearly, with this “supernatural” ability, OpenResty’s capabilities and possibilities have expanded to other areas, such as serverless computing and edge computing.

What are the focal points of your study? #

After discussing the key features of OpenResty, how should you go about learning it? In my opinion, learning requires focusing on the main points and developing around them, rather than grasping at every bit of information. This way, you can construct a coherent knowledge system.

It’s important to note that no matter how comprehensive a course may be, it cannot cover all possible issues, let alone directly solve every bug and exception you encounter online.

Returning to the topic of learning OpenResty, from my perspective, in order to become proficient in it, you must understand the following eight key areas:

  • Synchronous and non-blocking programming models;

  • Functions of different stages;

  • Differences between LuaJIT and Lua;

  • OpenResty API and related libraries;

  • Coroutines and cosockets;

  • Unit testing frameworks and performance testing tools;

  • Flame graphs and related toolchains;

  • Performance optimization.

These are the focal points of our study, and I will discuss them separately in various modules of this column. During your learning process, I hope you can apply the principles learned to other topics and, based on your own interests and background, extensively delve into certain chapters.

If you are a beginner in OpenResty, then I suggest you follow the progress of this column entirely. Install OpenResty in your own environment, run and modify the example code. Remember, your focus should be on building a comprehensive understanding of OpenResty rather than stubbornly mastering one specific knowledge point. Of course, if you have any questions, feel free to ask in the comments section, and I will address your concerns.

If you are using OpenResty in a project, that’s great! I believe that as you read the chapters on LuaJIT and performance optimization, you will resonate more and be able to apply them practically, seeing the performance metrics improve in your project before and after optimization.

Additionally, if you want to contribute code to OpenResty and its associated libraries, the biggest hurdle is not understanding the principles of OpenResty or how to write NGINX C modules. It is actually writing test cases and adhering to the code standards. I have seen many contributors to OpenResty code (including myself) spending a lot of time repeatedly modifying test cases and code style in a pull request because there are many obscure conventions. Therefore, the code standards and unit testing sections of this column are prepared for you.

If you are a test engineer, even if you don’t use OpenResty, the testing frameworks and performance analysis toolsets of OpenResty will undoubtedly provide you with a lot of inspiration. After all, OpenResty has invested and accumulated a great deal in the area of testing.

Conclusion #

Feel free to leave a message and share your learning journey in OpenResty. During this period, have you encountered any obstacles? You are also welcome to share this article with your colleagues and friends.

As always, if you have any questions during your learning process, feel free to leave a comment in the column, and I will respond to you as soon as possible.