一、绪论
最近要用到fastDFS,所以自己研究了一下,在搭建FastDFS的过程中遇到过很多的问题,为了能帮忙到以后搭建FastDFS的同学,少走弯路,与大家分享一下。FastDFS的作者淘宝资深架构余庆,这个优秀的轻量及的分布式文件系统的开源没多久,立马就火了。
二、应用场景
FastDFS是为互联网应用量身定做的一套分布式文件存储系统,非常适合用来存储用户图片、视频、文档等文件。对于互联网应用,和其他分布式文件系统相比,优势非常明显。其中有好几家是做网盘的公司。其中存储量最大的一家,集群中存储group数有400个,存储服务器超过800台,存储容量达到6PB,文件数超过1亿,Group持续增长中。
以下是使用FastDFS的用户列表:
UC (http://www.uc.cn/,存储容量超过10TB)
京东商城(http://www.360buy.com/)
淘淘搜(http://www.taotaosou.com/)
淘米网(http://www.61.com/)
5173(http://www.5173.com/)
华夏原创网(http://www.yuanchuang.com/)
华师京城教育云平台(http://www.hsjdy.com.cn/)
58同城(http://www.58.com/)
商务联盟网(http://www.biz72.com/)
中青网(http://www.youth.cn/)
缤丽网 (http://www.binliy.com/)
飞视云视频(http://www.freeovp.com/)
活动帮(http://www.eventsboom.com)
51CTO(http://www.51cto.com/)
三、详细介绍
FastDFS是一个开源的分布式文件系统,她对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS服务端有两个角色:跟踪器(tracker)和存储节点(storage)。跟踪器主要做调度工作,在访问上起负载均衡的作用。
存储节点存储文件,完成文件管理的所有功能:存储、同步和提供存取接口,FastDFS同时对文件的meta data进行管理。所谓文件的meta data就是文件的相关属性,以键值对(key value pair)方式表示,如:width=1024,其中的key为width,value为1024。文件meta data是文件属性列表,可以包含多个键值对。
FastDFS系统结构如下图所示:
跟踪器和存储节点都可以由一台多台服务器构成。跟踪器和存储节点中的服务器均可以随时增加或下线而不会影响线上服务。其中跟踪器中的所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。
为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用。
在卷中增加服务器时,同步已有的文件由系统自动完成,同步完成后,系统自动将新增服务器切换到线上提供服务。
当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就扩大了存储系统的容量。
FastDFS中的文件标识分为两个部分:卷名和文件名,者缺一不可。
3.1 上传文件交互过程
1. client询问tracker上传到的storage,不需要附加参数;
2. tracker返回一台可用的storage;
3. client直接和storage通讯完成文件上传。
3.2 下载文件交互过程
1. client询问tracker下载文件的storage,参数为文件标识(卷名和文件名);
2. tracker返回一台可用的storage;
3. client直接和storage通讯完成文件下载。
四、FastDFS搭建工具下载
作者的GitHub地址:https://github.com/happyfish100
这次搭建的所有工具,都可以在上面下载到。我搭建的是目前最新版本Version 5.11 2017-05-26。作者还有一个5.10的发行版本,你如果没有下载最近的,到时候整合nginx的时候可能会遇到:
local/fastdfs-nginx-module/src/common.c:1245: 错误:‘FDFSHTTPParams’没有名为‘support_multi_range’的成员
make[1]: *** [objs/addon/src/ngx_http_fastdfs_module.o] 错误 1
make[1]: Leaving directory `/usr/local/nginx-1.10.1'
遇到这个错误的原因是,在fastdfs-nginx-module的HISTORY中你可以到:
整合的时候,fastdfs-nginx-module中的support_multi_range在Version 5.10中找不到。
Version 5.11对应的fastdfs-nginx-module的Version 1.20
Version 5.10对应的fastdfs-nginx-module的Version 1.19
之所以在安装前写了这么一段话,是因为这个很重要,版本不对应会给接下来的安装带来各种问题。
4.1 下载工具
把源码下载下来4个zip包,再去下个nginx:
Nginx下载地址:https://nginx.org/en/download.html
4.2 上传到CentOS7
传文件到liunx系统的方法很多。我个人比较喜欢用xftp上传。
感兴趣的同学可以参考一篇博文:
CentOS7 搭建vsftp详细教程:http://blog.csdn.net/m0_37797991/article/details/73433969
也可通过vsftp上传,但后面介绍的是通xftp和xshell工具的操作
五、CentOS7 FastDFS搭建
5.1安装libfastcommon
1) 安装zip
- yum -y install unzip zip
2) 安装成功之后,解压libfastcommon-master.zip
- cd /usr/local/src/
- unzip libfastcommon-master.zip
3) 进入我们刚刚解压的目录
- cd libfastcommon-master
- ll
4) 当我们执行./make.sh的时候提示“gcc命令没找到”时
用yum安装gcc:
yum命令相当好用,是RedHad和CentOS从指定服务器下载RPM包并自动安装。我个人比较喜欢。
- yum -y install gcc-c++
这个时候分别执行./make.sh和./make.sh install,正常情况是可以成功的。
5) 执行./make.sh 和./make.sh install命令
- ./make.sh
- ./make.sh install
6) libfastcommon默认会被安装到/usr/lib64/libfastcommon.so,但是FastDFS的主程序却在/usr/local/lib目录下
这个时候我们就要建立一个软链接了,实际上也相当于windows上的快捷方式。
- ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
- ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so(在执行./make.sh install 命令时已经在/usr/lib/目录下安装了libfastcommon.so,这条命令可不执行)
- ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
- ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so
5.2安装FastDFS
1) 解压FastDFS安装包
- cd /usr/local/src
- unzip fastdfs-master.zip
2) 进入到刚解压的目录
- u cd fastdfs-master/
3) 执行./make.sh 和./make.sh install命令
- ./make.sh
- ./make.sh install
如果没有报错那么就成功了。安装log中会提示FastDFS安装到了/etc/fdfs目录下。
4) 成功后查看安装目录
- cd /etc/fdfs/
- ll
5) 我们需要把这三个示例文件复制一份,去掉.sample
- cp client.conf.sample client.conf
- cp storage.conf.sample storage.conf
- cp tracker.conf.sample tracker.conf
FastDFS安装结束。
5.3安装Tracker
1) 在配置Tracker之前,首先需要创建Tracker服务器的文件路径,即用于存储Tracker的数据文件和日志文件等,我这里选择在/opt目录下创建一个fastdfs_tracker目录用于存放Tracker服务器的相关文件:
- mkdir /opt/fastdfs_tracker
2) 接下来就要重新编辑上一步准备好的/etc/fdfs目录下的tracker.conf配置文件,打开文件后依次做以下修改:
- cd /etc/fdfs
- vim tracker.conf
如果没有vim命令可以把vim改为vi,或者去下载一个vim
yum -y install vim #简单粗暴安装方法
打开后重点关注下面4个配置:
1.disabled=false #默认开启
2.port=22122 #默认端口号
3.base_path=/opt/fastdfs_tracker #我刚刚创建的目录
4.http.server_port=6666 #默认端口是8080
修改完,按“ESC”键,只有输入“:wq!”保存退出
3) 配置完成后就可以启动Tracker服务器了,但首先依然要为启动脚本创建软引用,因为fdfs_trackerd等命令在/usr/local/bin中并没有,而是在/usr/bin路径下:
- ln -s /usr/bin/fdfs_trackerd /usr/local/bin
- ln -s /usr/bin/stop.sh /usr/local/bin
- ln -s /usr/bin/restart.sh /usr/local/bin
4) 启动Tracker
① 保存配置后启动Trackeer,命令如下:
- service fdfs_trackerd start
如果不能启动,或提示用systemctl可改用命令:
- systemctl start fdfs_trackerd
成功后应该可以看到:
[root@localhost fdfs]# service fdfs_trackerd start
Starting fdfs_trackerd (via systemctl): [ OK ]
② 进行刚刚创建的tracker目录,发现目录中多了data和log两个目录
- cd /opt/fastdfs_tracker/
- ll
total 0
drwxr-xr-x 2 root root 178 Jun 16 21:19 data
drwxr-xr-x 2 root root 26 Jun 13 22:01 logs
③ 我们需要给Tracker加入开机启动
- ll /etc/rc.d/rc.local
④ 发现被没有执行权限,需要加一下权限
- chmod +x /etc/rc.d/rc.local
加完权限后因该是这样的:
-rwxr-xr-x 1 root root 501 Jun 16 21:34 /etc/rc.d/rc.local
⑤ 修改rc.local
- vim /etc/rc.d/rc.local
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.
touch /var/lock/subsys/local
service fdfs_trackerd start
加完之后,按“ESC”键,之后输入“:wq!”保存退出
⑥ 查看一下tracker的端口监听情况
- netstat -unltp|grep fdfs
端口22122成功监听。
5.3安装Storage
storage的安装与tracker很类似。
1) 创建storage工作目录
与tracker不同的是,由于storage还需要一个目录用来存储数据,所以我另外多建了一个fasdfs_storage_data
- mkdir /opt/fastdfs_storage
- mkdir /opt/fastdfs_storage_data
2) 接下来修改/etc/fdfs目录下的storage.conf配置文件,打开文件后依次做以下修改:
- vim /etc/fdfs/storage.conf
重点注意下面的配置项
1.disabled=false
2.group_name=group1 #组名,根据实际情况修改
3.port=23000 #设置storage的端口号,默认是23000,同一个组的storage端口号必须一致
4.base_path=/opt/fastdfs_storage #设置storage数据文件和日志目录
5.store_path_count=1 #存储路径个数,需要和store_path个数匹配
6.store_path0=/opt/fastdfs_storage_data #实际文件存储路径
7.tracker_server=192.168.8.129:22122 #我CentOS7的ip地址
8.http.server_port=8888 #设置 http 端口号
修改完之后,按“ESC”键,之后输入“:wq!”保存退出
3) 创建软引用
- ln -s /usr/bin/fdfs_storaged /usr/local/bin
4) 启动storage
① 保存配置后启动Trackeer,命令如下:
- service fdfs_storaged start
如果不能启动,或提示用systemctl可改用命令:
- systemctl start fdfs_storaged
成功后应该可以看到:
[root@localhost fdfs]# service fdfs_stroaged start
Starting fdfs_storaged (via systemctl): [ OK ]
② 设置开机启动
修改rc.local
- vim /etc/rc.d/rc.local
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.
touch /var/lock/subsys/local
service fdfs_trackerd start
service fdfs_storaged start
③ 查看一下服务是否启动
- netstat -unltp | grep fdfs
服务已正常启动。
5) 校验整合
到这里,fastdfs的东西都已安装完成,最后我们还要确定一下,storage是否注册到了tracker中去
查看命令:
- /usr/bin/fdfs_monitor /etc/fdfs/storage.conf
成功后可以看到
[2017-10-18 17:03:50] DEBUG - base_path=/opt/fastdfs_storage, connect_timeout=30, network_timeout=60, tracker_server_count=1, anti_steal_token=0, anti_steal_secret_key length=0, use_connection_pool=0, g_connection_pool_max_idle_time=3600s, use_storage_id=0, storage server id count: 0
server_count=1, server_index=0
tracker server is 192.168.8.129:22122
group count: 1
Group 1:
group name = group1
disk total space = 51175 MB
disk free space = 35622 MB
trunk free space = 0 MB
storage server count = 1
active server count = 1
storage server port = 23000
storage HTTP port = 8888
store path count = 1
subdir count per path = 256
current write server index = 0
current trunk file id = 0
Storage 1:
id = 192.168.8.129
ip_addr = 192.168.8.129 ACTIVE
http domain =
version = 5.11
join time = 2017-10-18 17:02:44
up time = 2017-10-18 17:02:44
total storage = 51175 MB
free storage = 35622 MB
upload priority = 10
store_path_count = 1
subdir_count_per_path = 256
storage_port = 23000
storage_http_port = 8888
current_write_path = 0
source storage id =
if_trunk_server = 0
connection.alloc_count = 256
connection.current_count = 0
connection.max_count = 0
total_upload_count = 0
success_upload_count = 0
total_append_count = 0
success_append_count = 0
total_modify_count = 0
success_modify_count = 0
total_truncate_count = 0
success_truncate_count = 0
total_set_meta_count = 0
success_set_meta_count = 0
total_delete_count = 0
success_delete_count = 0
total_download_count = 0
success_download_count = 0
total_get_meta_count = 0
success_get_meta_count = 0
total_create_link_count = 0
success_create_link_count = 0
total_delete_link_count = 0
success_delete_link_count = 0
total_upload_bytes = 0
success_upload_bytes = 0
total_append_bytes = 0
success_append_bytes = 0
total_modify_bytes = 0
success_modify_bytes = 0
stotal_download_bytes = 0
success_download_bytes = 0
total_sync_in_bytes = 0
success_sync_in_bytes = 0
total_sync_out_bytes = 0
success_sync_out_bytes = 0
total_file_open_count = 0
success_file_open_count = 0
total_file_read_count = 0
success_file_read_count = 0
total_file_write_count = 0
success_file_write_count = 0
last_heart_beat_time = 2017-10-18 17:03:49
last_source_update = 1970-01-01 08:00:00
last_sync_update = 1970-01-01 08:00:00
last_synced_timestamp = 1970-01-01 08:00:00
六、FastDFS的Nginx 模块安装
6.1安装Nginx准备
在安装Nginx之前要安装Nginx所需要的依赖lib:
1) PCRE pcre-devel 安装
PCRE(Perl Compatible Regular Expressions) 是一个Perl库,包括perl兼容的正则表达式库。nginx的http模块使用pcre来解析正则表达式,所以需要在linux上安装pcre库,pcre-devel是使用pcre开发的一个二次开发库。nginx也需要此库。命令:
- yum install -y pcre pcre-devel
2) zlib 安装
zlib 库提供了很多种压缩和解压缩的方式, nginx使用zlib对http包的内容进行gzip,所以需要在Centos上安装zlib库。
- yum install -y zlib zlib-devel
3) OpenSSL 安装
OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及 SSL 协议,并提供丰富的应用程序供测试或其它目的使用。
nginx 不仅支持 http协议,还支持https(即在ssl协议上传输http),所以需要在Centos安装OpenSSL库。
- yum install -y openssl openssl-devel
6.2安装Nginx并添加fastdfs-nginx-module
1) 解压Nginx和fastdfs-nginx-module
- cd /usr/local/src
- tar -zxvf nginx-1.13.3.tar.gz
- unzip fastdfs-nginx-module-master.zip
2) 解压成功后就可以编译安装nginx了,进入nginx目录并输入以下命令进行配置
- cd /usr/local/src/nginx-1.13.3
- ./configure --prefix=/usr/local/nginx --add-module=/usr/local/src/fastdfs-nginx-module-master/src
3) 如果配置不报错的话,就开始编译
- make
- make install
如果报错的话,很可能是版本的原因。
Nginx的默认安装目录是/usr/local/nginx
4) 安装成功后查看
- cd /usr/local/nginx
- ll
配置storage nginx
5) 修改nginx.conf
- cd /usr/local/nginx/conf
- vim nginx.conf
8) 修改监听端口 listen 9999, 新增location
server {
listen 9999;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location ~/group1/M00 {
root /opt/fastdfs_storage_data/data;
ngx_fastdfs_module;
}
location = /50x.html {
root html;
}
}
修改完,按“ESC”键,再输入“:wq!”保存退出
9) 然后进入FastDFS安装时的解压过的目录,将http.conf、mime.types文件拷贝到/etc/fdfs 目录下
- cp -r /usr/local/src/fastdfs-master/conf/http.conf mime.types /etc/fdfs/
10) 另外还需要把fastdfs-nginx-module安装目录中src目录下的mod_fastdfs.conf也拷贝到/etc/fdfs目录下
- cp -r /usr/local/src/fastdfs-nginx-module-master/src/mod_fastdfs.conf /etc/fdfs/
11) 对刚刚拷贝的mod_fastdfs.conf文件进行修改
- vim /etc/fdfs/mod_fastdfs.conf
base_path=/opt/fastdfs_storage #保存日志目录
tracker_server=192.168.8.129:22122 #tracker服务器的IP地址以及端口号
storage_server_port=23000 #storage服务器的端口号
url_have_group_name = true #文件 url 中是否有 group 名
store_path0=/opt/fastdfs_storage_data #存储路径
group_count = 3 #设置组的个数,事实上这次只使用了group1
在文件的最后,设置group
在mod_fastdfs.conf最后设置group
[group1]
group_name=group1
storage_server_port=23000
store_path_count=1
store_path0=/opt/fastdfs_storage_data
[group2]
group_name=group2
storage_server_port=23000
store_path_count=1
store_path0=/opt/fastdfs_storage_data
[group3]
group_name=group3
storage_server_port=23000
store_path_count=1
store_path0=/opt/fastdfs_storage_data
修改完,按“ESC”键,再输入“:wq!”保存退出
12) 创建M00至storage存储目录的符号链接
- ln -s /opt/fastdfs_storage_data/data /opt/fastdfs_storage_data/data/M00
13) 启动nginx
- /usr/local/nginx/sbin/nginx
启动成功
14) 安装iptables防火墙
- yum install iptables-services -y
15) 防火墙设置
① 查看防火墙状态
- systemctl status iptables
② 编辑防火墙,增加端口
- vim /etc/sysconfig/iptables #编辑防火墙配置文件
-A INPUT -p tcp -m state --state NEW -m tcp --dport 9999 -j ACCEPT
:wq! #保存退出
③ 重启配置,重启系统
- systemctl restart iptables.service #重启防火墙使配置生效
- systemctl enable iptables.service #设置防火墙开机启动
16) 访问nginx
可以成功访问
配置storage nginx
17) 在/usr/local/下新建一个ngxin2文件夹
- mkdir /usr/local/nginx2
18) 再装一个nginx,安装路径为/usr/local/nginx2
- cd /usr/local/src/nginx-1.13.3
- ./configure --prefix=/usr/local/nginx2 --add-module=/usr/local/src/fastdfs-nginx-module-master/src
19) 如果配置不报错的话,就开始编译
- make
- make install
如果报错的话,很可能是版本的原因。
Nginx的默认安装目录是/usr/local/nginx2
20) 安装成功后查看
- cd /usr/local/nginx2
- ll
配置storage nginx
21) 修改nginx.conf
- cd /usr/local/nginx2/conf
- vim nginx.conf
接下来依然是修改nginx2的配置文件,进入conf目录并打开nginx.conf文件加入以下配置,tracker的nginx无需修改listen端口,即默认的80端口,并将upstream指向storage的nginx地址,在http节点下新增:
upstream fdfs_group1 {
server 127.0.0.1:9999;
}
在server节点下新增:
location /group1/M00 {
proxy_pass http://fdfs_group1;
}
22) 最后一步就是需要修改/etc/fdfs目录下的client.conf文件,打开该文件并加入以下配置:
base_path=/data/fastdfs_storage #日志存放路径
tracker_server=192.168.8.129:22122 #tracker 服务器 IP 地址和端口号
http.tracker_server_port=6666 # tracker 服务器的 http 端口号,必须和tracker的设置对应起来
至此关于fastdfs就已经全部配置完毕了,再一次进行测试看看是否能正常上传文件并通过http访问文件。
23) HTTP测试
再给/opt目录下上传一张图片(timg.jpg)
通过客户端命令测试上传:
- /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /opt/timg.jpg
如果报“upload file fail, error no: 2, error info: No such file or directory”这种错,看一下上传测试文件的路径和文件名称是否正确
下图这样证明文件上传成功:
24) 用浏览器访问上传文件
http://192.168.8.129/group1/M00/00/00/wKgIgVnn_6iATX7KAADAprdPTlg515.jpg
如果是这样请查看80端口是否打开,和nginx服务是否已启动
- vim /etc/sysconfig/iptables #编辑防火墙配置文件
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
:wq! #保存退出
重启防火墙使配置生效
- systemctl restart iptables.service #重启防火墙使配置生效
25) 当能用浏览器访问到上传文件时
一切正常~ 至此关于FastDFS在CentOS 7下的部署测试就已经全部完成了
26) Nginx开机自启动
在rc.local增加启动代码就可以了。
- vim /etc/rc.local
增加/usr/local/nginx/sbin/nginx、/usr/local/nginx2/sbin/nginx
设置执行权限:
- chmod 755 /etc/rc.local
到这里,nginx就安装完毕了,启动、停止、重启操作也都完成了,当然,你也可以添加为系统服务,我这里就不在演示了
七、FastDFS 常见问题
Q:/fdfs_trackerd: error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory
A:export LD_LIBRARY_PATH=/usr/loal/lib(libevent的安装路径,可以通过find来查找)
Q:Command 'ifconfig' is available in '/sbin/ifconfig'
The command could not be located because '/sbin' is not included in the PATH environment variable.
This is most likely caused by the lack of administrative priviledges associated with your user account.
ifconfig: command not found
A:export PATH=$PATH:/sbin
Q:nginx@ubuntu:~/fastdfs/bak$ ./run_nginx.sh
/home/nginx/nginx/sbin/nginx: error while loading shared libraries: libfastcommon.so: cannot open shared object file: No such file or directory
A:找不到fastdfs的库文件,因为前面执行了export LD_LIBRARY_PATH=/usr/loal/lib,所以 为了使得使用方便,就把所有需要用到的LIB放在一起:
cp libf*.so /usr/local/lib
ls -l /usr/local/lib/libf* 如果没有链接映射,就需要自己做一个或者把四个文件全部拷过去
sudo ln -sf /home/nginx/fastdfs/lib/libfastcommon.so.1 /usr/local/lib/libfastcommon.so
sudo ln -sf /home/nginx/fastdfs/lib/libfdfsclient.so.1 /usr/local/lib/libfdfsclient.so
注意:做软链接的时候需要加绝对路径,不然会出现黑色的提示。
Q:400 badrequest
[2011-12-12 15:24:21] ERROR - file: /tmp/fastdfs-nginx-module/src/common.c, line: 561, logic file: M00/00/00/wKgBNU7lqyjzJZ4mAA4CRXl5SCQ670.jpg not exists
2011/12/12 15:24:21 [error] 14147#0: *1 open() "/home/nginx/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.1.123, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.1.53:8090"
A:修改/fastdfs/conf/mod_fastdfs.conf
里面url_have_group_name = true
Q: 在track
转载自原文链接, 如需删除请联系管理员。 原文链接:分布式文件系统 - FastDFS 配置 Nginx,转载请注明来源!