Linux系统IO模型总结Nginx编译安装与基础配置

Linux系统IO模型总结Nginx编译安装与基础配置

一、Linux系统IO模型

1、IO的概念

Linux世界里一切皆文件,socket、管道、终端等都是文件。Linux系统中的文件也可以理解成一串二进制流。在信息交换的过程中,收发这些二进制流的操作就是I/O操作(input and output),其中最为常见的就是磁盘IO和网络IO。

2、内核空间与用户空间

Linux系统将内存空间分为内核空间与用户空间两部分。内核空间中存放的是内核代码和数据,可以执行特权指令,对外提供服务接口,例如访问硬件。用户空间中存放的是用户程序的代码和数据,只能执行非特权指令。

所有的系统资源管理都在内核空间中完成,比如读写磁盘文件,从网络接口读写数据等等。用户的应用程序是无法直接进行这样的操作的,只能通过内核提供的接口来完成这样的任务。

4、系统IO模型

以用户程序读取数据为例理解系统IO模型。由于用户没有权限直接访问磁盘设备,只能通过内核来实现。当内核从磁盘读取到用户所需的数据后,受内核空间与用户空间严格隔离的限制,需要将内核空间中的内存数据copy到用户空间的进程内存当中。所以简单来说,一次I/O就是内核从磁盘中将数据读取到内核空间,然后再将内核空间中的内存数据复制到用户空间中进程的内存当中的整个过程。系统IO有四种模型:同步、异步、阻塞、非阻塞。

  • 同步/异步

    关注的是事件处理的消息通信机制,即在等待一件事情的处理结果时,被调用者是否提供完成通知。同步:synchronous,用户进程发出请求调用后,内核不提供通知机制,即文件IO处理完成后不通知用户进程,需要用户进程自己去问内核是否处理完成。异步:asynchronous,用户进程发出请求调用后,内核会在调用处理完成后返回调用结果给用户进程,Nginx是异步的。

  • 阻塞/非阻塞

    关注调用者在等待结果返回之前所处的状态。阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成,最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。

以我去吃饭为例:我点了10个包子

  • 同步与异步:

    我点包子之后厨师是否告诉我:

    • 同步:厨师做好包子后会放到指定位置,但是做好包子之前需要自己一次次去看包子做好没有,厨师不会在包子做

    好之后通知我。

    • 异步:厨师做好包子后告诉我包子做好放哪了。
  • 阻塞与非阻塞::

    我点包子后的状态:

    • 阻塞:在厨师做包子期间一直在包子盘子前面等着,不能干别的事情。

    • 非阻塞:点完包子就可以去干别的事情,比如去逛逛街或者买买买。
  • IO模型组合:

    • 同步阻塞:我点完包子后不能去做别的事情,而且不知道包子有没有做好,需要自己一直等着并一次次的问厨师做好

    没有。

    • 同步非阻塞:点完包子后可以去做别的事情,但是不能长时间做别的事情,因为我还是不知道包子有没有做好,也要

    自己一直等着并一次次的问厨师做好没有,只能抽空做点别的。

    • 异步阻塞:我点完包子后不能去走做别的事情,但是厨师在做好包子后会告诉我,也就是我不用再一次次为厨师包子

    有没有做好了。

    • 异步非阻塞:我点完包子后可以做别的事情,而且可以一直在做别的去事情,因为厨师在做好包子后会告诉我。

5、Unix系统中五种网络IO模型与Apache三种工作模式

UNIX系统中有五种网络IO模型:

  • 同步阻塞型IO模型(blocking IO):阻塞IO模型是最简单的IO模型,用户线程在内核进行IO操作时被阻塞。
  • 同步非阻塞型I/O模型(nonblocking IO):应用进程向内核发送请IO求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核IO是否完成。
  • IO多路复用型(IO multiplexing):系统内核缓冲I/O数据,并让单个进程可以监视多个文件描述符,一旦某个描述符就绪,能够通知程序进行相应的读写操作。
    • 在Linux操作系统中,将一切都抽象为了文件,那么对于系统内的多种文件,应用程序怎么对应上呢?文件描述符(File descriptor,简称fd)应运而生。当应用程序请求内核打开/新建一个文件时,内核会返回一个文件描述符用于对应这个打开/新建的文件。
    • select,poll,epoll是IO多路复用模型在Linux系统中的功能实现。select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,并且读写过程是阻塞的。
    • Apache prefork模式是主进程+多进程/单线程+select模式;Apache work模式是主进程+多进程/多线程+poll模式。
  • 信号驱动式IO(signal-driven IO):用户进程可以通过sigaction系统调用注册一个信号处理程序,然后进程可以继续向下执行,当有IO操作准备就绪时,由内核通知触发一个SIGIO信号处理程序执行,然后将用户进程所需要的数据从内核空间拷贝到用户空间。
    • Apache event模式是主进程+多进程/多线程+信号驱动模式。
  • 异步(非阻塞) IO(asynchronous IO):用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情,等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知,异步非阻塞IO的两个阶段,进程都是非阻塞的。

二、Nginx基础

1、Ubuntu 18.04.5系统优化

# vim /etc/security/limits.conf   #在文件后补追加
#root账户的资源软限制和硬限制
root soft core unlimited
root hard core unlimited
root soft nproc 1000000
root hard nproc 1000000
root soft nofile 1000000
root hard nofile 1000000
root soft memlock 32000
root hard memlock 32000
root soft msgqueue 8192000
root hard msgqueue 8192000
#其他账户的资源软限制和硬限制
* soft core unlimited
* hard core unlimited
* soft nproc 1000000
* hard nproc 1000000
* soft nofile 1000000
* hard nofile 1000000
* soft memlock 32000
* hard memlock 32000
* soft msgqueue 8192000
# vim /etc/sysctl.conf      #在文件后补追加
# Controls source route verification
net.ipv4.conf.default.rp_filter = 1
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.ip_forward = 1

# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename.
# Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1

# Disable netfilter on bridges.
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0

# Controls the default maxmimum size of a mesage queue
kernel.msgmnb = 65536

# # Controls the maximum size of a message, in bytes
kernel.msgmax = 65536

# Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736

# # Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296

# TCP kernel paramater
net.ipv4.tcp_mem = 786432 1048576 1572864
net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 16384 4194304
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1

# socket buffer
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 20480
net.core.optmem_max = 81920

# TCP conn net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_syn_retries = 3
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15

# tcp conn reuse
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_max_tw_buckets = 20000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syncookies = 1

# keepalive conn
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.ip_local_port_range = 10001 65000

# swap
vm.overcommit_memory = 0
vm.swappiness = 10

#net.ipv4.conf.eth1.rp_filter = 0
#net.ipv4.conf.lo.arp_ignore = 1
#net.ipv4.conf.lo.arp_announce = 2
#net.ipv4.conf.all.arp_ignore = 1
#net.ipv4.conf.all.arp_announce = 2

# reboot

2、Nginx编译安装

2.1 操作系统软件版本信息

​ 4.15.0-112-generic #113-Ubuntu SMP Thu Jul 9 23:41:39 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

2.2 获取nginx源码

​ 官方网站:http://nginx.org/ ,页面右侧有下载入口。

image-20201118205917571

image-20201118210054867

2.3 编译安装环境准备
  • 创建nginx账户
# groupadd -g 2020 nginx
# useradd -u 2020 -g 2020 -r -s /bin/bash nginx
  • nginx目录权限设置
# mkdir -p /app/nginx
# chown -R nginx:nginx /app
  • 编辑定义安装参数
# mkdir  /app
# tar xvf nginx-1.18.0.tar.gz
# cd nginx-1.18.0
# ./configure --help

  --help                             print this message

  --prefix=PATH                      set installation prefix
  --sbin-path=PATH                   set nginx binary pathname
  --modules-path=PATH                set modules path
  --conf-path=PATH                   set nginx.conf pathname
  --error-log-path=PATH              set error log pathname
  --pid-path=PATH                    set nginx.pid pathname
  --lock-path=PATH                   set nginx.lock pathname

  --user=USER                        set non-privileged user for
                                     worker processes
  --group=GROUP                      set non-privileged group for
                                     worker processes

  --build=NAME                       set build name
  --builddir=DIR                     set build directory

  --with-select_module               enable select module
  --without-select_module            disable select module
  --with-poll_module                 enable poll module
  --without-poll_module              disable poll module

  --with-threads                     enable thread pool support

  --with-file-aio                    enable file AIO support

  --with-http_ssl_module             enable ngx_http_ssl_module
  --with-http_v2_module              enable ngx_http_v2_module
  --with-http_realip_module          enable ngx_http_realip_module
  --with-http_addition_module        enable ngx_http_addition_module
  --with-http_xslt_module            enable ngx_http_xslt_module
  --with-http_xslt_module=dynamic    enable dynamic ngx_http_xslt_module
  --with-http_image_filter_module    enable ngx_http_image_filter_module
  --with-http_image_filter_module=dynamic
                                     enable dynamic ngx_http_image_filter_module
  --with-http_geoip_module           enable ngx_http_geoip_module
  --with-http_geoip_module=dynamic   enable dynamic ngx_http_geoip_module
  --with-http_sub_module             enable ngx_http_sub_module
  --with-http_dav_module             enable ngx_http_dav_module
  --with-http_flv_module             enable ngx_http_flv_module
  --with-http_mp4_module             enable ngx_http_mp4_module
  --with-http_gunzip_module          enable ngx_http_gunzip_module
  --with-http_gzip_static_module     enable ngx_http_gzip_static_module
  --with-http_auth_request_module    enable ngx_http_auth_request_module
  --with-http_random_index_module    enable ngx_http_random_index_module
  --with-http_secure_link_module     enable ngx_http_secure_link_module
  --with-http_degradation_module     enable ngx_http_degradation_module
  --with-http_slice_module           enable ngx_http_slice_module
  --with-http_stub_status_module     enable ngx_http_stub_status_module

  --without-http_charset_module      disable ngx_http_charset_module
  --without-http_gzip_module         disable ngx_http_gzip_module
  --without-http_ssi_module          disable ngx_http_ssi_module
  --without-http_userid_module       disable ngx_http_userid_module
  --without-http_access_module       disable ngx_http_access_module
  --without-http_auth_basic_module   disable ngx_http_auth_basic_module
  --without-http_mirror_module       disable ngx_http_mirror_module
  --without-http_autoindex_module    disable ngx_http_autoindex_module
  --without-http_geo_module          disable ngx_http_geo_module
  --without-http_map_module          disable ngx_http_map_module
  --without-http_split_clients_module disable ngx_http_split_clients_module
  --without-http_referer_module      disable ngx_http_referer_module
  --without-http_rewrite_module      disable ngx_http_rewrite_module
  --without-http_proxy_module        disable ngx_http_proxy_module
  --without-http_fastcgi_module      disable ngx_http_fastcgi_module
  --without-http_uwsgi_module        disable ngx_http_uwsgi_module
  --without-http_scgi_module         disable ngx_http_scgi_module
  --without-http_grpc_module         disable ngx_http_grpc_module
  --without-http_memcached_module    disable ngx_http_memcached_module
  --without-http_limit_conn_module   disable ngx_http_limit_conn_module
  --without-http_limit_req_module    disable ngx_http_limit_req_module
  --without-http_empty_gif_module    disable ngx_http_empty_gif_module
  --without-http_browser_module      disable ngx_http_browser_module
  --without-http_upstream_hash_module
                                     disable ngx_http_upstream_hash_module
  --without-http_upstream_ip_hash_module
                                     disable ngx_http_upstream_ip_hash_module
  --without-http_upstream_least_conn_module
                                     disable ngx_http_upstream_least_conn_module
  --without-http_upstream_random_module
                                     disable ngx_http_upstream_random_module
  --without-http_upstream_keepalive_module
                                     disable ngx_http_upstream_keepalive_module
  --without-http_upstream_zone_module
                                     disable ngx_http_upstream_zone_module

  --with-http_perl_module            enable ngx_http_perl_module
  --with-http_perl_module=dynamic    enable dynamic ngx_http_perl_module
  --with-perl_modules_path=PATH      set Perl modules path
  --with-perl=PATH                   set perl binary pathname

  --http-log-path=PATH               set http access log pathname
  --http-client-body-temp-path=PATH  set path to store
                                     http client request body temporary files
  --http-proxy-temp-path=PATH        set path to store
                                     http proxy temporary files
  --http-fastcgi-temp-path=PATH      set path to store
                                     http fastcgi temporary files
  --http-uwsgi-temp-path=PATH        set path to store
                                     http uwsgi temporary files
  --http-scgi-temp-path=PATH         set path to store
                                     http scgi temporary files

  --without-http                     disable HTTP server
  --without-http-cache               disable HTTP cache

  --with-mail                        enable POP3/IMAP4/SMTP proxy module
  --with-mail=dynamic                enable dynamic POP3/IMAP4/SMTP proxy module
  --with-mail_ssl_module             enable ngx_mail_ssl_module
  --without-mail_pop3_module         disable ngx_mail_pop3_module
  --without-mail_imap_module         disable ngx_mail_imap_module
  --without-mail_smtp_module         disable ngx_mail_smtp_module

  --with-stream                      enable TCP/UDP proxy module
  --with-stream=dynamic              enable dynamic TCP/UDP proxy module
  --with-stream_ssl_module           enable ngx_stream_ssl_module
  --with-stream_realip_module        enable ngx_stream_realip_module
  --with-stream_geoip_module         enable ngx_stream_geoip_module
  --with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module
  --with-stream_ssl_preread_module   enable ngx_stream_ssl_preread_module
  --without-stream_limit_conn_module disable ngx_stream_limit_conn_module
  --without-stream_access_module     disable ngx_stream_access_module
  --without-stream_geo_module        disable ngx_stream_geo_module
  --without-stream_map_module        disable ngx_stream_map_module
  --without-stream_split_clients_module
                                     disable ngx_stream_split_clients_module
  --without-stream_return_module     disable ngx_stream_return_module
  --without-stream_upstream_hash_module
                                     disable ngx_stream_upstream_hash_module
  --without-stream_upstream_least_conn_module
                                     disable ngx_stream_upstream_least_conn_module
  --without-stream_upstream_random_module
                                     disable ngx_stream_upstream_random_module
  --without-stream_upstream_zone_module
                                     disable ngx_stream_upstream_zone_module

  --with-google_perftools_module     enable ngx_google_perftools_module
  --with-cpp_test_module             enable ngx_cpp_test_module

  --add-module=PATH                  enable external module
  --add-dynamic-module=PATH          enable dynamic external module

  --with-compat                      dynamic modules compatibility

  --with-cc=PATH                     set C compiler pathname
  --with-cpp=PATH                    set C preprocessor pathname
  --with-cc-opt=OPTIONS              set additional C compiler options
  --with-ld-opt=OPTIONS              set additional linker options
  --with-cpu-opt=CPU                 build for the specified CPU, valid values:
                                     pentium, pentiumpro, pentium3, pentium4,
                                     athlon, opteron, sparc32, sparc64, ppc64

  --without-pcre                     disable PCRE library usage
  --with-pcre                        force PCRE library usage
  --with-pcre=DIR                    set path to PCRE library sources
  --with-pcre-opt=OPTIONS            set additional build options for PCRE
  --with-pcre-jit                    build PCRE with JIT compilation support

  --with-zlib=DIR                    set path to zlib library sources
  --with-zlib-opt=OPTIONS            set additional build options for zlib
  --with-zlib-asm=CPU                use zlib assembler sources optimized
                                     for the specified CPU, valid values:
                                     pentium, pentiumpro

  --with-libatomic                   force libatomic_ops library usage
  --with-libatomic=DIR               set path to libatomic_ops library sources

  --with-openssl=DIR                 set path to OpenSSL library sources
  --with-openssl-opt=OPTIONS         set additional build options for OpenSSL

  --with-debug                       enable debug logging

可以通过官网文档查阅nginx模块的功能描述

image-20201118211423656

image-20201118211504074

  • 编译安装软件环境准备

    • 升级apt-get # apt update
    • 安装gcc # apt install -y gcc
    • 安装C++依赖库 # apt install build-essential # apt install libtool
    • 安装pcre依赖库 # apt install libpcre3 libpcre3-dev
    • 安装zlib依赖库 # apt install zlib1g-dev
    • 安装ssl依赖库 #apt install libssl-dev
  • 确定自定义安装参数

    官方网站上http://nginx.org/en/docs/configure.html,查看定制参数含义,最终安装选项参数:

    $ sudo ./configure --prefix=/app/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module

2.4 开始编译安装
  • configure

    #  ./configure --prefix=/app/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module
    
  • make

    # make
  • make install

    # make install
  • 编译安装后启动nginx

    # /app/nginx/sbin/nginx
  • 访问编译安装的nginx web界面:

    image-20201118230138056

3、Nginx常用配置与优化

3.1 在环境参数中增加nginx路径
root@dl-homework:~# pwd
/root
root@dl-homework:~# ll
total 64
drwx------  5 root root  4096 Nov 19 10:03 ./
drwxr-xr-x 24 root root  4096 Nov 18 21:05 ../
-rw-------  1 root root 10257 Nov 19 09:46 .bash_history
-rw-r--r--  1 root root  3140 Nov 19 09:44 .bashrc
drwx------  2 root root  4096 Nov 14 11:28 .cache/
drwx------  3 root root  4096 Nov 14 11:28 .gnupg/
-rw-r--r--  1 root root   148 Aug 17  2015 .profile
drwxr-xr-x  2 root root  4096 Nov 14 11:55 .vim/
-rw-------  1 root root 12836 Nov 19 09:45 .viminfo
-rw-r--r--  1 root root    17 Nov 19 09:45 .vimrc
-rw-------  1 root root   134 Nov 19 10:03 .Xauthority
root@dl-homework:~# vim .bashrc

100 export PATH=$PATH:/app/nginx/sbin   #在文件最后一行添加

# . .bashrc
3.2 利用启动脚本实现自启动nginx服务
# cd /lib/systemd/system
# vim nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking   
PIDFile=/run/nginx.pid   #要与nginx.conf里面的配置保持一致
ExecStart=/app/nginx/sbin/nginx -c /app/nginx/conf/nginx.conf  #更改为nginx的实际路径
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

# systemctl daemon-reload

# systemctl start nginx.service
## systemctl enable nginx.service
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /lib/systemd/system/nginx.service.
3.3 Nginx基础配置

所有参数均可在nginx.com网站中documentation中查到说明,nginx.conf默认参数:

# cd /app/nginx/conf
# grep -v "#"  nginx.conf |grep -v "^$"
worker_processes  1;
pid        /run/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
# vim /app/nginx/conf/nginx.conf

 worker_processes  auto;       #进程数量
 worker_cpu_affinity  auto;    #进程与CPU绑定

 pid        /run/nginx.pid;    #文件位置要与nginx.service里的配置保持一致

 worker_rlimit_nofile   65535;   #允许一个工作进程打开的文件数

 events {
      worker_connections  102400;  #单个进程最大并发连接数
      accept_mutex on;   #避免群惊
      multi_accept on;   #允许接受多个新连接
  }

  http {
    include       mime.types;   #支持的文件类型
    default_type  application/octet-stream;  #无法识别就下载文件

     sendfile        on;  #实现文件零拷贝MMAP
     tcp_nopush      on;  #合并请求后统一发送给客户端,降低服务器端负载,配合sendfile使用
     gzip  on;  #开启文件压缩
     keepalive_timeout  65;  #长连接时间65秒
     server {
        listen       80;
        server_name  localhost;
        charset utf-8;   #更改中文字符集
        location / {
            root   html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

  }

# nginx -t
nginx: the configuration file /app/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /app/nginx/conf/nginx.conf test is successful
# systemctl reload nginx.service
3.4 创建PC站点与Mobile站点
# mkdir /app/nginx/conf/conf.d
# vim /app/nginx/conf/conf.d/pc.conf
server {
    listen 80;
    server_name pc.home.net;

    location / {
        root /app/nginx/html/pc;
        }
    }

# vim /app/nginx/conf/conf.d/mobile.conf 
server {
    listen 80;
    server_name mobile.home.net;

    location / {
        root /app/nginx/html/mobile;
        }
    }

# mkdir /app/nginx/html/{pc,mobile}
# echo "mobile web" > /app/nginx/html/mobile/index.html
# echo "pc web" > /app/nginx/html/pc/index.html

# nginx -t
nginx: the configuration file /app/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /app/nginx/conf/nginx.conf test is successful

# systemctl reload nginx.service

修改windows系统下C:\Windows\System32\drivers\etc\hosts文件,增加172.20.200.138 pc.home.net mobile.home.net,访问站点:

image-20201119194403714

image-20201119194444533

猜你喜欢

转载自blog.51cto.com/12302225/2552422