PHP programmers - common tools

Keywords: PHP Redis socket zlib

Three links

There are often students in the community who ask, "is my PHP program blocked, is my PHP program open (not confident about the code I wrote), and is my PHP program problematic?" then they post their own programs, and enter the happy irrigation link. As time goes on, we have not formed a systematic solution. It is better to ask people than ourselves. We Solve these problems by yourself

Methodology

Recently I came into contact with the term methodology of ox
A term explanation of Baidu Encyclopedia is quoted

Methodology is the theory about people's methods of understanding and transforming the world.
It is how people observe things and deal with problems. Generally speaking, the world view mainly solves the problem of "what is the world", and the methodology mainly solves the problem of "how to do".
Methodology is a theoretical system or system aiming at solving problems, which usually involves the discussion of problem stages, tasks, tools and techniques. Methodology will analyze and study a series of specific methods, systematically summarize and finally put forward more general principles.
Methodology is also a philosophical concept. People's basic view about "what and how the world is" is the world outlook. Using this view as a guide to understand and transform the world has become a methodology Methodology is the sum of categories, principles, theories, methods and means that are generally applicable to specific social sciences and play a guiding role. The concept of methodology is often mentioned in the works of historical materialism.

We PHP programmers can also have a way to solve some basic problems that are easy to encounter. With this platform, I hope you can give me more advice
Or to quote a proposition of ox X, who am I, where do I come from and where do I go? Let's ask three questions

  • Who am I?
  • What am I going to do?
  • How are you doing?

Who am I?

This is a problem that has been explored by countless people for thousands of years

PHP is an interpretive language. First of all, let's see where and what PHP we are executing is, so as not to find out whether it's on the right number after a sudden operation on a strange machine. For example, there are many versions of PHP installed on my machine. Don't laugh at this problem. There are many people who have been working for several years and ignored this problem. Until one day, he waves on it It took two hours (escape)

1 $ which php
2 /home/shiguangqi/bin/php
3 $ ll /home/shiguangqi/bin/php
4 lrwxrwxrwx 1 shiguangqi shiguangqi 30 10 Month 2512:09 /home/shiguangqi/bin/php -> /usr/local/php-7.2.14//bin/php*

 

There are a series of problems, such as the version of PHP installation, the configuration file loaded, the compilation parameters of PHP, whether the extension you are concerned about is loaded, and the configuration version loaded
For example, I want to connect different versions of PHP to one of my own directories and freely switch between different versions

1 $ php -v
2 PHP 7.2.14 (cli) (built: Jul 4 2019 11:02:01) ( NTS DEBUG )
3 Copyright (c) 1997-2018 The PHP Group
4 Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

 

What configuration to load

1 $ php --ini
2 Configuration File (php.ini) Path: /usr/local/php-7.2.14/lib
3 Loaded Configuration File: /usr/local/php-7.2.14/lib/php.ini
4 Scan for additional .ini files in: (none)
5 Additional .ini files parsed: (none)

 

Compile parameters. My version is debug. By default, these modules are compiled statically

1 $ php -i | grep configure
2 Configure Command => './configure' '--prefix=/usr/local/php-7.2.14' '--with-config-file-path=/usr/local/php-7.2.14/lib' '--with-mysqli=mysqlnd' '--with-jpeg-dir' '--with-png-dir' '--with-iconv-dir' '--with-freetype-dir' '--with-zlib' '--with-mhash' '--with-libxml-dir' '--with-curl' '--with-mcrypt' '--with-gd' '--with-openssl' '--enable-ftp' '--enable-xml' '--enable-bcmath' '--enable-gd-native-ttf' '--enable-mbregex' '--enable-mbstring' '--enable-pcntl' '--enable-sockets' '--enable-fpm' '--enable-soap' '--enable-zip' '--enable-debug'

 

See PHP extension, in fact, you can use php --help to see more usage
For example, we often use

php --ri swoole

 

What am I going to do?

Goal oriented

This part is most familiar to us, but we do it every day
Before designing a service, you should think about the blueprint in mind. You'd better spend 90% of your time thinking and 10% of your time writing. Not only do you make fewer mistakes, but also your quality is high
For example, I want to query redis and write two simplest codes

 1 <?php
 2 $redis = new Redis;
 3 $redis->connect("127.0.0.1", 6379);
 4 $var = $redis->get("key");
 5 var_dump($var);
 6 <?php
 7 Swoole\Runtime::enableCoroutine();
 8 go(function () {
 9 $redis = new Redis;
10 $redis->connect("127.0.0.1", 6379);
11 $var = $redis->get("key");
12 var_dump($var);
13 });

 

Then we got the same result happily

How are you doing?

Target oriented and result oriented

It's easy to get the result. The question is how about the quality of our work. The above examples are just analogies. Don't laugh at these two examples
strace will be our help
We can see the system call of the core business in this way

 1 strace -s 1000 php redis.php
 2 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
 3 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
 4 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
 5 connect(3, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
 6 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=3, revents=POLLOUT}])
 7 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 8 fcntl(3, F_SETFL, O_RDWR) = 0
 9 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
10 setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0
11 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout)
12 sendto(3, "*2\r\n$3\r\nGET\r\n$3\r\nkey\r\n", 22, MSG_DONTWAIT, NULL, 0) = 22
13 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout)
14 poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=3, revents=POLLIN}])
15 recvfrom(3, "$6\r\nvalue2\r\n", 8192, MSG_DONTWAIT, NULL, NULL) = 12
16 write(1, "string(6) \"", 11string(6) ") = 11
17 write(1, "value2", 6value2) = 6

 

We can also add some parameters to get more detailed data, time consumed by current system call and current timestamp

 1 $ strace -ttt -T -s 1000 php redis.php
 2 1572266793.054360 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3 <0.000013>
 3 1572266793.054389 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) <0.000007>
 4 1572266793.054414 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 <0.000008>
 5 1572266793.054438 connect(3, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) <0.000070>
 6 1572266793.054533 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=3, revents=POLLOUT}]) <0.000008>
 7 1572266793.054565 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 <0.000008>
 8 1572266793.054594 fcntl(3, F_SETFL, O_RDWR) = 0 <0.000006>
 9 1572266793.054619 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000008>
10 1572266793.054644 setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0 <0.000007>
11 1572266793.054689 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout) <0.000007>
12 1572266793.054717 sendto(3, "*2\r\n$3\r\nGET\r\n$3\r\nkey\r\n", 22, MSG_DONTWAIT, NULL, 0) = 22 <0.000030>
13 1572266793.054788 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=3, revents=POLLIN}]) <0.000007>
14 1572266793.054816 recvfrom(3, "$", 1, MSG_PEEK, NULL, NULL) = 1 <0.000009>
15 1572266793.054851 poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=3, revents=POLLIN}]) <0.000007>
16 1572266793.054878 recvfrom(3, "$6\r\nvalue2\r\n", 8192, MSG_DONTWAIT, NULL, NULL) = 12 <0.000009>
17 1572266793.054923 write(1, "string(6) \"", 11string(6) ") = 11 <0.000010>
18 1572266793.054951 write(1, "value2", 6value2) = 6 <0.000009>
19 1572266793.054977 write(1, "\"\n", 2"

 

We can check the details of the program system call line by line. It is easy to find that this program is blocked. Although the time of each system call is very short, it is not the case for another service and another dependency. But it can never be separated from its origin

Let's take a look at the second program, which is the system call after the process is started

 1 1572266985.463011 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 4 <0.000016>
 2 1572266985.463048 fcntl(4, F_GETFL) = 0x2 (flags O_RDWR) <0.000006>
 3 1572266985.463070 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 <0.000006>
 4 1572266985.463092 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000007>
 5 1572266985.463127 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000005>
 6 1572266985.463167 connect(4, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) <0.000076>
 7 1572266985.463296 epoll_ctl(3, EPOLL_CTL_ADD, 4, {EPOLLOUT, {u32=4, u64=38654705668}}) = 0 <0.000011>
 8 1572266985.463353 epoll_wait(3, [{EPOLLOUT, {u32=4, u64=38654705668}}], 4096, 60000) = 1 <0.000007>
 9 1572266985.463383 epoll_ctl(3, EPOLL_CTL_DEL, 4, NULL) = 0 <0.000008>
10 1572266985.463407 getsockopt(4, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 <0.000008>
11 1572266985.463445 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000007>
12 1572266985.463467 setsockopt(4, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0 <0.000007>
13 1572266985.463525 recvfrom(4, 0x7f29bb9b033d, 1, MSG_PEEK, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000008>
14 1572266985.463556 sendto(4, "*2\r\n$3\r\nGET\r\n$3\r\nkey\r\n", 22, 0, NULL, 0) = 22 <0.000033>
15 1572266985.463633 recvfrom(4, 0x7f29bb9b033d, 1, MSG_PEEK, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000006>
16 1572266985.463662 recvfrom(4, "$6\r\nvalue2\r\n", 8192, 0, NULL, NULL) = 12 <0.000007>
17 1572266985.463713 write(1, "string(6) \"", 11string(6) ") = 11 <0.000009>
18 1572266985.463740 write(1, "value2", 6value2) = 6 <0.000008>

 

It can be found that by creating a socket, then connect ing the operation, and then joining the monitoring through epoll · CTL, it is through multiplexing. There is no blocking waiting here. We can confirm our program details clearly in this way
For example, you can see from line 8 that the timeout waiting time here is 60s
Then we modify the code timeout to 0.5s

1 <?php
2 Swoole\Runtime::enableCoroutine();
3 go(function () {
4 $redis = new Redis;
5 $redis->connect("127.0.0.1", 6379, 0.5);
6 $var = $redis->get("key");
7 var_dump($var);
8 });

 

Then continue to view

 1 1572267648.851924 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 4 <0.000011>
 2 1572267648.851952 fcntl(4, F_GETFL) = 0x2 (flags O_RDWR) <0.000004>
 3 1572267648.851968 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 <0.000004>
 4 1572267648.851986 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000005>
 5 1572267648.852011 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000006>
 6 1572267648.852042 connect(4, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) <0.000058>
 7 1572267648.852131 epoll_ctl(3, EPOLL_CTL_ADD, 4, {EPOLLOUT, {u32=4, u64=38654705668}}) = 0 <0.000006>
 8 1572267648.852164 epoll_wait(3, [{EPOLLOUT, {u32=4, u64=38654705668}}], 4096, 500) = 1 <0.000006>
 9 1572267648.852184 epoll_ctl(3, EPOLL_CTL_DEL, 4, NULL) = 0 <0.000005>
10 1572267648.852201 getsockopt(4, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 <0.000006>
11 1572267648.852225 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000058>
12 1572267648.852302 setsockopt(4, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0 <0.000006>
13 1572267648.852350 recvfrom(4, 0x7f71f91b033d, 1, MSG_PEEK, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000006>
14 1572267648.852373 sendto(4, "*2\r\n$3\r\nGET\r\n$3\r\nkey\r\n", 22, 0, NULL, 0) = 22 <0.000029>
15 1572267648.852446 recvfrom(4, "$", 1, MSG_PEEK, NULL, NULL) = 1 <0.000011>
16 1572267648.852486 recvfrom(4, "$6\r\nvalue2\r\n", 8192, 0, NULL, NULL) = 12 <0.000006>
17 1572267648.852523 write(1, "string(6) \"", 11string(6) ") = 11 <0.000008>
18 1572267648.852543 write(1, "value2", 6value2) = 6 <0.000006>

 

Then on line 8, we can see that the timeout is 500ms, which can find some simple but very important details. Also, the timeout in the first example can be read

The running process can view the details through strace -p pid
More detailed usage of strace can be seen in man strace

sublimation

If our project is very complex, how to locate our own run-time problems, too long blocking waiting time, dead cycle and other problems. In fact, we can use strace tool to view the load of the system and the resources occupied by the process by combining with top. The common ones are memory and CPU
vmstat is also a very good tool
Of course, there are also fully automatic tools, such as swoole tracker, which can fully check the blocking and even memory leakage. Of course, you can also write your own script to achieve this

The common tools are gdb. In the next article, we will experiment with the great effect of gdb on PHP programmers

Posted by blade_922 on Mon, 18 Nov 2019 22:53:22 -0800