一种IndexR实时数据分析库的制作方法

文档序号:11386751阅读:326来源:国知局
本发明属于互联网
技术领域
:,尤其涉及一种indexr实时数据分析库。
背景技术
::程序化广告业务需要对接全网的各大媒体,每秒产生上百万的分析数据。这些数据对广告投放活动的过程进行了精细的追踪和描述,比如创意的展示量、点击量,活动产生的注册数、回访数等。我们需要对这些数据进行实时分析处理,用于包括客户报告,投放优化,欺诈分析,收费结算等。数据使用者的查询模式是非固定的,无法预测的,并且随着业务量的激增,数据量也急剧增长。我们需要一种新的技术来解决这些需求:1、超大数据集,低查询延时:查询模式无法预测,无法预计算;表数据量普遍超过1亿,甚至上百亿千亿,过滤条件有可能会命中大量数据;数据在查询的同时还会有大量的更新,每秒入库几万的数据。要保证较低的查询延时,一般情况下查询延时要求在5s以内,常用高频查询要求1s以内。2、准实时:数据从产生到体现在分析结果延时几秒以内。时效性对于某些业务至关重要,并且越实时的数据,价值越大。3、可靠性,一致性,高可用:这些数据是公司最重要的数据之一,任何错误和不一致可能会直接体现在客户报表中,对公司的业务和品牌形象产生影响,至关重要。4、可扩展,低成本,易维护:业务会快速发展,会产生新的数据源,加入新的表,旧的数据不能删除,这带来巨大的成本压力,和运维压力。典型的更新如加列、列值更新等操作不能影响线上服务,不能带来入库或者查询延迟。5、sql支持:全面支持sql,要像mysql一样好用,功能强大。不仅仅支持常见的多维分析,还需要支持复杂的分析查询,如join,子查询等,支持自定义函数(udf,udfa)。6、与hadoop生态整合:hadoop生态的蓬勃发展给大数据处理带来越来越强的处理能力,如果能与它的工具链深度结合,会极大扩展系统的价值。7、多维分析、ad-hoc查询:大部分的查询结果是基于一个或多个维度组合的汇总,并且要求短时间内响应,最好全面支持sql和udf。目前提供相似功能的产品,有些通过使用传统的关系型数据技术,或者通过预先建cube加速查询。这些方式可能会带来一些问题,比如运维困难,数据量瓶颈,或者模式不够灵活,无法支持业务变化。有些方案使用内存存储技术,使用上成本比较高,而且在大数据分析场景并无特别大的速度优势。近年出现的一些时序数据库,解决了一些入库延迟方面的问题,但是在查询性能,可用性,可扩展性等方面存在一些问题。现有的技术解决方案如mysql,postgresql等关系型数据库,它们一般都有非常完整的功能支持,但无法支持超大量数据,统计分析的性能也不好,一般作为t+1架构的实时库。hbase,或者redis等k-v数据库,上层一般有一个sql查询层,比如phoenix,上游由spark、storm等流式框架预聚合数据。这类架构限制非常多,很难支持复杂及频繁修改的业务。kylin也属于这一类,离线预聚合。infobright,greenplum,memsql等各有特点的数据库,有开源社区版本。在一定条件、数据量下能满足特定需求,但是缺点较多,有些不支持更新,或者运维困难,数据量支持小等。hana,vertica,以及云服务等收费数据库。我们没有选择这个方向,认为把分析系统构建在这类第三方封闭系统上,与目前现有数据工具的整合相对困难,担心对后续扩展、迁移的影响。最近几年较火的所谓时间序列数据库,代表为druid,pinot,influxdb等。笔者曾经比较深入的研究过,甚至在项目中有过部署,但最终认为都不适合。有些项目并不成熟,或者对硬件要求极高,缺少弹性,有些架构上有比较大的问题,实际应用时表现的非常不稳定。其他开源分析工具,如impala,drill,或者sparksql。它们一般专注于计算层,缺少一个合适的数据格式,并且它们通常是分析静态文件的,没法做到分析实时数据。目前的arquet,orc等数据格式通常有不错的扫描、压缩性能,但缺少有效的索引和必要的灵活性。技术实现要素:本发明的目的在于提供一种indexr实时数据分析库,以解决上述
背景技术
:中提出的问题。本发明的目的是通过下述技术方案予以实现:一种indexr实时数据分析库,包括:系统构架、部署架构、存储结构和实时模块;所述系统构架负责文件存储格式,包括索引和数据,数据的实时导入、表定义操作,查询优化,以及数据缓存等。分布式计算框架(drill/spark)负责在indexr数据上的具体查询操作,以及其他计算任务,hadoop以及周边工具-提供分布式文件存储,离线批量计算,离线数据管理,以及各种离线etl任务,indexr与hadoop完美结合,可以作为一个高度压缩、自带索引的文件格式,兼容hive的所有操作,kafka-消息队列,数据经过kafka流入indexr,zookeeper-集群状态管理;所述部署架构在hadoop系统的环境下,在现有集群上部署indexr通常可以在半小时之内完成,只需要在所有hadoop的datanode(和namenode)节点上部署一份带有indexr插件的drill节点,只有几项必须配置项,并且所有节点的配置都是一样的,indexr的服务逻辑嵌入了drillbit进程,无需额外启动服务;所述存储结构以列式存储数据,并分片存储,分片称为segment,每一个segment都是自解释的,包括schema,数据以及索引,segment通常是固定不变的,这极大简化了数据管理,便于分布式处理;所述实时模块可以极高效率的导入实时数据,并且数据可以立刻被查询,可以多节点同时导入,实时导入的数据叫做realtimesegment,在达到一定阀值后,indexr会将它们合并成历史segment,并上传到hdfs,之后数据就可以被离线分析工具所使用和管理,realtimesegment具体实现参考了lsm-tree,通过在磁盘上的commitlog文件保存所有更新操作,最新数据放在内存中以快速入库和索引,周期性将内存数据dump到磁盘,indexr进程可以随时被重启,或者直接杀死,不用担心数据丢失;进一步的,所述indexr实时数据分析库的测试硬件标准包括以下部分:1)每个节点12核(24线程)cpu,60g内存,sata接口7200转机械硬盘,2)实时导入速度:超过30k消息/秒/节点/表,即,假如有10个节点,每个节点拥有10个表,可以在一秒钟之内消费3m条消息,一天轻松实时导入千亿数据,3)扫描速度:通常一行内通常会读取多个字段,在现代cpu和计算框架的帮助下,可以同时对多个字段进行运算,从而获得比以下数据更好的性能,4)冷数据-30m字段/秒/节点,5)热数据-100m字段/秒/节点,6)扫描速度约为parquet的2.5倍,7)olap查询:在我们的实际业务中,我们发现95%的查询延时在3s内,数据量规模为千亿级别,20个节点,8)相同的drill环境下约为parquet格式的3~8倍,9)压缩率:在我们的实际业务中,相对于csv格式,压缩率约为10:1,有些表甚至达到20:1,10)压缩后大小约为orc格式的75%。本发明的有益效果是:1、快速统计分析查询:indexr使用列式存储,对于超大量数据集,它提供高效的索引,通过过滤掉无关数据,快速定位有效数据,减少io。它使用了优秀的apachdrill作为上层查询引擎。特别适合于ad-hoc的olap查询。2、数据实时导入:indexr支持超高速实时导入数据。数据一到达indexr节点,立刻可以被查询到。实时数据和历史数据可以一起查,再也不需要考虑所谓t+1架构。且区分于其他有类似功能的系统,indexr永远不会主动丢弃任何数据。3、高效硬件利用率:相较于其他系统,indexr可以跑在廉价的机器上。不需要昂贵的ssd硬盘,高端cpu,甚至小型机,你就可以获得非常好的性能,虽然在上面跑会更加快。虽然跑在jvm上,它手动管理几乎所有的内存,使用经过高度设计、紧凑的数据结构。4、集群高可用,易扩展,易管理,简单:分布式系统发展到现在,高可用和扩展性已经是标配了。indexr的特点是结构非常简单可靠,且只有极少的必须配置项。5、与hadoop生态的深度整合:indexr把数据存放于hdfs。这意味着你可以使用mapreduce,或者任何hadoop工具处理这些文件。我们目前提供了hive插件,用于各种etl相关工作,或者跑离线任务。对接spark的工作正在进行,将被使用于数据挖掘以及机器学习。6、高度压缩的数据格式:indexr以列式存储,并提供超高的压缩率,可以显著的减少io以及网络开销。7、方便的数据管理:indexr可以方便的导入、删除数据,并且支持修改表schema,如对列的添加、删除、修改等。具体实施方式具体实施例一种indexr实时数据分析库,包括:系统构架、部署架构、存储结构和实时模块;所述系统构架负责文件存储格式,包括索引和数据,数据的实时导入、表定义操作,查询优化,以及数据缓存等。分布式计算框架(drill/spark)负责在indexr数据上的具体查询操作,以及其他计算任务,hadoop以及周边工具-提供分布式文件存储,离线批量计算,离线数据管理,以及各种离线etl任务,indexr与hadoop完美结合,可以作为一个高度压缩、自带索引的文件格式,兼容hive的所有操作,kafka-消息队列,数据经过kafka流入indexr,zookeeper-集群状态管理;所述部署架构在hadoop系统的环境下,在现有集群上部署indexr通常可以在半小时之内完成,只需要在所有hadoop的datanode(和namenode)节点上部署一份带有indexr插件的drill节点,只有几项必须配置项,并且所有节点的配置都是一样的,indexr的服务逻辑嵌入了drillbit进程,无需额外启动服务;所述存储结构以列式存储数据,并分片存储,分片称为segment,每一个segment都是自解释的,包括schema,数据以及索引,segment通常是固定不变的,这极大简化了数据管理,便于分布式处理;所述实时模块可以极高效率的导入实时数据,并且数据可以立刻被查询,可以多节点同时导入,实时导入的数据叫做realtimesegment,在达到一定阀值后,indexr会将它们合并成历史segment,并上传到hdfs,之后数据就可以被离线分析工具所使用和管理,realtimesegment具体实现参考了lsm-tree,通过在磁盘上的commitlog文件保存所有更新操作,最新数据放在内存中以快速入库和索引,周期性将内存数据dump到磁盘,indexr进程可以随时被重启,或者直接杀死,不用担心数据丢失;所述indexr实时数据分析库的测试硬件标准包括以下部分:1)每个节点12核(24线程)cpu,60g内存,sata接口7200转机械硬盘,2)实时导入速度:超过30k消息/秒/节点/表,即,假如有10个节点,每个节点拥有10个表,可以在一秒钟之内消费3m条消息,一天轻松实时导入千亿数据,3)扫描速度:通常一行内通常会读取多个字段,在现代cpu和计算框架的帮助下,可以同时对多个字段进行运算,从而获得比以下数据更好的性能,4)冷数据-30m字段/秒/节点,5)热数据-100m字段/秒/节点,6)扫描速度约为parquet的2.5倍,7)olap查询:在我们的实际业务中,我们发现95%的查询延时在3s内,数据量规模为千亿级别,20个节点,8)相同的drill环境下约为parquet格式的3~8倍,9)压缩率:在我们的实际业务中,相对于csv格式,压缩率约为10:1,有些表甚至达到20:1,10)压缩后大小约为orc格式的75%。indexr存储结构化数据,比如以下是一个虚构的广告投放用户表tablea:columnnamedatatypedateintcontrystringcampaign_idlongimpressionslongclickslong数据文件称为segment,一个segment保存一个表的部分行,包含所有的列。segment文件是自解释的,它包含版本信息,完整的表定义,各个部分的元数据(offset),以及索引。indexr默认对所有的列进行索引。行顺序可以是入库的自然顺序,也可以是按照用户定义的字段排序。这样的设计可以简化系统架构,不需要额外的元数据存储,非常适合于分布式环境下的并行处理,也方便外部系统如hive直接使用。segment的行数据在内部会进一步细分为pack,每个pack都有独立的索引。pack内部的行数据是以列存储的,即某一列的数据会集中存放在一起。这种方式对于列数据的快速遍历,和压缩带来极大的优势。对于现代通用计算机架构,cache友好,方便vectorprocess,充分发挥现代多核cpu的性能。segment的列数据使用特别优化的压缩算法,根据数据类型选择不同的算法和参数,通常压缩率10:1以上。在实际业务数据测试中,indexr每个节点每秒可以处理1亿个字段。测试机器配置:[intel(r)xeon(r)cpue5-2620v2@2.10ghz]x2,60gram,sata7200rpmdisk。这个配置在目前服务器配置中算低端的,更强大的cpu会对indexr有非常大的性能提升。索引indexr采用粗糙集索引(roughsetindex),它能以极低的成本,很高的精确度定位到相关文件和位置。比如我们的某一个数据块(pack)有以下数据,有date(int类型)和use_name(string)类型。indexr对于number和string类型有不同的索引方式,这里描述基本的思路。对于number类型,会记录该列的最大值(max),最小值(min),然后把它们的区间(max-min)进行分割成多个区间,每一个区间使用一个bit表示。然后把各个具体的值映射到这个区间之中。bitindexchunkvalue020170101~201701021120170103~201701040220170105~201701060320170107~201701081420170109~201701101如上表,value值为1表示这个区间存在一行或者多行的数据,为0表示不存在。我们只需要存储max,min,和value序列(5个bit)就完成了对这一列的索引。比如查询selectuser_namefromawheredate='20170106'因为'20170106'属于区间2,value是0,即可以知道'20170106'不存在于这个pack,可以直接跳过。这是一种类似于bloomfilter的过滤方式,索引不命中的pack一定不包含需要的数据string类型的索引和number类似,不过更加复杂一点。目前常见的索引有b+树索引,倒排索引,这些索引可以精确定位到具体行,在相对小数据量情况下很有效。这种方式通常没有特别有效的压缩,数据文件大小一般在原始数据的1~3倍之间,当数据量膨胀到一定程度,这类索引的代价就会被放大,甚至无法服务。indexr的粗糙集索引的优势是非常快速,索引文件足够小,可以低成本的方式load到内存,在极大数据量场景下仍然能有效的工作。由于数据通常是排序的内聚的,通过实际数据的观察,列的值基数(cardinality)通常比较小,这种方式是可以有效的过滤掉无关的pack。它会对所有的列进行索引,非常适合于业务不固定,或者数据分析场景的探索型分析。实时入库indexr支持实时数据追加,但不支持数据在线更新,可以通过离线的方式使用hive等工具更新数据,这样的设计和mesa类似。它的入库速度非常快,通常单个节点单表可以达到30k消息/s。消息到达indexrnode之后,可以立刻被查询。indexr的实时入库模块使用类似lsm-tree的结构。使用commitlog文件保存消息,最新的数据存放于内存,在达到一定阀值之后会被写入硬盘。内存中的数据周期性的存储到硬盘,时间一久会产生较多碎片文件,这些文件在达到一定阀值之后,会被整理合并。行的存储顺序可以是自然入库顺序,也可以按照指定字段排序,类似于关系型数据库中的一级索引和hbase中的columnfamily,这样做可以让数据更加内聚,对于查询非常有利。类似于mesa,如果需要,indexr实时入库可以根据多维分析(multidimensionalanalysis)的概念,把字段分成维度(dimension)和指标(metric/measure),具有相同维度的行会合并到一起,指标使用聚合函数(aggregationfunction,e.g.sum,count),并且表之间可以设计成父子关系。tableb与tablec可以可以认为是tablea的子表。tablea拥有三个维度(date,country,campaign_id),可以表达最详细的信息。tableb与tablec通过减少维度,减少了数据量,可以更加快速的获得查询结果。应用层只需要做简单的表路由,比如selectdate,country,sum(impressions)frombwherecountry='cn'groupbydate,country可以路由到tableb表,快速获得结果。如果需要下钻(drilldown)查询,如selectcampaign_id,sum(impressions)fromawherecountry='cn'anddate='20170101'groupbycampaign_id则会路由到tablea。这种设计类似于关系型数据库中预聚合view。在olap领域,特别是多维分析场景,这种设计非常有效。架构设计indexr的架构设计遵循简单可靠、易扩展的原则。它可以大规模集群部署,支持上千个节点。事实上indexr的硬件成本相对来说很低,并且可以通过加节点线性扩展处理能力。apachedrill作为indexr的查询层。drill是一个全新的查询引擎,专注于sql计算,使用了代码生成技术,vectorprocess,列式计算,堆外内存(消除gc)等技术,有专门针对对于大数据集的优化。速度极快,并且支持标准sql,没有迁移负担。从我们的使用经验来看,它非常稳定,工程质量很高。indexr主要负责存储层,并且对具体的查询过程进行优化,比如常见的条件下推(predicatepushdown),limit下推等,未来还将支持聚合下推(aggregationpushdown)。indexr通过任务分配算法,结合数据距离、节点繁忙程度等,把计算任务分配到最合适的节点。hdfs存储具体的数据文件,分布式文件系统帮助构建节点无状态的服务。数据存放于hdfs中,可以方便的使用各种hadoop工具进行其他复杂分析。我们对接了hive,方便对数据进行离线处理。由于hdfs上的数据只有一份,可以同时被多个工具处理,省去了繁琐的同步步骤,在10:1的高压缩比上又节省一倍空间。数据经过kafka等队列高速导入indexr。indexr的实时导入非常灵活,可以随时增加或者删除导入节点。它拥有极高的导入性能(30k/s),入库延迟的压力成为历史。在indexr集群中只有一种节点(indexrnode),有利于部署和维护,不需要对节点进行划分。目前indexr作为drill插件嵌入了drillbit进程。indexr提供了indexr-tool工具,提供了完整的运维工具。比如可以在线更新表结构,在线添加、修改实时入库配置。工程实现的挑战算法和数据结构要真正落地,必须通过具体的工程来实现,而工程实现的质量决定了项目的最终效果。如果空有高超的设计图纸,而没有高质量的施工和合适的材料,高楼大厦是建不起来的。indexr在工程上最求极致的性能,但又不失灵活的扩展性。使用直接内存(directmemory))。indexr主要使用java8编写,而java的堆内存(heap)与垃圾回收(gc)的模式在大数据运算场景下面临比较大的挑战。在需要使用较大内存(超过32g)以及数据更新频繁时,jvm的gc问题比较明显,容易造成性能不稳定,并且对象实例的内存模型通常很浪费内存。我们在indexr项目中把所有的存储数据和运算临时数据存放于堆外,手动管理内存申请释放。这样提高了代码复杂度,但相比于传统的堆内存模式,节省了超过1/2内存,并且没有了gc代价,涉及大量数据的赋值操作通常可以使用内存拷贝,节省大量cpu循环。充分利用现代cpu能力。indexr的堆外内存模型对于充分发掘硬件潜能非常有益,它们通常是连续的内存块,没有类指针跳转,没有虚函数损耗,cpu寄存器和多级缓存都可以充分利用,而且对于使用vectorprocessor非常便利,没有结构转换开销。避免随机读取。通常磁盘的特点是连续读取非常快,因而kafka可以使用磁盘做消息队列;而随机读取相对很慢,故传统数据库的瓶颈一般在io。indexr的索引方式对磁盘连续读取友好,并且它会对数据进行整理从而更加内聚。我们还特别对文件读取方式进行了细致的优化。优化线程、io调度。在任务非常繁忙的时候,cpu争抢带来的线程切换的开销变的不可忽视。并且由于数据库环境的特殊性,在做繁忙cpu任务的同时,还会进行网络、io操作。如何做任务调度,合理安排线程数量和任务,对整体性能影响比较大。有时候单线程比多线程效率更高,并且更省资源。关键性能点使用c++实现。它在同时涉及内存操作和复杂cpu运算场景时,运行效率优势明显。我们把关键的性能点,比如压缩算法,使用c++实现。工具选型indexr是一个新的工具,如果你的项目有以下需求,或者之前已经有一些选型但是无法满足需求,可以考虑使用indexr。经典场景:需要在海量数据之上做快速的统计分析查询。要求入库速度非常快,并且需要实时分析。存放超大量历史明细数据库。比如网站浏览信息,交易信息,安保数据,电力行业数据,物联网设备采集数据等。这类数据通常量非常大,数据内容复杂,存放时间比较久,且希望在需要时可以比较快速的根据各种条件做明细查询,或者在一定范围内做复杂的分析。这种情况下可以充分发挥indexr的低成本,可扩展,适合超大数据集的优势。典型选型:使用mysql,postgresql等关系型数据库,不仅用于业务查询(oltp),也做统计分析,一般是在现有业务数据库上直接做一些分析需求。这种方式在数据量增长之后就会遇到性能问题,特别是分析查询会对业务查询产生极大影响。可以考虑把数据导入indexr做分析,即把业务数据库和分析数据库分开。es,solr等全文搜索数据库用于统计分析场景。这类数据库最大的特点是使用了倒排索引解决索引问题。对于统计分析场景通常没有特别优化,在大数据量场景下内存和磁盘压力比较大。如果遇到性能问题,或者数据量撑不住了,可以考虑使用indexr。druid,pinot等所谓时序数据库。在查询条件命中大量数据情况下可能会有性能问题,而且排序、聚合等能力普遍不太好,从我们的使用经验来看运维比较困难,灵活性和扩展性不够,比如缺乏join、子查询等。在保存大量历史数据情况下需要的硬件资源相对昂贵。这种场景下可以考虑使用indexr直接替换,不用担心业务实现问题。infobright,clickhose等列式数据库。列式数据库本身非常适合于olap场景,indexr也属于列式数据库。最大的区别在于indexr是基于hadoop生态的。离线预聚合,建cube,结果数据存放于hbase等kv数据库,如kylin等。这种方式在只有多维分析场景且查询比较简单的情况下非常有效。问题就在于灵活性不足(flexibility),无法探索式分析,以及更复杂的分析需求。indexr可以通过表配置达到预聚合的效果,并且聚合是实时,没有延迟的;可以保留原始数据或者高维度数据,通过表路由决定具体的查询表。为了解决大数据量的即时分析问题,上层使用impala,presto,sparksql,drill等计算引擎来做查询,存储层使用开源数据格式比如parquet,基于hadoop生态。这类架构和indexr很相似。indexr的优势在于更有效的索引设计,更好的性能,并且支持实时入库,秒级延迟。我们在相同环境下与parquet格式做过查询性能对比,indexr的查询速度提升在3~8倍以上。之后indexr经历了很大的性能优化,估计会有更好的表现。kudu,phoenix等既支持oltp场景,又为olap场景优化等开源产品。通常很难两者兼顾,建议分成实时库和历史库,针对不同数据特点采用不用的存储方案。内存数据库。飞科技大数据平台组对于以上提到的大部分技术选型有着丰富的经验,即这些工具我们或者在生成环境中使用过,或者有过深入的调研和测试,这也促使了indexr的诞生。本发明的有益效果是:1、快速统计分析查询:indexr使用列式存储,对于超大量数据集,它提供高效的索引,通过过滤掉无关数据,快速定位有效数据,减少io。它使用了优秀的apachdrill作为上层查询引擎。特别适合于ad-hoc的olap查询。2、数据实时导入:indexr支持超高速实时导入数据。数据一到达indexr节点,立刻可以被查询到。实时数据和历史数据可以一起查,再也不需要考虑所谓t+1架构。且区分于其他有类似功能的系统,indexr永远不会主动丢弃任何数据。3、高效硬件利用率:相较于其他系统,indexr可以跑在廉价的机器上。不需要昂贵的ssd硬盘,高端cpu,甚至小型机,你就可以获得非常好的性能,虽然在上面跑会更加快。虽然跑在jvm上,它手动管理几乎所有的内存,使用经过高度设计、紧凑的数据结构。4、集群高可用,易扩展,易管理,简单:分布式系统发展到现在,高可用和扩展性已经是标配了。indexr的特点是结构非常简单可靠,且只有极少的必须配置项。5、与hadoop生态的深度整合:indexr把数据存放于hdfs。这意味着你可以使用mapreduce,或者任何hadoop工具处理这些文件。我们目前提供了hive插件,用于各种etl相关工作,或者跑离线任务。对接spark的工作正在进行,将被使用于数据挖掘以及机器学习。6、高度压缩的数据格式:indexr以列式存储,并提供超高的压缩率,可以显著的减少io以及网络开销。7、方便的数据管理:indexr可以方便的导入、删除数据,并且支持修改表schema,如对列的添加、删除、修改等。对于本领域技术人员而言,显然本发明不限于上述示范性实施例的细节,而且在不背离本发明的精神或基本特征的情况下,能够以其他的具体形式实现本发明。因此,无论从哪一点来看,均应将实施例看作是示范性的,而且是非限制性的,本发明的范围由所附权利要求而不是上述说明限定,因此旨在将落在权利要求的等同要件的含义和范围内的所有变化囊括在本发明内。不应将权利要求中的任何附图标记视为限制所涉及的权利要求。此外,应当理解,虽然本说明书按照实施方式加以描述,但并非每个实施方式仅包含一个独立的技术方案,说明书的这种叙述方式仅仅是为清楚起见,本领域技术人员应当将说明书作为一个整体,各实施例中的技术方案也可以经适当组合,形成本领域技术人员可以理解的其他实施方式。当前第1页12当前第1页12
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1