50 Q& a Five How to Introduce Open Resty Into Work

50 Q&A Five- How to Introduce OpenResty into Work #

Hello, I am Wen Ming.

Several months have passed in the blink of an eye. Now, we have completed the last section of the OpenResty column, which is about microservices API gateways. Congratulations on not falling behind and for actively learning, practicing, and sharing your thoughts.

Many of the questions raised in the comments are very valuable. I have already replied to most of them in the app. However, for some questions that are not convenient to answer on mobile, or those that are more typical and interesting, I have extracted them to be included in today’s Q&A session, where I will address them collectively. This is also to ensure that no one misses any important points.

Now, let’s take a look at the 5 questions for today.

Question 1: The use of OpenResty in work #

Q: The semester is almost over, and I have basically kept up with the course. However, I haven’t had much practical experience (not used in work yet). But this is indeed a very powerful course. Thanks to Teacher Wen for the continuous sharing, I will also introduce OpenResty when appropriate in my future work.

A: Thank you for your recognition. With regards to this comment, I would like to discuss how to introduce OpenResty in work, which is indeed a worthy topic to discuss.

OpenResty is based on Nginx and adds the lua-nginx-module C module and many lua-resty libraries on top of it. Therefore, OpenResty can be seamlessly replaced with Nginx, which is the lowest-cost way to start using OpenResty. Of course, this replacement process has its risks, and you need to pay attention to the following three points.

Firstly, confirm the version of the online Nginx. The major version of OpenResty is consistent with Nginx, for example, OpenResty 1.15.8.1 uses Nginx 1.15.8 as the kernel. If the version of the online Nginx is higher than the latest version of OpenResty, then you should be cautious when switching to OpenResty. After all, the upgrade speed of OpenResty is relatively slow, lagging behind Nginx’s mainline version by six months to a year. If the version of the online Nginx is the same as or lower than OpenResty, then the prerequisite for upgrading is met.

Secondly, testing. Testing is the most important stage. Replacing Nginx with OpenResty has very low risk, but there are still some risks involved. For example, whether there are custom C modules that need to be compiled, the version of openssl that OpenResty relies on, and whether the patches applied by OpenResty to Nginx will affect the business, etc. You need to replicate some of the business traffic for verification.

Thirdly, traffic switching. After the basic verification is passed, you also need to verify with real online traffic in a phased manner. At this time, in order to be able to roll back quickly, we can deploy OpenResty on a few new servers instead of directly replacing the existing Nginx service. If there are no problems, we can choose the binary hot upgrade method or gradually remove and replace Nginx from the LB to upgrade.

In addition to replacing Nginx, two other relatively easy entry points for OpenResty are WAF and API gateways. They both have high requirements for performance and dynamism, and there are corresponding open source projects that can be used out of the box, which I have also mentioned in the column.

If you continue to deepen OpenResty into the business layer, you need to consider more factors beyond technology, such as whether it is easy to recruit engineers related to OpenResty, and whether it can integrate with the company’s existing technology systems, and so on.

In summary, starting from replacing Nginx and then gradually expanding the use of OpenResty is a good approach to consider.

Question 2: OpenResty’s Database Encapsulation #

Q: According to your guidance, we should try to avoid using .. string concatenation, especially in hot code areas. However, when dealing with database access, I need to dynamically construct SQL statements (i.e., insert variables into the statements), which seems to be a very common use case. But for this requirement, at the moment, the only way I can think of that is both simple and high performance is string concatenation.

A: You can first analyze whether string concatenation of SQL statements is a bottleneck by using SystemTap or other tools introduced in our previous courses. If it is not a bottleneck, there is naturally no need for optimization, as premature optimization is the root of all evil.

If the bottleneck is indeed the string concatenation of SQL statements, then we can optimize it by using the prepare statement of the database or by using the array-based concatenation method. However, the support of prepare statement in lua-resty-mysql has always been in the TODO state, so only the array concatenation method is left. This is also a common issue with lua-resty libraries, where most of the functionality is implemented and in a usable state, but the updates are not timely enough. In addition to the prepare statement of the database, lua-resty-redis has also lacked support for cluster.

String concatenation, including this type of issue with lua-resty libraries, is something that OpenResty aims to completely solve with DSL (Domain Specific Language) - using compiler techniques to automatically generate arrays for string concatenation, hiding these details from the upper layers so that users don’t have to be aware of them. The use of a small language like wirelang to automatically generate various lua-resty network communication libraries also eliminates the need for manual coding.

This sounds great, right? But there is one problem that must be faced, which is that the code generated automatically is not human-friendly. If you want to learn or modify the generated code, you have to learn compiler techniques and a DSL that may not be open sourced, which will raise the barrier to entry for participating in the community.

Question 3: OpenResty Web Framework #

Q: I want to use OpenResty to build a web project, but I find it difficult because I can’t find a mature web framework. I have to do a lot of work from scratch, like the database operations mentioned earlier (I couldn’t find a library that allows me to dynamically construct SQL statements and perform fluent operations). So I would like to ask the teacher if there are any good web frameworks that you can recommend?

A: In the awesome-resty repository, we can see a dedicated Web framework category, where there are 20 open source projects. However, most of them are in a stagnant state. Among them, you can try Lapis, lor, and xiangcao to see which one is more suitable.

Indeed, due to the lack of strong web frameworks to rely on, OpenResty can be insufficient in handling large projects. This is also one of the reasons why few people use OpenResty for business systems.

Question 4: How to modify the content-length in the response header after modifying the response body? #

Q: If we need to modify the content of the response body, we can only do it in the body filter. However, this will cause a mismatch between the body length and the content-length. How should we handle this?

A: In this case, we need to set the content-length response header to nil in the header filter stage before the body filter, and instead use streaming output.

Here is an example code:

server {
    listen 8080;

    location /test {
        proxy_pass http://www.baidu.com;
        header_filter_by_lua_block {
            ngx.header.content_length = nil
        }
        body_filter_by_lua_block {
            ngx.arg[1] = ngx.arg[1] .. "abc"
        }
    }
}

From this code, you can see that in the body filter stage, ngx.arg[1] represents the response body. If we append the string abc to it, the content-length in the response header will no longer be accurate. Therefore, in the header filter stage, we disable it directly.

Furthermore, from this example, we can also see how the different stages in OpenResty work together. Please pay attention to and ponder over this aspect.

Question 5: Search path for Lua code #

Q: lua_package_path seems to configure the search path for Lua dependencies. For content_by_lua_file, I experimented and found that it only searches under the prefix based on the relative path provided in the instruction, and does not search under lua_package_path. Is my understanding correct?

A: It is commendable that you have taken the initiative to experiment and think critically, and your understanding is indeed correct. The lua_package_path directive is used to load Lua modules. For example, when we call require 'cjson', Lua will search for the cjson module in the directories specified in lua_package_path. On the other hand, content_by_lua_file works differently. It expects a file path in the disk:

location /test {
    content_by_lua_file /path/test.lua;
}

If the path provided is not an absolute path but a relative path:

content_by_lua_file path/test.lua;

OpenResty will concatenate it with the -p directory specified when starting, in order to obtain the absolute path.

That concludes today’s answers to these questions. Feel free to leave any further questions in the comments, and I will continue to provide answers. I hope that through communication and Q&A, I can help you turn your learning into achievements. Feel free to share this article and let us exchange ideas and make progress together.