华人澳洲中文论坛

热图推荐

    Linux 后盾开发必知的 I/O 优化常识总结

    [复制链接]

    2022-8-6 15:26:14 18 0

    来自:SegmentFault,作者:维子 链接:http://segmentfault.com/a/十一90000021388785


    IO机能关于一个零碎的影响是相当首要的。一个零碎通过多项优化当前,瓶颈往往落在数据库;而数据库通过多种优化当前,瓶颈终究会落到IO。而IO机能的开展,显著后进于CPU的开展。Memchached也好,NoSql也好,这些盛行技术的面前都在间接或者直接地躲避IO瓶颈,从而进步零碎机能 一、IO 零碎的分层


    上图档次对比多,但总的就是三部份。磁盘(存储)、VM(卷办理)和文件零碎。专着名词欠好了解,打个比喻说:磁盘就至关于一块待用的旷地;LVM至关于旷地上的围墙(把旷地划分红多个部份);文件零碎则至关于每块旷地上建的楼房(抉择了有多少房间、屋宇编号如何,能包容多少人住);而房子外面住的人,则至关于零碎外面存的数据。 1.1 文件零碎—数据如何寄放? 对应了上图的File System和Buffer Cache。 File System(文件零碎):解决了空间办理的问题,即:数据如何寄放、读取。 Buffer Cache:解决数据缓冲的问题。对读,进行cache,即:缓存常常要用到的数据;对写,进行buffer,缓冲一定数据当前,一次性进行写入。 1.2 VM—磁盘空间缺乏了怎么办? 对应上图的Vol Mgmt。 VM其实跟IO没有必定分割。他是处于文件零碎和磁盘(存储)两头的一层。VM屏蔽了底层磁盘对下层文件零碎的影响。当没有VM的时分,文件零碎间接使用存储上的地址空间,因此文件零碎间接受限于物理硬盘,这时候假如产生磁盘空间缺乏的状况,对运用而言将是一场恶梦,不能不新增硬盘,而后从新进行数据复制。而VM则能够完成静态扩展,而对文件零碎没有影响。此外,VM也能够把多个磁盘合并成一个磁盘,对文件零碎呈现一致的地址空间,这个特性的杀伤力显而易见。 1.3 存储—数据放在哪儿?如何拜候?如何进步IO速度? 对应上图的Device Driver、IO Channel和Disk Device 数据终究会放在这里,因此,效力、数据平安、容灾是这里需求斟酌的问题。而进步存储的机能,则能够间接进步物理IO的机能。 1.4 Logical IO vs Physical IO 逻辑IO是操作零碎发动的IO,这个数据可能会放在磁盘上,也可能会放在内存(文件零碎的Cache)里。 物理IO是装备驱动发动的IO,这个数据终究会落在磁盘上。 逻辑IO和物理IO不是一一对应的。 二、IO 模型 这部份的货色在网络编程常常能看到,不外在一切IO处置中都是相似的。 2.1 IO申请的两个阶段 等候资源阶段:IO申请个别需求申请特殊的资源(如磁盘、RAM、文件),当资源被上一个使用者使用没有被释放时,IO申请就会被梗阻,直到可以使用这个资源。 使用资源阶段:真正进行数据接纳和产生。
    2.2 在等候数据阶段,IO分为梗阻IO和非梗阻IO。
    梗阻IO:资源不成历时,IO申请始终梗阻,直到反馈后果(无数据或超时)。 非梗阻IO:资源不成历时,IO申请分开前往,前往数据标识资源不成用
    2.3 在使用资源阶段,IO分为同步IO和异步IO。
    同步IO:运用梗阻在发送或接纳数据的形态,直到数据胜利传输或前往失败。 异步IO:运用发送或接纳数据后立刻前往,数据写入OS缓存,由OS实现数据发送或接纳,并前往胜利或失败的信息给运用。


      2.4 根据Unix的5个IO模型划分
    梗阻IO
    非梗阻IO
    IO复用
    信号驱动的IO
    异步IO
    从机能上看,异步IO的机能无疑是最佳的。


    文件零碎各有不同,其最次要的指标就是解决磁盘空间的办理问题,同时提供高效性、平安性。假如在散布式环境下,则有相应的散布式文件零碎。Linux上有ext系列,Windows上有Fat和NTFS。如图为一个linux下文件零碎的构造。 其中VFS(Virtual File System)是Linux Kernel文件零碎的一个模块,简略看就是一个Adapter,对下屏蔽了上层不同文件零碎之间的差别,对上为操作零碎提供了一致的接口. 两头部份为各个不同文件零碎的完成。 再往下是Buffer Cache和Driver。


    各种文件零碎完成形式不同,因此机能、办理性、牢靠性等也有所不同。上面为Linux Ext2(Ext3)的一个大抵文件零碎的构造。


    Boot Block寄放了疏导顺序。 Super Block寄放了全部文件零碎的一些全局参数,如:卷名、形态、块大小、块总数。他在文件零碎被mount时读入内存,在umount时被释放。


    上图形容了Ext2文件零碎中很首要的三个数据构造和他们之间的瓜葛。 Inode:Inode是文件零碎中最首要的一个构造。如图,他外面记载了文件相干的一切信息,也就是咱们常说的meta信息。包罗:文件类型、权限、一切者、大小、atime等。Inode外面也保留了指向实际文件内容信息的索引。其中这类索引分几类:
    间接索引:间接指向实际内容信息,私有十二个。因此假如,一个文件零碎block size为1k,那末间接索引到的内容最大为十二k直接索引两级直接索引三级直接索引如图:


    Directory代表了文件零碎中的目录,包罗了以后目录中的一切Inode信息。其中每行只要两个信息,一个是文件名,一个是其对应的Inode。需求留意,Directory不是文件零碎中的一个特殊构造,他实际上也是一个文件,有本人的Inode,而它的文件内容信息外面,包罗了下面看到的那些文件名和Inode的对应瓜葛。如下图:


    Data Block即寄放文件的时间内容块。Data Block大小必需为磁盘的数据块大小的整数倍,磁盘个别为5十二字节,因此Data Block个别为1K、2K、4K。 Buffer & Cache 虽然Buffer和Cache放在一同了,然而在实际过程当中Buffer和Cache是彻底不同了。Buffer个别关于写而言,也叫“缓冲区”,缓冲使很多个小的数据块可以合并成一个大数据块,一次性写入;Cache个别关于读并且,也叫“缓存”,防止频繁的磁盘读取。如图为Linux的free命令,其中也是把Buffer和Cache进行区别,这两部份都算在了free的内存。


    Buffer Cache Buffer Cache中的缓存,实质与一切的缓存都是同样,数据构造也是相似,下图为VxSF的一个Buffer Cache构造。


    这个数据构造与memcached和Oracle SGA的buffer何等类似。左边的hash chain实现数据块的寻址,上方的的链表记载了数据块的形态。
    Buffer vs Direct I/O 文件零碎的Buffer和Cache在某些状况下的确进步了速度,然而反之也会带来一些负面影响。一方面文件零碎减少了一个两头层,此外一方面,当Cache使用不妥、配置欠好或者有些业务无奈获得cache带来的益处时,cache则成了一种担负。 合适Cache的业务:串行的大数据量业务,如:NFS、FTP。 不合适Cache的业务:随机IO的业务。如:Oracle,小文件读取。 块装备、字符装备、裸装备 这几个货色看得很晕,找了一些材料也没有找到很精确的阐明。 从硬件装备的角度来看,
    块装备就是以块(好比磁盘扇区)为单位收发数据的装备,它们反对缓冲和随机拜候(不用程序读取块,而是能够在任什么时候候拜候任何块)等特性。块装备包罗硬盘、CD-ROM 和 RAM 盘。字符装备则没有能够进行物理寻址的媒体。字符装备包罗串行端口和磁带装备,只能逐字符地读取这些装备中的数据。从操作零碎的角度看(对应操作零碎的装备文件类型的b和c),# ls -l /dev/*lv  brw------- 1 root system 22, 2 May 15 2007 lv  crw------- 2 root system 22, 2 May 15 2007 rlv块装备能反对缓冲和随机读写。即读取和写入时,能够是恣意长度的数据。最小为1byte。对块装备,你能够胜利履行以下命令:dd if=/dev/zero of=/dev/vg01/lv bs=1 count=1。即:在装备中写入一个字节。硬件装备是不反对这样的操作的(最小是5十二),这个时分,操作零碎首先实现一个读取(如1K,操作零碎最小的读写单位,为硬件装备反对的数据块的整数倍),再更改这1k上的数据,而后写入装备。
    字符装备只能反对固定长度数据的读取和写入,这里的长度就是操作零碎能反对的最小读写单位,如1K,所以块装备的缓冲功用,这里就没有了,需求使用者本人来实现。因为读写时不通过任何缓冲区,此时履行dd if=/dev/zero of=/dev/vg01/lv bs=1 count=1,这个命令将会犯错,由于这里的bs(block size)过小,零碎无奈反对。假如履行dd if=/dev/zero of=/dev/vg01/lv bs=1024 count=1,则能够胜利。这里的block size有OS内核参数抉择。
    如上,比拟之下,字符装备在使用更加间接,而块装备更加灵敏。文件零碎个别建设在块装备上,而为了寻求高机能,使用字符装备则是更好的选择,如Oracle的裸装备使用。


    CIO就是为理解决这个问题。 并且CIO带来的机能进步直逼裸装备。 当文件零碎反对CIO并开启CIO时,CIO默许会开启文件零碎的Direct IO,即: 让IO操作不通过Buffer间接进行底层数据操作。 因为不通过数据Buffer,在文件零碎层面就无需斟酌数据统一性的问题,因此,读写操作能够并行履行。
    在终究进行数据存储的时分,一切操作都会串行履行,CIO把这个事件交个了底层的driver。


    LVM(逻辑卷办理),位于操作零碎和硬盘之间,LVM屏蔽了底层硬盘带来的繁杂性。 最简略的,LVM使得N块硬盘在O S看来成为一块硬盘,大大进步了零碎可用性。
    LVM的引入,使得文件零碎和底层磁盘之间的瓜葛变得更加灵敏,并且更便利瓜葛。LVM有下列特征:
    一致进行磁盘办理。按需调配空间,提供静态扩展。条带化(Striped)镜像(mirrored)快照(snapshot)LVM能够做静态磁盘扩展,想一想看,当零碎办理员发现运用空间缺乏时,敲两个命令就实现空间扩展,估量做梦都要笑醒:) LVM的磁盘办理形式


    L VM中有几个很首要的概念:
    PV(physical volume):物理卷。在LVM中,一个PV对应就是操作零碎能看见的一块物理磁盘,或者由存储装备调配操作零碎的lun。一块磁盘独一对应一个PV,PV创立当前,阐明这块空间能够归入到LVM的办理。创立PV时,能够指定PV大小,便可以把全部磁盘的部份归入PV,而不是整个磁盘。这点在外表上看没有甚么意义,然而假如主机前面接的是存储装备的话就颇有意义了,由于存储装备调配的lun是能够静态扩展的,只要当PV能够静态扩展,这类扩展性能力向上延长。VG(volume group):卷组。一个VG是多个PV的聚拢,简略说就是一个VG就是一个磁盘资源池。VG对上屏蔽了多个物理磁盘,下层是使历时只需斟酌空间大小的问题,而VG解决的空间的如安在多个PV上延续的问题。LV(logical volume):逻辑卷。LV是终究可供使用卷,LV在VG中创立,有了VG,LV创立是只需斟酌空间大小等问题,对LV而言,他看到的是始终分割的地址空间,不必斟酌多块硬盘的问题。有了下面三个,LVM把单个的磁盘笼统成为了一组延续的、可随便调配的地址空间。除下面三个概念外,还有一些其余概念:PE(physical extend): 物理扩展块。LVM在创立PV,不会按字节形式去进行空间办理。而是按PE为单位。PE为空间办理的最小单位。即:假如一个1024M的物理盘,LVM的PE为4M,那末LVM办理空间时,会根据256个PE去办理。调配时,也是根据调配了多少PE、残余多少PE斟酌。LE(logical extend):逻辑扩展块。相似PV,LE是创立LV斟酌,当LV需求静态扩展时,每次最小的扩展单位。关于下面几个概念,无需刻意去记住,当你需求做这么一个货色时,这些概念是天然而然的。PV把物理硬盘转换成LVM中关于的逻辑(解决如何办理物理硬盘的问题),VG是PV的聚拢(解决如何组合PV的问题),LV是VG上空间的再划分(解决如何给OS使用空间的问题);而PE、LE则是空间调配时的单位。


    如图,为两块18G的磁盘组成为了一个36G的VG。 此VG上划分了3个LV。 其PE和LE都为4M。 其中LV1只用到了sda的空间,而LV2和LV3使用到了两块磁盘。
    串连、条带化、镜像


    串连(Concatenation): 按程序使用磁盘,一个磁盘使用完当前使用后续的磁盘。 条带化(Striping): 交替使用不同磁盘的空间。条带化使得IO操作能够并行,因此是进步IO机能的症结。此外,Striping也是RAID的根底。如:VG有2个PV,LV做了条带数量为2的条带化,条带大小为8K,那末当OS发动一个16K的写操作时,那末恰好这2个PV对应的磁盘能够对全部写入操作进行并行写入。


    Striping带来益处有: 并发进行数据处置。读写操作能够同时发送在多个磁盘上,大大进步了机能。 Striping带来的问题:
    数据残缺性的危险。Striping致使一份残缺的数据被散布到多个磁盘上,任何一个磁盘上的数据都是不残缺,也无奈进行复原。一个条带的毁坏会致使一切数据的生效。因此这个问题只能经过存储装备来补救。条带大小的设定很大水平抉择了Striping带来的益处。假如条带设置过大,一个IO操作终究仍是产生在一个磁盘上,无奈带来并行的益处;当条带设置国小,原本一次并行IO能够实现的事件会终究致使了屡次并行IO。镜像(mirror) 犹如名字。LVM提供LV镜像的功用。即当一个LV进行IO操作时,相反的操作产生在此外一个LV上。这样的功用为数据的平安性提供了反对。如图,一份数据被同时写入两个不同的PV。


    使用mirror时,能够获取一些益处:
    读取操作能够从两个磁盘上获得,因此读效力会更好些。数据残缺繁杂了一份,平安性更高。然而,伴有也存在一些问题:一切的写操作都会同时发送在两个磁盘上,因此实际发送的IO是申请IO的2倍因为写操作在两个磁盘上产生,因此一些残缺的写操作需求两边都实现了才算实现,带来了额定担负。在处置串行IO时,有些IO走一个磁盘,此外一些IO走此外的磁盘,一个残缺的IO申请会被打乱,LVM需求进行IO数据的合并,能力提供应下层。像一些如预读的功用,因为有了多个数据获得同道,也会存在额定的担负。


    快照如其名,他保留了某一时间点磁盘的形态,然后续数据的变动不会影响快照,因此,快照是一种备份很好伎俩。 然而快照因为保留了某一时间点数据的形态,因此在数据变动时,这部份数据需求写到其余中央,跟着而往返带来一些问题。对于这块,后续存储也波及到相似的问题,前面再说。 这部份值得一说的是多门路问题。IO部份的高可用性在全部运用零碎中能够说是最症结的,运用层能够坏掉一两台机器没有问题,然而假如IO欠亨了,全部零碎都没法使用。如图为一个典型的SAN网络,从主机到磁盘,一切门路上都提供了冗余,以备产生通路间断的状况。


    如上图构造,因为存在两条门路,关于存储划分的一个空间,在OS端会看到两个(两块磁盘或者两个lun)。可怕的是,OS其实不知道这两个货色对应的实际上是一块空间,假如门路再多,则OS会看到更多。仍是那句经典的话,“计算机中碰到的问题,往往能够经过减少的一个两头层来解决”,因而有了多门路软件。他提供了下列特性:
    把多个映照到同一块空间的门路合并为一个提供应主机提供fail over的反对。当一条通路泛起问题时,及时切换到其余通路提供load balance的反对。即同时使用多条门路进行数据传送,发扬多门路的资源劣势,进步零碎总体带宽。Fail over的才能个别OS也可能反对,而load balance则需求与存储配合,所以需求按照存储不同配置装置不同的多通路软件。 多门路除理解决了高可用性,同时,多条门路也能够同时任务,进步零碎机能。 Raid很根底,然而在存储零碎中占领十分首要的位置,一切波及存储的书籍都会提到RAID。RAID经过磁盘冗余的形式进步了可用性和可高性,一方面减少了数据读写速度,另外一方面减少了数据的平安性。 RAID 0 对数据进行条带化。使用两个磁盘交替寄放延续数据。因此能够完成并发读写,但带来的问题是假如一个磁盘毁坏,此外一个磁盘的数据将失去意义。RAID 0至少需求2块盘。


    RAID 1 对数据进行镜像。数据写入时,相反的数据同时写入两块盘。因此两个盘的数据彻底统一,假如一块盘毁坏,此外一块盘能够顶替使用,RAID 1带来了很好的牢靠性。同时读的时分,数据能够从两个盘上进行读取。然而RAID 1带来的问题就是空间的挥霍。两块盘只提供了一块盘的空间。RAID 1至少需求2块盘。


    RAID 5 使用过剩的一块校验盘。数据写入时,RAID 5需求对数据进行计算,以便得出校验位。因此,在写机能上RAID 5会有损失。然而RAID 5统筹了机能和平安性。当有一块磁盘毁坏时,RAID 5能够经过其余盘上的数据对其进行恢复。


    如图能够看出,右下角为p的就是校验数据。能够看到RAID 5的校验数据挨次散布在不同的盘上,这样能够防止泛起热点盘(由于一切写操作和更新操作都需求修正校验信息,假如校验都在一个盘做,会致使这个盘成为写瓶颈,从而拖累总体机能,RAID 4的问题)。RAID 5至少需求3块盘。 RAID 6


    RAID 6与RAID 5相似。然而提供了两块校验盘(下图右下角为p和q的)。平安性更高,写机能更差了。RAID 0至少需求4块盘。
    RAID 10(Striped mirror) RAID 10是RAID 0 和RAID 1的结合,同时统筹了两者的特征,提供了高机能,然而同时空间使用也是最大。RAID 10至少需求4块盘。 需求留意,使用RAID 10来称说其实很容易发生混杂,由于RAID 0+1和RAID 10根本上只是两个数字替换了一下地位,然而对RAID来讲就是两个不同的组成。因此,更易了解的形式是“Striped mirrors”,即:条带化后的镜像——RAID 10;或者“mirrored stripes”,即:镜像后的条带化。对比RAID 10和RAID 0+1,虽然终究都是用到了4块盘,然而在数据组织上有所不同,从而带来问题。RAID 10在可用性上是要高于RAID 0+1的:
    RAID 0+1 任何一块盘毁坏,将失去冗余。如图4块盘中,右边一组毁坏一块盘,左边一组毁坏一块盘,全部盘阵将无奈使用。而RAID 10摆布各毁坏一块盘,盘阵依然能够任务。RAID 0+1 毁坏后的恢复进程会更慢。由于先通过的mirror,所以摆布两组中保留的都是残缺的数据,数据恢复时,需求残缺恢复所以数据。而RAID 10由于先条带化,因此毁坏数据当前,恢复的只是本条带的数据。如图4块盘,数据少了一半。


    RAID 50
    RAID 50 同RAID 10,先做条带化当前,在做RAID 5。统筹机能,同时又包管空间的利用率。RAID 50至少需求6块盘。


    总结:
    RAID与LVM中的条带化原理上相似,只是完成层面不同。在存储上完成的RAID个别有专门的芯片来实现,因此速度上远比LVM块。也称硬RAID。
    如上引见,RAID的使用是有危险的,如RAID 0,一块盘毁坏会致使一切数据丧失。因此,在实际使用中,高机能环境会使用RAID 10,统筹机能和平安;个别状况下使用RAID 5(RAID 50),统筹空间利用率和机能;


    DAS:有PATA、SATA、SAS等,次要是磁盘数据传输协定。
    单台主机。在这类状况下,存储作为主机的一个或多个磁盘存在,这样局限性也是很显著的。因为受限于主机空间,一个主机只能装一块到几块硬盘,而硬盘空间时受限的,当磁盘满了当前,你不能不为主机改换更大空间的硬盘。
    独立存储空间。为理解决空间的问题,因而斟酌把磁盘独立出来,因而有了DAS(Direct Attached Storage),即:直连存储。DAS就是一组磁盘的聚拢体,数据读取和写入等也都是由主机来管制。然而,随之而来,DAS又面临了一个他无奈解决的问题——存储空间的同享。接某个主机的JBOD(Just a Bunch Of Disks,磁盘组),只能这个主机使用,其余主机无奈用。因此,假如DAS解决空间了,那末他无奈解决的就是假如让空间可以在多个机器同享。由于DAS能够了解为与磁盘交互,DAS处置问题的层面相对于更低。使用协定都是跟磁盘交互的协定
    独立的存储网络。为理解决同享的问题,鉴戒以太网的思想,因而有了SAN(Storage Area Network),即:存储网络。关于SAN网络,你能看到两个十分特征,一个就是光纤网络,另外一个是光纤替换机。SAN网络因为不会之间跟磁盘交互,他斟酌的更可能是数据存取的问题,因此使用的协定相对于DAS层面更高一些。光纤网络:关于存储来讲,与以太网很大的一个不同就是他对带宽的要求十分高,因此SAN网络下,光纤成了其衔接的根底。而其上的光纤协定比拟以太网协定而言,也被设计的更加简洁,机能也更高。光纤替换机:这个相似以太网,假如想要做到真实的“网络”,替换机是根底。
    网络文件零碎。存储空间能够同享,那文件也是能够同享的。NAS(Network attached storage)相对于下面两个,对待问题的层面更高,NAS是在文件零碎级别对待问题。因此他面的再也不是存储空间,而是单个的文件。因此,当NAS和SAN、DAS放在一同时,很容易惹起混杂。NAS从文件的层面斟酌同享,因此NAS相干协定都是文件管制协定。NAS解决的是文件同享的问题;SAN(DAS)解决的是存储空间的问题。NAS要处置的对象是文件;SAN(DAS)要处置的是磁盘。为NAS办事的主机必需是一个残缺的主机(有OS、有文件零碎,而存储则纷歧定有,由于能够他前面又接了一个SAN网络),他斟酌的是如安在各个主机间接高效的同享文件;为SAN提供办事的是存储装备(能够是个残缺的主机,也能够是部份),它斟酌的是数据怎么散布到不同磁盘。NAS使用的协定是管制文件的(即:对文件的读写等);SAN使用的协定是管制存储空间的(即:把多长的一串二进制写到某个地址)


    如图,对NAS、SAN、DAS的组成协定进行了划分,从这里也能很明晰的看出他们之间的差异。
    NAS:波及SMB协定、NFS协定,都是网络文件零碎的协定。 SAN:有FC、iSCSI、AOE,都是网络数据传输协定。 DAS:有PATA、SATA、SAS等,次要是磁盘数据传输协定。 从DAS到SAN,在到NAS,在不同层面对存储计划进行的增补,也能够看到一种从低级到初级的开展趋向。而当初咱们常看到一些散布式文件零碎(如hadoop等)、数据库的sharding等,从存储的角度来讲,则是在OS层面(运用)对数据进行存储。从这也能看到一种技术开展的趋向。 跑在以太网上的SAN SAN网络并非只能使用光纤和光纤协定,现在之所以使用FC,传输效力是一个很大的问题,然而以太网开展到明天被不停的完美、增强,带宽的问题也被不停的解决。因此,以太网上的SAN也许会成为一个趋向。


    如图两个FC的SAN网络,经过FCIP完成了两个SAN网络数据在IP网络上的传输。这个时分SAN网络仍是以FC协定为根底,仍是使用光纤。 iFCP 经过iFCP形式,SAN网络由FC的SAN网络演化为IP SAN网络,全部SAN网络都基于了IP形式。然而主机和存储间接使用的仍是FC协定。只是在接入SAN网络的时分经过iFCP进行了转换


    iSCSI iSCSI是对比主流的IP SAN的提供形式,并且其效力也失掉了认可。


    关于iSCSI,最首要的一点就是SCSI协定。SCSI(Small Computer Systems Interface)协定是计算机外部的一个通用协定。是一组规范集,它定义了与少量装备(次要是与存储相干的装备)通讯所需的接口和协定。如图,SCSI为block device drivers之下。


    从SCIS的分层来看,共分三层: 高层:提供了与OS各种装备之间的接口,完成把OS如:Linux的VFS申请转换为SCSI申请 两头层:完成高层和底层之间的转换,相似一个协定网关。 底层:实现于详细物理装备之间的交互,完成真实的数据处置。


    --- EOF ---

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    返回列表 本版积分规则

    :
    注册会员
    :
    论坛短信
    :
    未填写
    :
    未填写
    :
    未填写

    主题31

    帖子35

    积分169

    图文推荐