转载

部署LAMP动静分离以及部署Discuz论坛

通过LAMP平台部署及应用 已经可以部署出LAMP平台,来面对客户端的请求,但是由于这些组件都是在一台服务器上进行安装,如果出现问题,将导致LAMP平台的瘫痪。在实际环境中,不可能将LAMP平台都部署在同一台服务器上,这就需要使用到LAMP动静分离的技术。

博文大纲:

一、LAMP动静分离的相关概念

1.PHP的工作模式

2.FastCGI模式的工作机制

二、实现LAMP动静分离

1.FastCGI方式编译安装php

2.搭建Apache并配置通过fastcgi协议调用php

  1. 搭建Mysql数据库

    4.ab压力测试工具

    5.安装php加速软件Xcache

    三、部署Discuz论坛

一、LAMP动静分离的相关概念

要想实现LAMP动静分离,最主要的还是PHP,因为我们需要使用PHP解释器来解析动态页面,然后向Web服务器传输解析后的网站内容。我们下面重点介绍一下PHP。

1.PHP的工作模式

PHP在在LAMP环境下共有三种工作模式:

  • CGI模式: 在这种模式下运行PHP,性能不是很好;
  • apache模块: 在这种模式下运行PHP,在LAMP平台部署及应用 就是使用的这种模式,使用apache调用php完成工作;
  • FastCGI模式: 在这种模式下运行PHP,PHP就是一处独立的进程,所有的PHP子进程都由PHP的一个叫做php-fpm的组件负责管理;

2.FastCGI模式的工作机制

首选客户端发起请求,请求一般分为两种:一种是静态请求,可以直接由Apache响应直接返回客户端所需资源;另一种动态请求,其中包含PHP或Perl这种脚本解释型语言,则由Apache服务器通过fastcgi协议调用php服务器执行并返回给Apache,由Apache向客户端返回客户端所需资源,如果这个过程中涉及到对数据的操作,此时php服务器还会通过mysql协议调用mysql服务器。如图:

部署LAMP动静分离以及部署Discuz论坛

二、实现LAMP动静分离

案例所需:

  • 一台httpd服务器(192.168.1.1)编译安装httpd服务;
  • 一台mysql服务器(192.168.1.2)编译安装mysql服务;
  • 一台php服务器(192.168.1.3)编译安装php服务;

1.FastCGI方式编译安装php

获取 PHP所需软件包

1)解决依赖关系

[root@localhost ~]#  yum -y install libxml2-devel lzip2-devel libcurl-devel /
libmcrypt-devel openssl-devel bzip2-devel 
//安装PHP程序所需要的依赖包
[root@localhost ~]# tar zxf libmcrypt-2.5.7.tar.gz -C /usr/src
[root@localhost ~]# cd /usr/src/libmcrypt-2.5.7/
[root@localhost libmcrypt-2.5.7]#  ./configure --prefix=/usr/local/libmcrypt && make && make install 
//编译安装 libmcrypt 软件包

2)编译安装php

[root@localhost ~]# tar zxf php-5.6.27.tar.gz -C /usr/src
[root@localhost ~]# cd /usr/src/php-5.6.27/
[root@localhost php-5.6.27]#  ./configure --prefix=/usr/local/php5.6 --with-mysql=mysqlnd /
--with-pdo-mysql=mysqlnd --with-mysqli=mysqlnd --with-openssl --enable-fpm --enable-sockets /
--enable-sysvshm --enable-mbstring --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib /
--with-libxml-dir=/usr --enable-xml --with-mhash --with-mcrypt=/usr/local/libmcrypt  /
--with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d /
--with-bz2 --enable-maintainer-zts && make && make install

配置选项相关解释:

  • --prefix=/usr/local/php5.6 //指定安装位置;
  • --with-mysql=mysqlnd //安装连接mysql工具支持 mysql;
  • --with-pdo-mysql=mysqlnd //支持Mysql pdo 模块
  • --with-mysqli=mysqlnd //支持 mysqli 模块
    注意:上面的三选项的作用:数据库与 php 不在一个服务器上,指定此种方式,安装数据库 连接驱动;
  • --with-openssl //支持 openssl 模块;
  • --enable-fpm //支持 fpm 模式;
  • --enable-sockets //启用 socket 支持;
  • --enable-sysvshm //启用系统共享内存支持;
  • --enable-mbstring //多字节字串、像我们的中文就是多字节字串;
  • --with-freetype-dir //支持 freetype、就要装 freetype-devel、跟字体相关的、字体解析工具 --with-jpeg-dir --with-png-dir;
    注意:上面的二选项的作用:处理 jpeg、png 图片的、php 可以动态生成 jpeg 图片;
  • --with-zlib //是个压缩库、在互联网传输时用来压缩传输的;
  • --with-libxml-dir=/usr //这个 libxml 是用来解析 xml 的;
  • --enable-xml //支持 xml ;
  • --with-mhash //支持 mhash;
  • --with-mcrypt=/usr/local/libmcrypt //libmcrypt-devel 这个程序包所指定的;
  • --with-config-file-path=/etc //指定配置文件的存放路径;
  • --with-config-file-scan-dir=/etc/php.d //配置文件扫描路径;
  • --with-bz2 //支持 BZip2 为了支持 apache 的 worker 或 event 这两个 MPM,编译时使用了--enable-maintainer-zts 选项

如果使用 PHP5.3 以上版本,为了链接 MySQL 数据库,可以指定 mysqlnd,这样在本机就不需要先安装 MySQL 或 MySQL 开发包了。mysqlnd 从 php 5.3 开始可用,可以编译时绑定到它 (而不用和具体的 MySQL 客户端库绑定形成依赖),但从 PHP 5.4 开始它就是默认设置

3)提供php配置文件

[root@localhost ~]# cp /usr/src/php-5.6.27/php.ini-production /etc/php.ini
//复制源码包下的配置文件生成php的配置文件

4)创建php-fpm脚本

[root@localhost ~]# cp /usr/src/php-5.6.27/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
//复制源码包下的启动脚本
[root@localhost ~]# chmod +x /etc/init.d/php-fpm 
[root@localhost ~]# chkconfig --add php-fpm
//添加为系统服务,现在还不可以启动,因为还没生成php服务器的配置文件

5)提供 php-fpm配置并进行编辑

[root@localhost ~]# cd /usr/local/php5.6/etc/
[root@localhost etc]# cp php-fpm.conf.default php-fpm.conf
//原本安装完成的后配置文件不生效,所以需要改名(这是php-fpm的配置文件)
[root@localhost etc]# sed -i 's#;pid = run/php-fpm.pid#pid = run/php-fpm.pid#g' php-fpm.conf
//指定pid文件存放位置
[root@localhost etc]# sed -i 's/listen = 127.0.0.1:9000/listen = 0.0.0.0:9000/g' php-fpm.conf
//修改监听地址为全部监听
[root@localhost etc]# sed -i 's/pm.max_children = 5/pm.max_children = 50/g' php-fpm.conf
//修改最大启动的子进程数为50
[root@localhost etc]# sed -i 's/pm.start_servers = 2/pm.start_servers = 5/g' php-fpm.conf
//修改初始启动进程数为5
[root@localhost etc]# sed -i 's/pm.min_spare_servers = 1/pm.min_spare_servers = 5/g' php-fpm.conf
//修改最小空闲子进程数为5
[root@localhost etc]# sed -i 's/pm.max_spare_servers = 3/pm.max_spare_servers = 35/g' php-fpm.conf
//修改最大空闲子进程为35
[root@localhost ~]# systemctl start php-fpm       //启动php服务
[root@localhost ~]# netstat -anpt | grep 9000      //确定9000在监听
tcp        0      0 0.0.0.0:9000            0.0.0.0:*               LISTEN      45563/php-fpm: mast

如果防火墙是开启的状态,需要进行以下操作:

[root@localhost ~]#  firewall-cmd --permanent --add-port=9000/tcp 
[root@localhost ~]# firewall-cmd --reload 
//允许TCP9000访问,重载以立即生效
[root@localhost ~]# mkdir -p /var/www/benet
//在该主机上新键虚拟主机目录用于存放网页文件

2.搭建Apache并配置通过fastcgi协议调用php

参考安装Apache 进行安装Apache,这里就略过了,Apache安装完成之后,需要进行以下操作!

自从Apache 2.4以后已经专门有一个模块对FastCGI的实现,此模块为mod_proxy_fcgi.so,它其实是作为mod_proxy.so模块的扩充,因此以下两个模块需要被加载:

LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
LoadModule proxy_module modules/mod_proxy.so

操作如下:

[root@localhost ~]# vim /usr/local/http-2.4.23/conf/httpd.conf
//编辑httpd的主配置文件
……………………                 //省略部分内容
# LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so         
# LoadModule proxy_module modules/mod_proxy.so
//去除模块前面的“#”号,启用模块
#Include conf/extra/httpd-vhosts.conf         //去除“#”号,启用虚拟主机配置文件
定位到AddType:添加以下一行:
AddType  application/x-httpd-php .php
//让apache能识别php格式的页面
定位到以下内容:
<IfModule dir_module>
    DirectoryIndex index.php index.html         //在index.html前面添加index.php 
</IfModule>
[root@localhost ~]# vim /usr/local/http-2.4.23/conf/extra/httpd-vhosts.conf 
//编辑Apache的虚拟主机配置文件,修改为以下内容:
<VirtualHost *:80>
    ServerAdmin admin@admin.com
    DocumentRoot "/var/www/benet"
    ServerName www.benet.com
    ServerAlias www.benet.com
    ErrorLog "logs/benet-error_log"
    CustomLog "logs/benet-access_log" common
    ProxyRequests Off                                         //关闭正向代理
        ProxyPassMatch  ^/(.*/.php(/.*)?)$  fcgi://192.168.1.3:9000/var/www/benet/$1    
<Directory "/var/www/benet">        
 Options  FollowSymLinks          //禁止目录遍历  
 AllowOverride None        //允许请求为空
 Require all granted                 //允许所有客户端访问
</Directory>
</VirtualHost>
[root@localhost ~]# mkdir -p /var/www/benet
[root@localhost ~]# systemctl restart httpd
//创建虚拟目录之后,重启httpd服务
ProxyPassMatch  ^/(.*/.php(/.*)?)$  fcgi://192.168.1.3:9000/var/www/benet/$1                  
//把以.php 结尾的文件请求发送到 php-fpm 进程,php-fpm 至少需要知道运 行的目录和 URI,所以这里直接在 fcgi://192.168.1.3:9000 后指明了这两个参数,其它的参数的传递已经被 mod_proxy_fcgi.so 进行了封装,不需要手动指定。 特别注意的是,IP地址后面的目录路径需要与<VirtualHost> 中的 DocumentRoot 后的路径一致 。ProxyPassMatch 只有满足特定正则模式的内容才会匹配并执行此规则,这里的模式是,^/(.*/.php(/.*)?)$ 从网站(虚拟主机<VirtualHost> 的根目录开始,匹配任何以 .php 结尾,或者在 .php 之后 紧跟一个 / 再跟别的内容的路径。 ^ (caret) 和 $ (dollar)标志要匹配的路径的开始和结束 ( )括号里的内容可以用 $1 来表示,以方便后面引用它。 fcgi:// 192.168.1.3:9000 通过 mod_proxy_fcgi 来转发的代理,使用 fastCGI 协议,转到 PHP-FPM 监听的端口。 /path/to/your/documentroot/ 非常重要!必须与虚拟主机的路径匹配,且必须是对应 php 文件在操作系统中的绝对路径。 否则会找不到文件。 
$1 可以从原始请求扩展成整个请求路径的变量,这里指代前面( ) 里面匹配的那个路径(uri)

注意:Apache httpd 2.4 以前的版本中,要么把 PHP 作为 Apache 的模块运行,要么添加一个第 三方模块支持 PHP-FPM 实现。

在php服务器上创建测试网页:

[root@localhost ~]# cat /var/www/benet/index.php 
<?php 
phpinfo(); 
?>

访问效果如下:

部署LAMP动静分离以及部署Discuz论坛

安装这样页面,就表示Apache已经可以和php协同工作了

以上是利用Apache的虚拟主机来调用php-fpm进行工作,其实Apache本身就可以调用php-fpm,无需创建虚拟主机。

3. 搭建Mysql数据库

由于编译安装Mysql数据库需要很长的时间,本人提供 Mysql安装脚本及安装所需软件 一分钟安装完成(mysql数据库的账号root默认的密码是123)!

安装完成之后,进行以下操作:

[root@localhost ~]# mysql -u root -p123
mysql> grant all on *.* to 'lzj'@'192.168.1.%' identified by '123456';
//创建数据库用户并进行授权
mysql> exit

在php服务器填写测试脚本:

[root@localhost ~]# cat /var/www/benet/test.php 
<?php
$link=mysql_connect('192.168.1.2','lzj','123456');
if($link) echo "恭喜你,数据库连接成功!!!"; else echo "connect shibai";
mysql_close($link);
?>

访问进行测试:

部署LAMP动静分离以及部署Discuz论坛

看到这个页面就表示Apache、PHP、Mysql可以协同工作了!

4.ab压力测试工具

网络性能压力测试是服务器网站性能调优过程中必不可缺少的一环。只有当服务器处在高压的情况下,才能体现出软件、硬件等各种设置不当所暴露的问题。

性能测试工具比较常用的就是:ab、http_load、webbench、siege。本篇博文只介绍ab工具。

ab是Apache自带的压力测试工具。ab非常实用,它不仅可以对apache服务器进行网站访问压力测试,也可以对其他类型的服务器进行压力测试。比如:Nginx、Tomcat、IIS等。

(1)ab压力测试工具的原理

ab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问。它的测试目标是基于URL的,因此,它既可以测试Apache的负载压力,也可以测试Nginx、Tomcat、IIS等其他Web服务器的压力。

ab命令对发出负载的计算机要求很低,它既不会占用很高的CPU,也不会占用很多内存。但却会给目标服务器造成巨大的负载。进行测试时,需要格外注意,否则可能一次性测试太多的负载,可能造成目标服务器资源耗尽,严重导致死机。

(2)ab压力测试工具的安装

ab的安装非常简单,如果是源码包进行安装Apache的话,Apache安装完毕后,ab就存放在Apache安装目录的bin目录下;

如果是使用yum的方式安装Apache的话,ab命令默认存放在/usr/bin目录下;

注意:如果不想安装Apache又想使用ab命令的话,就需要使用yum的方式安装httpd-tools。

查看ab是否安装成功,可以进行以下测试:

部署LAMP动静分离以及部署Discuz论坛

这是由于安装openssl时指定的库位置出现错误。

如果出现上述情况,解决方法如下:

[root@localhost ~]# export  LD_LIBRARY_PATH=/usr/local/openssl/lib/               //将所需模块所在路径导出为环境变量
[root@localhost ~]# /usr/local/http-2.4.23/bin/ab -V                        //这样就可以正常使用
This is ApacheBench, Version 2.3 <$Revision: 1748469 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

(3)ab压力测试命令的参数

ab命令常用的参数有两个:

  • -n:在测试会话中所执行的请求个数(总请求数);
  • -c:一次产生的请求个数(即并发用户数);
[root@localhost ~]# cat /var/www/benet/index.html
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
//创建Apache的首页文件
[root@localhost ~]# ab -c 500 -n 10000 http://192.168.1.1/index.html
//对192.168.1.1的Web服务器进行测试
This is ApacheBench, Version 2.3 <$Revision: 1748469 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.1.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests

Server Software:        Apache/2.4.23
Server Hostname:        192.168.1.1
Server Port:            80

Document Path:          /index.html                  //请求的资源名称
Document Length:        34 bytes                  //响应数据的正文长度

Concurrency Level:      500                   //并发个数
Time taken for tests:   1.727 seconds       //处理这些请求所花费的时间
Complete requests:      10000               //成功请求完成的次数
Failed requests:        0                          //失败的请求次数
Total transferred:      2780000 bytes      //所有请求的响应数据长度总和
HTML transferred:       340000 bytes         //请求的正文数据总和
Requests per second:    5788.87 [#/sec] (mean)      //吞吐量-每秒请求数(计算公式:请求的次数/用户等待时间)吞吐量越大越好
Time per request:       86.373 [ms] (mean)        //用户平均等待时间(计算方式:用户等待时间/(请求的次数/并发))
Time per request:       0.173 [ms] (mean, across all concurrent requests)       //服务器平均等待时间(计算方式:用户等待时间/完成请求的次数)
Transfer rate:          1571.59 [Kbytes/sec] received   //用户请求的数据大小(计算方式:数据总长度/用户等待时间)

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   24 138.0      4    1034
Processing:     8   50  93.8     16     822
Waiting:        0   47  93.2     13     816
Total:         12   74 168.7     20    1255

Percentage of the requests served within a certain time (ms)
  50%     20
  66%     25
  75%     31
  80%     39
  90%    222
  95%    250
  98%    832
  99%   1050
 100%   1255 (longest request)
 //这部分数据用于描述每个请求处理时间的分布情况

(4)ab压力测试工具重要的性能指标

在进行性能测试过程中有几个指标比较重要:

1.吞吐量:服务器并发处理能力的量化描述。指的是在某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐量。

注意:吞吐量是基于并发用户数的。这句话的含义:

  • 吞吐量和并发用户数有关;
  • 不同的并发用户数下,吞吐量是不同的;
    计算公式:总请求数/处理完成这些请求所花费的时间。

2.并发连接数:并发连接数指的是某个时刻服务器所接收的请求数目,简单的讲,就是一个会话。

3.并发用户数:一个用户可以同时会产生一个会话或多个会话,也就是连接数;

4.用户平均等待时间:计算公式:处理完成所有请求数所花费的时间/(总请求数/并发用户数);

5.服务器平均等待时间:计算公式:处理完成多有请求数所花费的时间/总请求数。也就是吞吐量的倒数。同时也就是用户平均等待时间/并发用户数。

5.安装php加速软件Xcache

以下操作均在php服务器上完成。

下载 Xcache软件

(1)安装xcache

[root@localhost ~]# tar zxf xcache-3.2.0.tar.gz -C /usr/src   
[root@localhost ~]# cd /usr/src/xcache-3.2.0/
[root@localhost xcache-3.2.0]#  /usr/local/php5.6/bin/phpize
Configuring for:
//需要使用phpize命令来生成configure配置文件
PHP Api Version:         20131106
Zend Module Api No:      20131226
Zend Extension Api No:   220131226
[root@localhost xcache-3.2.0]# ./configure --enable-xcache --enable-xcache-coverager /
--enable-xcache-optimizer --with-php-config=/usr/local/php5.6/bin/php-config && make && make install  
//编译安装之后,这条路径至关重要:
Installing shared extensions:     /usr/local/php5.6/lib/php/extensions/no-debug-zts-20131226/

编译配置参数详解:

  • --enable-xcache:启用xcache功能;
  • --enable-xcache-coverager:用于测试加速器功效和附加性;
  • --enable-xcache-optimizer:操作代码优化;

(2)创建xcache缓存文件

[root@localhost ~]# touch /tmp/xcache
[root@localhost ~]# chmod 777 /tmp/xcache

(3)将xcache的后台管理程序复制到网站目录下

[root@localhost ~]# cp -r /usr/src/xcache-3.2.0/htdocs/ /var/www/benet/xcache
//以便使用web页面进行访问,查看效果

(4)修改php的配置文件,让其支持xcache

[root@localhost ~]# vim /etc/php.ini                   //编辑php的配置文件
//在末尾添加以下内容
[xcache-common] 
extension = /usr/local/php5.6/lib/php/extensions/no-debug-zts-20131226/xcache.so 
//启用php的xcache扩展功能
[xcache.admin] 
xcache.admin.enable_auth = Off         //关闭xcache认证
[xcache] 
xcache.shm_scheme ="mmap"            //决定xcache如何从系统共享内存
//nmap是一种内存映射文件的方法
xcache.size=60M              //所用共享缓存的大小,如果设置为0,将无法使用
xcache.count =1                  //将cache切分成多少块,建议设置为cpu数 
xcache.slots =8K                //指作为hash槽个数的参考值
xcache.ttl=0                      //文件生存时间,设置为0将无限缓存
xcache.gc_interval =0          //触发垃圾回收的时间间隔,默认为0秒
xcache.var_size=64M           //针对变量的缓存
xcache.var_count =1 
xcache.var_slots =8K 
xcache.var_ttl=0 
xcache.var_maxttl=0 
xcache.var_gc_interval =300 
xcache.test =Off                   //关闭测试功能
xcache.readonly_protection = Off           //启动会降低性能,但是略微提高安全性
xcache.mmap_path ="/tmp/xcache"          //用于只读文件路径
xcache.coredump_directory =""                
//在遇到故障时,放置核心转储功能,必须是php可写入的目录,保留为空表示禁用
xcache.cacher =On            //使用opcode缓存,xcache.size=0时无效
xcache.stat=On                 //使用stat发现检查脚本的更新
xcache.optimizer =Off                 //禁用优化
[xcache.coverager] 
xcache.coverager =On           //启用代码覆盖信息采集器
xcache.coveragedump_directory =""        
//放置数据采集信息的目录位置,默认使用目录/tmp/pcovis
[root@localhost ~]# scp -r /var/www/benet/xcache/  192.168.1.1:/var/www/benet
//将xcache网页文件复制到Apache服务器网页根目录
[root@localhost ~]# systemctl restart php-fpm
//重新启动php

客户使用浏览器进行访问测试:

部署LAMP动静分离以及部署Discuz论坛

如果现在对动态页面进行压力测试,此时xcache就会缓存动态页面信息,实际环境中一般也使用不到,所以这里就略过了。

三、部署Discuz论坛

下载 Discuz论坛程序

php服务器进行以下操作:

[root@localhost ~]# unzip Discuz_7.0.0_FULL_SC_UTF8.zip -d discus
//将Discuz软件程序解压到discus目录
[root@localhost ~]# mv discus/Discuz_7.0.0_FULL_SC_UTF8/upload/ /var/www/benet/bbs
//将Discuz程序中的upload移动到网站跟目录下
[root@localhost ~]# chown -R nobody:nobody /var/www/benet/bbs/
[root@localhost ~]# chmod -R 777 /var/www/benet/bbs/
//将目录设置权限(测试环境赋予最大权限)
[root@localhost ~]# sed -i 's/short_open_tag = Off/short_open_tag = On/g' /etc/php.ini
//修改php服务器的配置文件
[root@localhost ~]# systemctl restart php-fpm                  //重启php-fpm
[root@localhost ~]# echo "/var/www/benet  192.168.1.0/24(rw,sec=sys,sync,no_root_squash)" >> /etc/exports
[root@localhost ~]# systemctl restart nfs
[root@localhost ~]# showmount -e
Export list for localhost.localdomain:
/var/www/benet 192.168.1.0/24
//配置nfs服务,并重启nfs服务

Mysql服务器进行以下操作:

[root@localhost ~]# mysql -u root -p123      //登录Mysql服务器
mysql> create database bbs;                //创建bbs数据库

Apache服务器进行以下操作:

[root@localhost ~]# mount -t nfs 192.168.1.3:/var/www/benet/ /var/www/benet
//将php服务器的网页根目录复制到Apache服务器网页根目录

客户端访问测试

部署LAMP动静分离以及部署Discuz论坛 部署LAMP动静分离以及部署Discuz论坛 部署LAMP动静分离以及部署Discuz论坛 部署LAMP动静分离以及部署Discuz论坛 部署LAMP动静分离以及部署Discuz论坛

访问论坛成功!

———————— 本文至此结束,感谢阅读 ————————

原文  https://blog.51cto.com/14157628/2454369
正文到此结束
Loading...