lvs负载简介,原理,常见使用案例及Keepalived高可用

Lvs简介

基础概念

LVS(Linux Virtual Server)即Linux虚拟服务器,是由张文嵩博士主导的开源负载均衡项目,目前LVS已经被集成到Linux内核模块中(2.6及以上版本内核),LVS本质上是为了解决单台服务器性能处理瓶颈的问题,LVS在Linux内核中实现了基于IP的数据请求负载均衡调度方案,终端互联网用户从外部访问公司的外部负载均衡服务器,终端用户的Web请求会发送给LVS调度器,调度器根据自己预设的算法觉得将请求发送给后端的某台真实的Web服务器,同时如果真实服务器连接的是共享存储,那么提供的服务也是相同的,最终用户不管是访问哪台真实服务器,得到的服务内容都是一样的,因此整个集群对用户而言都是透明的。根据LVS工作模式的不同,LVS工作模式分为NAT模式、TUN模式、以及DR模式,以及阿里自己研发的FULL-NAT模式,不过Full--NAT模式没有被编译进内核,工作中常用的模式是DR模式,也算默认的工作模式。

/*
	查看内核是否有lvs模块
	[root@43 ~]# grep -i -C 10 ipvs /boot/config-3.10.0-514.el7.x86_64 
*/
基础术语
/*
    VS:Virtual Server,Director Server(DS),Dispatcher(调度器),Load Balancer
    RS:Real Server(lvs),upstream server(nginx),backend server(haproxy)
    CIP:Client IP
    VIP:Virtual Server IP VS外网的IP
    DIP:Director IP VS内网IP
    RIP:Real Server IP,真实服务的IP
    
    访问流程:CIP<-->VIP<-->DIP<-->RIP
*/

四种工作模式

NAT模式

LVS - NAT本质是多目标IP的DNAT,通过将请求报文中的目标地址和目标端口修改为某挑出的RS的RIP和PORT实现转发。

特点

/*
		1)RIP和DIP应在同一个IP网络,且应使用私网地址;RS的网关要指向DIP
    2)请求报文和响应报文都必须经由Director转发,Director易于成为系统瓶颈
    3)支持端口映射,可修改请求报文的目标PORT(RealServer的Port端口)
    4)VS必须是Linux系统,RS可以是任意OS系统
*/

在实际的场景中,Clients和LVS之间会跨越互联网以及企业入口防火墙、核心交换机等设备,这里为了简要说明,就模拟Client与LVS直连的情况,如下图所示,当客户端的请求到达LVS调度器之后,LVS会结合系统的netfilter模块对数据包进行判断处理,同时根据LVS自身的调度策略,修改报文目的IP地址和端口号,并重新进行封装,然后将报文发送到指定的RealServer,RealServer收到请求报文,然后对其进行处理,将返回报文发送给LVS,然后LVS再修改源IP和源端口,然后发送出去,到达Client,完成整个业务过程。

LVS-NAT的问题:所有的请求报文由LVS调度到后端的RealServer,同时响应报文也需要经过LVS发送出去,因此这里有一个问题是,LVS承载的压力过大,会成为整个集群的性能瓶颈。

DR模式

在DR模型中,LVS服务器只负责请求报文的调度,并且在调度过程中只是修改链路层MAC地址,不修改IP层和传输层头部字段,经过RealServer处理后的返回报文,也是通过VIP和CIP对报文进行封装,因此返回数据包会直接路由到网关,从而经过互联网到达客户端,不会像NAT模式中的返回报文还回到LVS服务器,因此在DR模式中,大大降低了LVS的服务器处理压力,其处理瓶颈基本上只是在LVS硬件本身的性能,下图展示了DR模型下,数据包的大致处理流程,此处忽略了客户端报文到达企业核心的细节过程,因此中间还包括运营商网络、企业入口防火墙等设备。

Director和RealServer同时配置VIP会有什么问题

因为LVS和后端真实服务器RealServer都配置了VIP,在常规网络环境下,这肯定会造成IP地址冲突,同时当报文第一次到达图中核心交换机时,在发送ARP请求VIP的MAC地址时,可能会返回LVS和RealServer的MAC地址,因此造成,为解决这个问题,DR模型提供了两种配置方法:

配置DR的两种方式

1)在图中核心交换机上将Director调度器MAC地址与VIP做静态绑定,这样请求报文就会直接被发送到调度器Director

2)通过调整内核参数,来抑制VIP接口收到ARP请求报文对其进行相应,同时在配置上VIP地址之后,抑制对其向外发送免费ARP,两个参数分别为:arp_ignore、 arp_announce

arp_ignore: 定义接收到ARP请求时的相应级别:

/*
		arp_ignore:定义接受到ARP请求时的相应级别
      0:只要本地配置的有相应地址,就给予响应(默认)
      1:仅回应目标IP地址是本地的入网地址的arp请求。
      2:仅回应目标IP地址是本地的入网地址,而且源IP和目标IP在同一个子网的arp请求。
      3:不回应该网络界面的arp请求,而只对设置的唯一和连接地址做出回应
      4-7:保留未使用
      8:不回应所有的arp请求
*/

arp_announce: 定义将自己地址向外界通告的通告级别

/*
		0:将本地任何接口上的任何地址向外通告
    1:试图仅向目标网络通告与其网络匹配的地址
    2:仅向本地接口上地址匹配的网络进行通告
*/

DR特点

/*
		1、保证前端路由将目标地址为VIP报文统统发给Director Server,而不是RS
    2、Director和RS的VIP为一个VIP
    3、RS可以使用私有地址,也可以是公网地址,通过在企业环境中是私有ip地址
    4、RS跟DirectorServer必须在同一个物理网络中
    5、所有的请求报文经由Director Server,响应报文不经过Director Server
    6、RS的网关不能指向Director,直接指向出口网关即可
    7、RS上的lo接口配置VIP的ip地址
    8、DR模式是LVS默认的方式
*/
TUN模式

TUN模式本质上同DR的方式一样,只是在Director和RealServer之间是通过IP隧道的方式去通信,一般这种方式只在企业需要在多个异地机房做调度时,可以采用这种方式,因此较为不常用。

Full-NAT模式

这种方式同NAT的方式本质上也是一样的,不管是请求报文还是响应报文都要经过Director,唯一的区别是,NAT模式在发送给后端RealServer时,只是做目的IP地址和目的端口转换,而Full-NAT模型下是源目IP地址和源目端口都需要做转换.

十种调度算法

/*
		固定调度算法:rr、wrr、dh、sh
    动态调度算法:wlc、lc、lblc、lblcr、SED、NQ
    固定调度算法:即调度器不会去判断后端服务器的繁忙与否,一如既往的将请求派发下去。
    动态调度算法:调度器会去判断后端服务器的繁忙程度,然后依据调度算法动态的派发请求。
*/
Rr:轮训(round robin)

这种算法是最简单的,就是按依次循环的方式将请求调度到不同的服务器上,该算法最大的特点就是简单。轮询算法假设所有的服务器处理请求的能力都是一样的。调度器会将所有的请求平均分配给每个真实服务器,不管后端RS配置和处理能力,非常均衡的分发下去。这个调度的缺点是,不管后端服务器的繁忙程度是怎样的,调度器都会将请求依次发下去。如果A服务器上的请求很快请求完了,而B服务器的请求一直持续着,将会导致B服务器一直很忙,而A服务器很闲,这样便没有起到均衡的作用。

Wrr:加权轮训(weight round robin)

这种算法比rr的算法多了一个权重的概念,可以给RS设置权重,权重越高,那么分发的请求数越多,权重的取值范围0-100。主要是对rr算法的一种优化和补充,LVS会考虑每台服务器的性能,并给每台服务器添加要给权值,如果服务器A的权值为1,服务器B的权值为2,则调度到服务器B的请求会是服务器A的2倍。权值越高的服务器,处理的请求越多.

Dh: 目标地址散列调度算法(destination hash)

简单的说,即将同一类型的请求分配给同一个后端服务器,例如将.jpg、.png等结尾的请求转发到同一个节点。这种算法其实不是为了真正意义的负载均衡,而是为了资源的分类管理。这种调度算法主要应用在使用了缓存节点的系统中,提高缓存的命中率。

Sh: 原地址散列调度算法(source hash)

即将来自同一个ip的请求发给后端的同一个服务器,如果后端服务器工作正常没有超负荷的话,这可以解决session共享的问题,但是这里有个问题,很多企业,社区,学校都是公用一个ip,这将导致请求分配的不均衡。

Lc: 最少连接数(least-connection)

这个算法会根据后端RS的连接数来决定把请求分发给谁,比如RS1连接数比RS2连接数少,那么请求就优先发给RS1,这里问题是无法做到会话保持,即session共享。

Wlc: 加权最少连接数(least-connection)

这个比最少连接数多了一个加权的概念,即在最少连接数的基础上加一个权重值,当连接数相近,权重值越大,越优先被分派请求

Lblc: 基于局部性的最少连接调度算法(locality-based least-connection)

将来自同一目的地址的请求分配给同一台RS如果这台服务器尚未满负荷,否则分配给连接数最小的RS,并以它为下一次分配的首先考虑。

Lblcr: 基于地址的带重复最小连接数调度(Locality-Based Least-Connection with Replicationn)

用的少,略过

SED 最短期望延迟(Shortest Expected Delay Scheduling Sed) 基于wlc算法

比如ABC三台机器分别权重123,连接数分别为123,那么如果使用wlc算法的话一个请求进来时它可能会分给ABC中的任意一个。使用sed算法后会进行这样一个运算

A:(1+1)/1

B:(1+2)/2

C:(1+3)/3

根据运算结果,把连接交给C

个人理解的算法是(1+当前连接数)/权重

NQ最少队列调度(Never Queue Scheduling NQ)算法

无需队列,如果有台realserver的连接数 = 0就直接分配过去,不需要进行sed运算

命令介绍

语法格式
/*
		ipvsadm COMMAND [protocol] service-address [scheduling-method] [persistence options]

		ipvsadm COMMAND [protocol] service-address server-address [packet-forwarding-emthod] [weight options]
*/
基本参数
/*
		-A,--add-service:为ipvs虚拟服务器添加一个虚拟服务,即添加一个需要被负载均衡的虚拟地址。虚拟地址需要时ip地址,端口号,协议的形式。
    -E,--edit-service:修改一个虚拟服务。
    -D,--delete-service:删除一个虚拟服务。
    -C,--clear:清除所有虚拟服务。
    -R,--restore:从标准输入获取ipvsadm命令,一般结合下边的-S使用
    -S,--save:从标准输出输出虚拟服务器的规则。可以将虚拟服务器的规则保存,在以后通过-R直接读入,以实现自动化配置。
    -a,--add-server:为虚拟服务添加一个real server(RS)
    -e,--edit-server:修改RS
    -d,--delete-server:删除
    -L,-l,--list:列出虚拟服务列表中所有虚拟服务。可以指定地址,添加-c显示连接表
    -Z,--zero:将所有数据相关的记录清零,这些记录一般用于调度策略。
    --set tcp tcpfin udp:修改协议的超时时间
    --start-daemon state:设置虚拟服务器的备服务器,用来实现主备服务器冗余(该功能只支持ipv4)
    --stop-daemon:停止备服务器。
    -h,--help:帮助。
*/

参数 -- 以下参数可以接在上边命令后面

-t,--tcp-service service-address:指定虚拟服务器为tcp服务,service-address要是host[:port]的形式,端口是0表示任意端口,如果需要将端口设置为0,还需要加上-p选项 (持久化)。

-u,--udp-service service-address:使用udp服务,其他同上。

-f,--fwmark-service integer:用firewall mark取代虚拟地址来指定要被负载均衡的数据包,可以通过这个命令实现把不同地址、端口的虚拟地址整合成一个虚拟服务,可以 让虚拟服务器同时截获处理去往多个不同地址的数据包。fwmark可以通过iptables命令指定。如果用在ipv6需要加上-6.

-s,--scheduler shceduling-method:指定调度算法,调度算法可以指定以下8种:rr,wrr,lc,wlc,lblc,lblcr,dh,sh,sed,nq

-p,--persistent [timeout]:设置持久连接,这个模式可以使来自客户的多个请求被送到同一个真实服务器,通常用于ftp或者ssl中。

-M,--netmask netmask:指定客户地址子网掩码,用于将同属一个子网的客户请求转发到同一服务器。

-r,--real-server server-address:为虚拟服务指定数据可以转发到的真实服务器地址,可以添加端口号,如果没有指定端口号,则等效于使用虚拟地址的端口号。

[packet-forwarding-method]:此选项指定某个真实服务器所使用的数据转发模式。需要对每个诊室服务期分别指定模式。

-g,--gatewaying:使用网关(即直接路由),此模式是默认模式

-i,--ipip:使用ipip隧道模式

-m,--masquerading:使用NAT模式

-w,--weight weight:设置权重,权重是0-65535的整数,如果将某个真实服务器的权重设置为0,那么它不会受到新的连接,但是已有连接还会继续维持

-x,--u-threshold uthreshold:设置一个服务器连接下限,当服务器的连接数低于此值得时候服务器才可以重新接收连接。如果此值未设置,则当服务器的连接数连续 三次低于uthreshold时服务器才可以接收到新的连接。(ps:笔者认为此设置可能是为了防止服务器在能否接收连接这两个状态上频繁变换)

--mcast-interface interface:指定使用备服务器时候的广播接口。

--syncid syncid:指定syncid,同样用于主备服务器的同步

以下选项用于list命令

/*
		-c,--connection:列出当前的ipvs连接
    --timeout:列出超时
    --daemon:
    --stats:状态信息
    --rate:传输速率
    --thresholds:列出阈值
    --persistent-conn:坚持连接
    --sor:把列表排序
    --nosort:不排序
    -n,--numeric:不对ip地址进行dns查询
    --exact:单位
    -6:如果fwmark用的是ipv6地址需要指定此选项
    其他注意事项:
    1、如果使用IPv6地址,需要在地址两端加上[],例如:ipvsadm -A -t [2001:db8::80]:80 -s rr
*/

Lvs-nat部署

拓扑说明:为了便于测试实验部署,这里直接采用Clinent和Director相连的方式,实际生产环境肯定比这复杂,但是这个图也能掩饰除lvs-nat模型的调度效果.

按照上面拓扑图准备环境后,还需要做其他环境准备:

/*
		1)关闭Director、RealServer的防火墙(避免写iptables规则)
    2)RealServer的网关需要指向10.0.0.3(Director的DIP)
    3)在Director调度器上面开启核心转发功能,/etc/sysctl.conf文件中添加一行
    net.ipv4.ip_forward=1 并执行sysctl -p
*/
在RealServer上部署Web服务

这里只是简单模拟了web服务,以便我们能够看出lvs的效果

[root@3 ~]# rpm -ivh nginx-1.16.0-1.el7.ngx.x86_64.rpm 
[root@3 ~]# echo 3 > /usr/share/nginx/html/index.html 
[root@3 ~]# nginx

[root@5 ~]# rpm -ivh nginx-1.16.0-1.el7.ngx.x86_64.rpm 
[root@5 ~]# echo 5 > /usr/share/nginx/html/index.html 
[root@5 ~]# nginx
在Director上部署lvs服务
[root@43 ~]# yum -y install ipvsadm

[root@43 ~]# ipvsadm -A -t 192.168.43.43:80 -s rr
[root@43 ~]# ipvsadm -a -t 192.168.43.43:80 -r 172.18.80.3:80 -m
[root@43 ~]# ipvsadm -a -t 192.168.43.43:80 -r 172.18.80.5:80 -m

# -A 添加一个集群服务
# -E 修改一个集群服务
# -t 使用tcp协议
# -u 使用udp协议
# -f 使用防火墙标记
# -s 使用哪种集群算法
# -p 是否启用持久连接


[root@43 ~]# ipvsadm-save -n > /etc/sysconfig/ipvsadm
# ipvsadm-save  保存规则  恢复规则

# ipvsadm -C 清空所有规则
# 但不清楚以保存在/etc/sysconfig/ipvsadm中的规则,以及自定义保存的规则。

[root@43 ~]# systemctl start ipvsadm && systemctl enable ipvsadm


# 查看类命令
ipvsadm -L|l [ -n ] [--rate] [--stats] [--timeout] [-c]
	    -L|l:显示目前系统中创建的集群
            -n:以数字显示端口
            -c:显示连接信息状态
            --rate:显示速率
            --stats:显示统计信息
        eg:ipvsadm -Lc 显示连接信息状态

            ipvsadm -L -n --stats  显示统计信息
客户端访问测试

在客户端上访问vip,看访问的情况,从下面的访问情况,我们可以看到请求被轮询的方式分别调度到了RealServer1和RealServer2

[root@web219 ~]# curl  192.168.43.43 
5
[root@web219 ~]# curl  192.168.43.43 
3
[root@web219 ~]# curl  192.168.43.43 
5
[root@web219 ~]# curl  192.168.43.43 
3

Lvs-DR部署

在LVS-DR模型中,DIP和RIP与VIP可以在相同网段,可以在不同网段

下面这张图是DIP和RIP与VIP网段相同的情况,部署方法同上面一样,只是网络配置有一些差异

环境准备

按照上面拓扑图搭建好网络,个人实验可以全部用虚拟机代替,包括router,注意在Router和Director上开启核心转发功能,编辑/etc/sysctl.conf文件添加net.ipv4.ip_forward=1然后执行sysctl -p命令生效.

配置vip
ifconfig ens32:0 192.168.43.100 netmask 255.255.255.255
route add -host 192.168.43.100 dev ens32:0
Director配置lvs
[root@43 ~]# yum -y install ipvsadm

[root@43 ~]# ipvsadm -At 192.168.43.100:80 -s rr

[root@43 ~]# ipvsadm -at 192.168.43.100:80 -r 192.168.43.215:80 -g
[root@43 ~]# ipvsadm -at 192.168.43.100:80 -r 192.168.43.86:80 -g

[root@43 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.43.100:80 rr
  -> 192.168.43.86:80             Route   1      0          0         
  -> 192.168.43.215:80            Route   1      0          0    
    
[root@43 ~]# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  43:http rr
  -> 192.168.43.86:http           Route   1      0          0         
  -> 192.168.43.215:http          Route   1      0          0  
配置RealServer
[root@215 ~]# ifconfig lo:0 192.168.43.100 netmask 255.255.255.255 broadcast 192.168.43.100
[root@215 ~]# route add -host 192.168.43.100 dev lo:0
[root@215 ~]# echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore 
[root@215 ~]# 
[root@215 ~]# echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce 
[root@215 ~]# 
[root@215 ~]# echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore 
[root@215 ~]# 
[root@215 ~]# echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce



[root@web86 ~]# ifconfig lo:0 192.168.43.100 netmask 255.255.255.255 broadcast 192.168.43.100
[root@web86 ~]# 
[root@web86 ~]# route add -host 192.168.43.100 dev lo:0
[root@web86 ~]# echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore 
[root@web86 ~]# echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce 
[root@web86 ~]# echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore 
[root@web86 ~]# echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
客户端访问测试
[root@web219 ~]# curl 192.168.43.100
5
[root@web219 ~]# curl 192.168.43.100
86
[root@web219 ~]# curl 192.168.43.100
5
[root@web219 ~]# curl 192.168.43.100
86

Lvs负载+Keepalived高可用

LVS负载均衡的实验我在上几篇文章中已经做了简单介绍,包括LVS的nat模型和dr模型,以及lvs的基本概念,这边文章主要讲解lvs配合keepalived实现director调度器的高可靠,keepalived的实现原理就是利用了计算机网络中的VRRP(虚拟网络冗余协议)技术,其本身是为了解决网关单点故障的问题,如下图右上部分,两台Director设备通过心跳来维持一个向外开放虚拟IP,这里也就是192.168.43.100,LVS集群向外提供服务器的地址,这个地址只能同时存在一个设备上,当其中一台设备故障,心跳丢失,虚IP就会漂移到BACKUP设备上,从而接管业务继续调度。

拓扑图

拓扑说明:图中keepalived_master和keepalived_slave设备就是来演示Director调度器的高可靠,RealServer1和RealServer2来模拟后端真实的web服务

环境准备

按照上面拓扑图,搭建好网络环境,并按照图示在每台设备商配置好相应的IP地址,保证各个设备间通信正常,两台Keepalived设备只需要配置好DIP和GW即可,其他配置下面步骤做.

配置Lvs-dr

参考上面...

安装,配置lvs,keepalived

配置lvsmaster

# lvs的master和slave都安装
yum install -y keepalived ipvsadm

# 修改master配置
[root@lvs_master ~]# cat /etc/keepalived/keepalived.conf 
! Configuration File for keepalived

global_defs {
#   notification_email {
#     acassen@firewall.loc
#     failover@firewall.loc
#     sysadmin@firewall.loc
#   }
#   notification_email_from Alexandre.Cassen@firewall.loc
#   smtp_server 192.168.200.1
#   smtp_connect_timeout 30
   router_id LVS_DEVEL
}

vrrp_instance VI_1 {
    state MASTER                  #设置角色为MASTER
    interface ens33               #浮动IP绑定在哪个接口
    virtual_router_id 51          #虚拟路由器的ID,这个需要和Slave保持一致
    priority 150                  #设置该设备的优先级为150,此值需要高于Master
    advert_int 1                  #这个为两台设备的心跳间隔时间
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.43.100:80              #配置LVS集群虚IP     
    }
}

virtual_server 192.168.43.100 80 {  #配置Director调度器
    delay_loop 6
    lb_algo rr                    #配置Director调度器
    lb_kind DR                    #分发模型
    nat_mask 255.255.255.0
    persistence_timeout 0
    protocol TCP                  #使用传输层的协议

    real_server 192.168.43.215 80 {     #RealServer地址+端口
        weight 1                  #调度权重
        TCP_CHECK {
            connect_timeout 3
            retry 3
            delay_before_retry 3
      connect_port 80
        }
    }
    real_server 192.168.43.86 80 {     #RealServer地址+端口
        weight 1                  #调度权重
        TCP_CHECK {
            connect_timeout 3
            retry 3
            delay_before_retry 3
      connect_port 80
        }
    }
}

lvs_slave

[root@lvs_slave ~]# cat /etc/keepalived/keepalived.conf 
! Configuration File for keepalived

global_defs {
#   notification_email {
#     acassen@firewall.loc
#     failover@firewall.loc
#     sysadmin@firewall.loc
#   }
#   notification_email_from Alexandre.Cassen@firewall.loc
#   smtp_server 192.168.200.1
#   smtp_connect_timeout 30
   router_id LVS_DEVEL
}

vrrp_instance VI_1 {
    state BACKUP					#设置角色为BACKUP,即为我文中提到的Slave
    interface ens33				#浮动IP绑定在那个接口
    virtual_router_id 51  #虚拟路由器的ID,这个需要和Master保持一致
    priority 149					#设置该设备的优先级为149,此值需要低于Master
    advert_int 1					#这个为两台设备的心跳间隔时间
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        172.16.0.100			#配置LVS集群虚IP
    }
}

virtual_server 192.168.43.100 80  {		#配置Director调度器
    delay_loop 6
    lb_algo rr											#调度算法
    lb_kind DR											#分发模型
    nat_mask 255.255.255.0
    persistence_timeout 0
    protocol TCP										#传输层协议

    real_server 192.168.43.215 80 {				配置
        weight 1
        TCP_CHECK {
            connect_timeout 3
            retry 3
            delay_before_retry 3
            connect_port 80
        }
    }
    real_server 192.168.43.86 80 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            retry 3
            delay_before_retry 3
	    connect_port 80
        }
    }
}
启动服务
systemctl start keepalived
posted @ 2020-06-21 20:15  常见-youmen  阅读(711)  评论(0编辑  收藏  举报