Gevent: advantages, disadvantages, and disadvantages

Source: Internet
Author: User
Tags mongodb client connection reset vps

Original Source: in the Milky Way

I don't want to spend a lot of time describing what gevent is. I think it's enough to make a summary on its official website:

"Gevent is a coroutine-based Python network library. It uses the high-level synchronization API provided by greenlet to encapsulate libevent event loops ."

Next, I will describe how to use gevent in an internal project in mixpanel. For this article, I also wrote a few small performance tests. (Whipped up, which is confusing here --)

Advantages

First, the most obvious feature of gevent is its amazing performance, especially when compared with traditional thread solutions.

At this point, when the load exceeds a certain degree, the performance of asynchronous I/O is much better than that of synchronous I/O based on independent threads. This is almost common sense.

At the same time, gevent provides interfaces that look very similar to traditional thread-based model programming, but what is hidden below is asynchronous I/O.

Even better, it makes everything transparent. (Here, you don't have to worry about how it is implemented, and gevent will automatically help you convert it)

You can continue to use these common Python modules, such as urllib2 to process HTTP requests, which will replace common blocked socket operations with gevent.

Of course, there are some issues that need attention. I will explain them later.

Next, it's time to witness the performance miracle.

See

Ignore other factors. gevent performance is about 4 times the thread solution (paste is compared in this test. Note: This is another python thread-Based Network Library)

In the thread solution, the number of errors increases linearly with the increase of the number of concurrent connections (these errors are time-out, and I can increase the time-out limit, but from the user's point of view, the long wait and failure are actually a mother's life ).

Gevent means that there are no errors until 10,000 concurrent connections, or at least 5,000 concurrent connections can be processed.

In both cases, the number of actually completed requests per second is very stable, at least until the gevent crashes before the 10,000 concurrent connection tests. This surprised me. I originally guessed that RPS (number of completed requests per second) will decrease with the increase in concurrency.

The thread model fails completely in the 10,000 concurrent connection test. I can make it work normally (for example, I should be able to do it with some resource optimization skills), but I did not spend too much effort on it because I did it purely out of fun.

If this kind of things can seduce you, we're hiring, you know. (That's right. I am mixing some advertisement in the content .)

Test Method

This is the Python code I used to test:

#! /Usr/bin/ENV Python

Import sys

Def serve_page (ENV, start_response ):
Paragraph = '''
Lorem ipsum dolor sit Amet,
Consectetur adipisicing elit,
Sed do eiusmod Tempor incididunt ut labore et
Dolore Magna aliqua. ut enim adminim veniam,
Quis nostrud exercitation ullamco laboris nisi ut aliquip
Ex EA commodo consequat.
DUIs aute irure dolor in reprehenderit in
Voluptate Velit esse cillum dolore EU fugiat nulla pariatur.
Deleteur Sint occaecat cupidatat non proident,
Sunt in culpa qui officia deserunt mollit anim id est laborum.
'''
Page = '''
\ <HTML \>
\ <Head \>
\ <Title \> Static Page \ </Title \>
\ </Head \>
\ <Body \>
\
<H1 \> static content \ </H1 \>
% S
\ </Body \>
\ </Html \>
''' % (Paragraph * 10 ,)

Start_response ('2017 OK ', [('content-type', 'text/html')])
Return [Page]

If _ name _ = '_ main __':
Def usage ():
Print 'usage: ', SYS. argv [0], 'gevent | threaded concurrency'
SYS. Exit (1)

If Len (SYS. argv )! = 3
Or SYS. argv [1] Not in ['gevent', 'threaded']:
Usage ()

Try:
Concurrency = int (SYS. argv [2])
Failed t valueerror:
Usage ()

If SYS. argv [1] = 'gevent ':
From gevent import wsgi
Wsgi. wsgiserver (
('1970. 0.0.1 ', 127 ),
Serve_page,
Log = none,
Spawn = concurrency
). Serve_forever ()
Else:
From paste import httpserver
Httpserver. Serve (
Serve_page,
Host = '2017. 0.0.1 ',
Port = '000000 ',
Use_threadpool = true,
Threadpool_workers = concurrency
)

On the client side, I use Apache keystore with the following parameters:

  • -C num: The num here is the number of concurrent connections. In each test, this number matches the number used in the server command line. (Note: This refers to the second parameter that needs to be provided when the script is running)

  • -N 100000: 100,000 requests are required for all tests. In the preceding figure, the error rate is not counted, but the number of failed requests in the actual 100,000 request.

  • -R: if the request fails, retry automatically.

All tests, including servers and clients, run on a VPs with a low configuration and only MB of memory.

I initially thought I needed some methods to limit the thread solution to a CPU, but it turns out that even if the VPs is called a "quad-core", you only have to make one core to 100%. It's so cool.

Linux Optimization in Load Testing

  • When Linux processes more than 500 connections per second, I encountered a lot of problems.
    Basically, these problems occur because all connections are from one IP address to another (127.0.0.1 <-> 127.0.0.1 ).
    In other words, you may not encounter these problems in the production environment, but it is almost certain that these problems will certainly appear in the test environment (unless you run a one-way proxy on the backend ).

  • Increase client port range

    Echo-e '1970 \ t65535' | sudo tee/proc/sys/NET/IPv4/ip_local_port_range

    This step will enable more available ports for the client connection. Without this, you will soon use up all ports (and the connection will be in the time_wait State ).

  • Enable time_wait Reuse

    Echo 1 | sudo tee/proc/sys/NET/IPv4/tcp_tw_recycle

    This will also optimize the connections staying at time_wait. Of course, this optimization will take effect only when the number of connections containing the same IP address exceeds a certain number per second. At the same time, another parameter called tcp_tw_reuse can also play the same role, but I don't need to use it.

  • Disable synchronization tags

    Echo 1 | sudo tee/proc/sys/NET/IPv4/tcp_syncookies

    When you see "Possible SYN Flooding on port 10001. Sending cookies.", you may need to disable the synchronization tag (tcp_syncookies ). Do not do this on the server in your production environment. This will lead to Connection Reset, but it is still okay to test.

  • If Connection Tracing is used, disable iptables.

    You will soon fill your netfiler table. Of course, you can try to increase the value in/proc/sys/NET/Netfilter/nf_conntrack_max, but I think it is better to disable the firewall during testing.

  • Improve file descriptor restrictions

    At least on Ubuntu, the maximum number of file descriptors for each common user is 4096 by default. So, if you want to test more than 4000 concurrent connections, you need to increase this value. The simplest way is to add a line similar to "* hard nofile 16384" in/etc/security/limits. conf before testing, and then run the ulimit-N 16384 shell command.

Disadvantages

Of course all things won't be so good, right? Yes. In fact, if you have more complete documents, many gevent problems will be solved better. (The translator has no resistance to such sentences. Let's take a look at the sentence)

Document

In short, this product is generally the same. I probably read more gevent source code than the document (this is useful !). In fact, the best document is the sample code under the source code directory. If you have any problems, take a serious look at them first. At the same time, I spent a lot of time using Google to search for the email list.

Compatibility

I would like to mention eventlet here. In retrospect, this is justified, and it will lead to some incredible faults. We use some eventlet on the MongoDB client (Translator's note: a high-performance document-type database) code. When I use gevent, it cannot run on the server at all.

Er, the order of use is incorrect.

Start the listening process before you import gevent or at least before you call monkey. path_all. I don't know why, but this is what I learned from the mail list. Another point is that gevent modifies the python internal socket implementation. When you start a listening process, all opened file descriptors will be closed, so in the child process, the socket will be re-created in the form of unmodified, of course, this causes an exception. Gevent must handle such exceptions, or provide at least one compatible daemon function.

Monkey pathing?

When you execute monkey. path_all (), many operations will be patched and modified. I am not very good at this, but this allows the normal Python module to continue running well. It is strange that not all of these things are patched with this patch. I have been aiming for a long time to find out that the gross signals module cannot run until I find it is a problem with gevent. Signal. If you want to patch the function, isn't all Mao's?

This problem also applies to gevent. queue and the standard Python queue module. In short, when you need to use gevent-specific APIs to replace standard modules, classes, and functions, it needs to be clearer (just like a simple list ).

Poor places

Gevent cannot support multiple processes. This is a more painful deployment problem than other problems, which means that if you want to use multiple cores completely, you need to run multiple listening processes on multiple ports. Then, you may need to run something similar to nginx to distribute requests in these service listening processes (If your service needs to process HTTP requests ).

To be honest, the lack of multi-process capabilities means that you need to add more things to the server to make it available. (Note: Isn't it an extra layer of nginx or ha)

This is a big problem in using the gevent client for load testing. I finally implemented a client that uses multi-process loads with shared memory to count and print the status. This requires more work. (If someone needs to do the same thing, contact me and I will give you this client script program)

Last

If you have seen this, you will find that I have used two chapters to describe the shortcomings of gevent. Don't be blinded by these things. I believe that gevent is a great solution for python network programming. It is true that it has a variety of problems, but most of the problems are only the lack of documents, so it takes more time to survive.

We are using gevent internally. In fact, our services are so efficient that we can easily use up bandwidth resources before the use of computing resources (including CPU and memory) on the type of VPs we use.

# This is a translation article. For the original article, see http://code.mixpanel.com/gevent-the-good-the-bad-the-ugly /.

# Due to the large number of English-Chinese comparisons in the original text, the original text is removed considering its suitability.

# In the Milky Way


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.