MogileFS是一套高效的文件自动备份组件,由Six Apart开发,广泛应用在包括LiveJournal等web2.0站点上

MogileFS由3个部分组成:

   第1个部分:是server端,包括mogilefsd和mogstored两个程序。前者即是mogilefsd的tracker,它将一些全局信息保存在数据库里,例如站点domain,class,host等。后者即是存储节点(store node),它其实是个HTTP Daemon,默认侦听在7500端口,接受客户端的文件备份请求。在安装完后,要运行mogadm工具将所有的store node注册到mogilefsd的数据库里,mogilefsd会对这些节点进行管理和监控。

   第2个部分:是utils(工具集),主要是MogileFS的一些管理工具,例如mogadm等。

   第3个部分:是客户端API,目前只有Perl API(MogileFS.pm)、PHP,用这个模块可以编写客户端程序,实现文件的备份管理功能,提供MogileFS.pm。

   当下互联网飞速发展,海量并发所产生的数据量以几何方式增长,随着信息链接方式日益多样化,数据存储的结构也发生了变化,在这样的压力下我们不得不重新审视大量数据的存储所带来了巨大的挑战:

   1、数据采集:对于社交网站一般都是由用户上传的;

   2、数据存储:现在是数据量大爆炸时代,每天都会产生大量的数据,所以数据存储就成了一个大问题;

   3、数据搜索:如果说存储是考验数据的存储能力的话,那搜索就是考量计算机能力了,从大量的数据中搜索出来;

   4、数据共享:数据存储下来之后还要进行数据的共享问题,大量的数据该怎么共享这些数据呢;

   5、数据传输:而海量数据存储下来之后数据怎么用户与用户之间进行安全的传输;

   6、数据分析:数据的分析是了解我们过去的一些行为规范;

   7、数据可视化:而海量数据存储下来之后怎么样可以直观的展示在人们面前呢;

分布式文件系统的几个难点:

   1、缺乏全局时钟、不过同步本身就存在时间差,很难做到步调一致,

   2、面对故障的独立性,分布式是由多个节点组成的,而每个节点都是独立工作的,一个节占故障度不会影响其它节点正常工作,

   3、如何去处理单点故障, 一是:做冗余,对单点做备份;二是:降低单点故障的影响范围

   4、事务类的挑战,在分布环境中怎么处理事务呢;ACID或2PI(两段式提交)、最终一致、BASE法则、CAP理论、Paxos算法;





什么是两段式提交: 

   通过使用某种协议进行通信来完成分布式事务,被称为两段式提交。从名字上看,您可能已经知道有两个阶段:

第一个阶段,即预提交:

   事务协调器给每个事务管理器发送准备操作的信号。

   事务管理器将操作(通常是数据更新)步骤(或细节)写入事务日志。如果失败,事务管理器使用这些步骤重复操作。

   事务管理器本地创建事务并通知资源管理器对资源(例如,数据库或消息服务器)执行操作。

   资源管理器执行操作并向事务管理器报告成功(准备提交信号)或失败(准备回滚)。

   资源管理器等待事务管理器进一步的指令。

   事务管理器向事务协调器报告成功或失败。

第二阶段,即提交阶段:在第二阶段中,第一阶段的结果将传送给所有事务管理器。

   如果任何事务管理器报告失败,所有的事务参与者都必须回滚。

   事务协调器让所有事务管理器提交(或回滚)。

   所有事务管理器将提交或回滚信息传递给其资源管理器。

   资源管理器将成功或失败提示返回给事务管理器。

   事务管理器向事务协调器报告成功或失败。





CAP理论:一致性,可用性,分区容错性;指一个分布式系统不可以满足一致性,可用性和分区容错性这三个需求,最多只能同时满足其中的两个;

   C(Consistency):一致性,任何一个读操作总是能够读取之前完成的写操作;就是一个数据写入一立马被读到;

   A(Availability):可用性,每一次操作总是能够 在确定的时间返回;无论成功或失败都能收到一个返回值的;

   P(Tolerance of network Partition):分区容错性,在出现网络分区的情况下,仍然能够满足一致性和可用性;



BASE法则模型反ACID模型,完全不同ACID模型,牺牲高一致性,获得可用性或可靠性:

   BA:Basically Available,基本可以用,支持分区失败(sharding碎片划分数据库);

   S:Soft state,软状态,接受一段时间内的状态不同步,异步;

   E:Eventually consistent:最终一致性,弱一致性的表现;

   BASE思想主要强调基本的可用性,如果你需要High 可用性,也就是纯粹的高性能,那么就要以一致性或容错性为牺牲,BASE思想的方案在性能上还是有潜力可挖的。





Paxos算法:比2PC提交更轻量级的分布式事务的协调方式;大概是指不出现故拜占庭将军的前提下,要取得数据的一致性,在通信信道不安全的时候,我们数据传输可能会被人劫持,这样就不能保证数据的可信了,所以必须保证通信信道安全下Paxos算法才可行;



实现MogileFS的分布式过程,按照下图构建MogileFS分布式文件系统的结构,这里限于机器的原因,一些服务都整合在一起;

第一步:安装MogileFS软件

我们前面提到,它是由三部分组成,所以三个组件都得安装上,并且每个节点都做MogileFS和Mogstored;

在这里先说此次的基本布局,192.168.8.39上安装nginx,192.168.8.40上安装MariaDB数据库,192.168.8.41和192.168.8.43上都安装了MogileFS和Mogstored,8.41和8.43都共同使用8.40上的MariaDB数据库,nginx做为前端接收用户请求并负载均衡到后端两个节点上

在8.41上的安装和配置过程,修改好配置文件之后复制一份相同的配置文件到8.43节点上,因为它们的配置参数都是一样的:



在 8.41 和8.43 分别安装 mofilefs和mofstored服务



  

# yum install -y epel-release
# yum install -y perl-Net-Netmask perl-IO-AIO
# yum localinstall -y MogileFS-Server-2.46-2.el6.noarch.rpm MogileFS-Server-mogilefsd-2.46-2.el6.noarch.rpm MogileFS-Server-mogstored-2.46-2.el6.noarch.rpm MogileFS-Utils-2.19-1.el6.noarch.rpm Perlbal-1.78-1.el6.noarch.rpm Perlbal-doc-1.78-1.el6.noarch.rpm perl-MogileFS-Client-1.14-1.el6.noarch.rpm perl-Net-Netmask-1.9015-8.el6.noarch.rpm perl-Perlbal-1.78-1.el6.noarch.rpm

# 安装好之后修改配置文件,只需要修改以下几项就可以了

   # mysql指使用的数据库是什么,MariaDB也是写mysql;mogdb指数据库名;host=192.168.8.40指定安装数据的地址

# vim /etc/mogilefs/mogilefsd.conf
db_dsn = DBI:mysql:mogdb:host=192.168.8.40
db_user = moguser # 指登录mogdb数据所使用的用户名
db_pass = mogpass # 登录mogdb数据所使用密码
listen = 0.0.0.0:7001 # 0.0.0.0表示监听所有地址
# 再编辑mogstored.conf这个配置文件
maxconns = 10000
httplisten = 0.0.0.0:7500
mgmtlisten = 0.0.0.0:7501
docroot = /dfs/mogdata # 把这项改一个特定的目录,以便存储数据,为提升系统性能最好是一个独立分区 # mkdir -pv /dfs/mogdata/dev1 # 创建修改的docroot目录
# chown -R mogilefs.mogilefs /dfs/mogdata/dev1 # 修改属主属组
# chown -R mogilefs.mogilefs /var/run/mogilefsd/
# cd /etc/mogilefs
# scp mogilefsd.conf mogstored.conf root@192.168.8.43:/etc/mogilefs/ # 复制修改好的配置文件到node2的mogilefs目录下,覆盖即可,两个节点都安装配置好之后先不要启动服务,数据库还没有安装





在8.43上的安装和配置,这里的配置文件由node1上复制过来就可以了;

# mkdir -pv /dfs/mogdata/dev2  # 创建修改的docroot目录
# chown -R mogilefs.mogilefs /var/run/mogilefsd/
# chown -R mogilefs.mogilefs /dfs/mogdata/dev2 # 修改属主属组

第二步:安装nginx和MariaDB

这里安装Nginx需要编译安装,因为他需要装载第三方模块才可以使用mogilefs,MariaDB安装这里就不再说明了;

在8.39节点上的安装步骤:





# 解决依赖关系

# yum -y groupinstall "Development Tools" "Server Platform Development"
# yum -y install openssl-devel pcre-devel
# groupadd -r nginx
# useradd -r -g nginx nginx
# tar xf nginx-1.4.7.tar.gz

下载nginx-mogilefs-module-master.zip 地址:https://github.com/vkholodkov/nginx-mogilefs-module

# unzip nginx-mogilefs-module-master.zip 

# cd nginx-1.4.7

# ls

auto  CHANGES  CHANGES.ru  conf  configure  contrib  html  LICENSE  man  README  src

# ./configure \
--prefix=/usr \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/tmp/nginx/client/ \
--http-proxy-temp-path=/var/tmp/nginx/proxy/ \
--http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
--http-scgi-temp-path=/var/tmp/nginx/scgi \
--with-pcre \
--with-debug \
--add-module=/root/nginx-mogilefs-module-master # 这里要指定编译的模块
# make && make install

# 这里MariaDB安装过程不再说明了,可以参数前面的博文 centos6.5下编译安装mariadb-10.0.20:http://blog.csdn.net/reblue520/article/details/50562099

编译安装好之后就可以可以启动MariaDB和去配置Nginx的相关配置了,还要给nginx提供一个服务脚本;

# service mysqld start





# vim /etc/rc.d/init.d/nginx

#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig: - 85 15
# description: Nginx is an HTTP(S) server, HTTP(S) reverse \
# proxy and IMAP/POP3 proxy server
# processname: nginx
# config: /etc/nginx/nginx.conf
# config: /etc/sysconfig/nginx
# pidfile: /var/run/nginx.pid # Source function library.
. /etc/rc.d/init.d/functions # Source networking configuration.
. /etc/sysconfig/network # Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0 nginx="/usr/sbin/nginx"
prog=$(basename $nginx) NGINX_CONF_FILE="/etc/nginx/nginx.conf" [ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx lockfile=/var/lock/subsys/nginx make_dirs() {
# make required directories
user=`nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
options=`$nginx -V 2>&1 | grep 'configure arguments:'`
for opt in $options; do
if [ `echo $opt | grep '.*-temp-path'` ]; then
value=`echo $opt | cut -d "=" -f 2`
if [ ! -d "$value" ]; then
# echo "creating" $value
mkdir -p $value && chown -R $user $value
fi
fi
done
} start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
make_dirs
echo -n $"Starting $prog: "
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
} stop() {
echo -n $"Stopping $prog: "
killproc $prog -QUIT
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
} restart() {
configtest || return $?
stop
sleep 1
start
} reload() {
configtest || return $?
echo -n $"Reloading $prog: "
killproc $nginx -HUP
RETVAL=$?
echo
} force_reload() {
restart
} configtest() {
$nginx -t -c $NGINX_CONF_FILE
} rh_status() {
status $prog
} rh_status_q() {
rh_status >/dev/null 2>&1
} case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
exit 2
esac

测试访问一下nginx的页面:

# chmod +x /etc/init.d/nginx
# vim /etc/profile.d/nginx.sh
export PATH=/usr/sbin/nginx:$PATH
# . /etc/profile.d/nginx.sh # service nginx start # ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:38573 *:*
LISTEN 0 128 :::111 :::*
LISTEN 0 128 *:111 *:*
LISTEN 0 128 *:80 *:*
LISTEN 0 128 :::22 :::*

第三步:连接上数据库,给两个用户授权:

# mysql -uroot -p

MariaDB [(none)]> GRANT ALL ON *.* TO 'root'@'192.168.%.%' IDENTIFIED BY 'mysqlpass';
MariaDB [(none)]> GRANT ALL ON mogdb.* TO 'moguser'@'192.168.%.%' IDENTIFIED BY 'mogpass';
MariaDB [(none)]> FLUSH PRIVILEGES;

第四步:再到两个节点上初始化数据库,在其中一个上设置即可:

# mogdbsetup --dbhost=192.168.8.40 --dbport=3306 --dbname=mogdb --dbrootuser=root --dbrootpass=mysqlpass --dbuser=moguser --dbpass=mogpass --yes





# 可以再回到8.40上验证一下生成的数据库

MariaDB [(none)]> use mogdb
Database changed
MariaDB [mogdb]> show tables;
+----------------------+
| Tables_in_mogdb |
+----------------------+
| checksum |
| class |
| device |
| domain |
| file |
| file_on |
| file_on_corrupt |
| file_to_delete |
| file_to_delete2 |
| file_to_delete_later |
| file_to_queue |
| file_to_replicate |
| fsck_log |
| host |
| server_settings |
| tempfile |
| unreachable_fids |
+----------------------+

第五步:在两个节点的其中一个上添加主机:

将两个节点的mogilefsd和mogstored服务都启动起来

# service mogilefsd start
# service mogstored start
# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:7500 *:*
LISTEN 0 128 *:7501 *:*
LISTEN 0 128 :::111 :::*
LISTEN 0 128 *:111 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 128 *:22 *:*
LISTEN 0 128 127.0.0.1:631 *:*
LISTEN 0 128 ::1:631 :::*
LISTEN 0 128 *:7001 *:*
LISTEN 0 100 ::1:25 :::*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 *:42848 *:*
LISTEN 0 128 :::56905 :::*

# 添加主机

# mogadm --trackers=192.168.8.41:7001 host add 192.168.8.41 --ip=192.168.8.41 --status=alive
# mogadm --trackers=192.168.8.41:7001 host add 192.168.8.43 --ip=192.168.8.43 --status=alive
# mogadm --trackers=192.168.8.41:7001 host list
192.168.8.41 [1]: alive
IP: 192.168.8.41:7500 192.168.8.43 [2]: alive
IP: 192.168.8.43:7500
# 再添加设备

# mogadm --trackers=192.168.8.41:7001 device add 192.168.8.41 1
# mogadm --trackers=192.168.8.41:7001 device add 192.168.8.43 2
# mogadm --trackers=192.168.8.41:7001 device list
192.168.8.41 [1]: alive
used(G) free(G) total(G) weight(%)
dev1: alive 0.000 0.000 0.000 100 192.168.8.43 [2]: alive
used(G) free(G) total(G) weight(%)
dev2: alive 0.000 0.000 0.000 100 # 添加域 # mogadm --trackers=192.168.8.41:7001 domain add images
# mogadm --trackers=192.168.8.41:7001 domain add files
# mogadm --trackers=192.168.8.41:7001 domain add html
# mogadm --trackers=192.168.8.41:7001 domain list
domain class mindevcount replpolicy hashtype
-------------------- -------------------- ------------- ------------ -------
files default 2 MultipleHosts() NONE html default 2 MultipleHosts() NONE images default 2 MultipleHosts() NONE # 添加类
# mogadm --trackers=192.168.8.41:7001 class add images class0 --mindevcount=2
# mogadm --trackers=192.168.8.41:7001 class list
domain class mindevcount replpolicy hashtype
-------------------- -------------------- ------------- ------------ -------
files default 2 MultipleHosts() NONE html default 2 MultipleHosts() NONE images class0 2 MultipleHosts() NONE
images default 2 MultipleHosts() NONE

# 上传几张图片和测试的页面上去

# mkdir -pv /var/www/html
mkdir: created directory `/var/www'
mkdir: created directory `/var/www/html'
# vim /var/www/html/index.html <h1>www.chinasoft.com</h1> # mogupload --trackers=192.168.8.41:7001 --domain=images --key='1.png' --file='/usr/share/backgrounds/default_1920x1200.png'
# mogupload --trackers=192.168.8.41:7001 --domain=images --key='2.png' --file='/usr/share/backgrounds/wallpaper-six-2560x1240.png'
# mogupload --trackers=192.168.8.41:7001 --domain=images --key='/images/3.png' --file='/usr/share/backgrounds/centos_wallpaper_01_1920x1200.png'
# mogupload --trackers=192.168.8.41:7001 --domain=html --key='/files/index.html' --file='/var/www/html/index.html'
# mogupload --trackers=192.168.8.41:7001 --domain=files --key='/files/index.html' --file='/var/www/html/index.html'
# moglistkeys --trackers=192.168.8.41:7001 --domain=images
/images/3.png
1.png
2.png
# moglistkeys --trackers=192.168.8.43:7001 --domain=images
/images/3.png
1.png
2.png
# mogfileinfo --trackers=192.168.8.41:7001 --domain=images --key='/images/3.png'
- file: /images/3.png
class: default
devcount: 2
domain: images
fid: 5
key: /images/3.png
length: 202652
- http://192.168.8.41:7500/dev1/0/000/000/0000000005.fid
- http://192.168.8.43:7500/dev2/0/000/000/0000000005.fid





 可以复制这个地址在页面上测试一下,这里是每上传一个文件就都会在两个节点是都存一份,如果节点多的话它会根据定义的devcount自己选择节点存储几份,这样在一个节点掉了也可以在别的节点在有相同的资源可用;

第六步:在前端的Nginx上配置访问控制,修改配置文件:

# vim /etc/nginx/nginx.conf

 

upstream mogcluster {
server 192.168.8.41:7001;
server 192.168.8.43:7001;
} server {
location / {
root html;
index index.html index.htm;
} listen 80;
server_name www.chinasoft.com; location /images/ {
mogilefs_tracker mogcluster;
mogilefs_domain images; mogilefs_pass {
proxy_pass $mogilefs_path;
proxy_hide_header Content-Type;
proxy_buffering off;
}
} location ~* ^(/files/.*)$ {
mogilefs_tracker mogcluster;
mogilefs_domain files; mogilefs_pass $1 {
proxy_pass $mogilefs_path;
proxy_hide_header Content-Type;
proxy_buffering off;
}
}



然后在页面上测试访问刚才上传的文件以及图片:





总结:

   最后还可以测试一下把一个节点mogstoed服务关闭,试着访问一下看另外正常工作的节点可不可以正常提供服务。

centos 6.5环境下分布式文件系统MogileFS工作原理及分布式部署实现过程的更多相关文章

  1. centos / Linux 服务环境下安装 Redis 5.0.3

    原文:centos / Linux 服务环境下安装 Redis 5.0.3 1.首先进入你要安装的目录 cd /usr/local 2.下载目前最新稳定版本 Redis 5.0.3 wget http ...

  2. 【架构设计】分布式文件系统 FastDFS的原理和安装使用

    本文地址 分享提纲: 1.概述 2. 原理 3. 安装 4. 使用 5. 参考文档 1. 概述 1.1)[常见文件系统] Google了一下,流行的开源分布式文件系统有很多,介绍如下:   -- mo ...

  3. 分布式文件系统FastDFS设计原理

    原文地址: http://blog.chinaunix.net/uid-20196318-id-4058561.html FastDFS是一个开源的轻量级分布式文件系统,由跟踪服务器(tracker ...

  4. 分布式文件系统之MogileFS工作原理及实现过程

    MogileFS是一套高效的文件自动备份组件,由Six Apart开发,广泛应用在包括LiveJournal等web2.0站点上.MogileFS由3个部分组成:   第1个部分:是server端,包 ...

  5. 分布式文件系统 ~MogileFS~

    一.分布式文件系统 分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连,也就是集群文件系统,可以支持 ...

  6. 分布式集群环境下,如何实现session共享四(部署项目测试)

    这是分布式集群环境下,如何实现session共享系列的第四篇.在上一篇:分布式集群环境下,如何实现session共享三(环境搭建)中,已经准备好了相关的环境:tomcat.nginx.redis.本篇 ...

  7. CentOS 6.5环境下heartbeat高可用集群的实现及工作原理详解

    Linux HA Cluster高可用服务器集群,所谓的高可用不是主机的高可用,而是服务的高可用. 什么叫高可用:一个服务器down掉的可能性多种多样,任何一个可能坏了都有可能带来风险,而服务器离线通 ...

  8. 分布式文件系统FastDFS设计原理(转)

    FastDFS是一个开源的轻量级分布式文件系统,由跟踪服务器(tracker server).存储服务器(storage server)和客户端(client)三个部分组成,主要解决了海量数据存储问题 ...

  9. 详细的图文教程来实现 eclipse环境下如何配置tomcat,并且把项目部署到Tomcat服务器上

    很多初学,尤其自学JavaWeb的朋友首次在eclipse下配置tomcat时,总会有种难下手的感觉,在此,通过图文解说的方法,最直观的向大家演示一遍该配置过程. 第一部分:eclipse环境下如何配 ...

随机推荐

  1. 教程] 《开源框架-Afinal》之FinalHttp 01一步一脚

    1.FinalHttp是什么 :FinalHttp 对 HttpClient再次封装,最简洁的就是增加了许多回调的方法,对Get 和 Post 请求进行了简化.另外一点就是FinalHttp加入线程池 ...

  2. [codevs3342][绿色通道]

    codevs3342 思路: 既然是要求最小化最长空题段,直接二分答案.然后就是check函数的写法. 先考虑n方转移,假设当前二分的答案是x,用f[i]表示前i个题,第i道题写的最小花费时间.最后再 ...

  3. JS面试题(一)

    1.JS六种基本数据类型:string Boolean number object undefined function typeof返回的是字符串,有六种:string Boolean number ...

  4. idea 显示properties 中文

    有时我们打开.properties文件时,中文显示为utf8编码格式,可以在file->setting->editor->file encodings下 把transparent n ...

  5. 继承之es5对比es6

    es5: 熟悉es5的童鞋们就知道es5的继承多么恶心~~ es5最经典的继承写法就是如下这样 1.写一个function,用this来扩展其值类属性 2.prototype添加其方法类属性 3.若整 ...

  6. python3简单实现微信爬虫

    Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...

  7. 版本管理——git

    一.git简介 git是一个 分布式版本控制系统 ,学习git之前首先要了解什么是分布式版本控制系统. 集中式版本控制:版本库集中存放在中央服务器,我们工作的时候先从中央服务器获取最新版本,干完活后把 ...

  8. 震惊!最全PyCharm教程

    PyCharm PyCharm是一个用于计算机编程的集成开发环境(IDE),主要用于Python语言开发,由捷克公司JetBrains开发,提供代码分析.图形化调试器,集成测试器.集成版本控制系统(V ...

  9. js/jquery控制页面动态加载数据 滑动滚动条自动加载事件--转他人的

    js/jquery控制页面动态加载数据 滑动滚动条自动加载事件--转他人的 相信很多人都见过瀑布流图片布局,那些图片是动态加载出来的,效果很好,对服务器的压力相对来说也小了很多 有手机的相信都见过这样 ...

  10. text-decoration和text-indent和text-shadow

    text-decoration 属性规定添加到文本的修饰,规定划线的位置. <html> <head> <style type="text/css"& ...