说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

【问底】许鹏:使用Spark+Cassandra打造高性能数据分析平台(二)

HTML文档下载 WORD文档下载 PDF文档下载
Spark,强大的迭代计算框架,内存计算上无可匹敌。Cassandra,优异的列式存储NoSQL,在写入上难逢敌手。《问底》Spark+Cassandra高性能数据分析平台打造进入第二部分,本文主要探讨spark-cassandra-connector。

【导读】笔者( 许鹏)看Spark源码的时间不长,记笔记的初衷只是为了不至于日后遗忘。在源码阅读的过程中秉持着一种非常简单的思维模式,就是努力去寻找一条贯穿全局的主线索。在笔者看来,Spark中的线索就是如何让数据的处理在分布式计算环境下是高效,并且可靠的。

在对Spark内部实现有了一定了解之后,当然希望将其应用到实际的工程实践中,这时候会面临许多新的挑战,比如选取哪个作为数据仓库,是HBase、MongoDB还是Cassandra。即便一旦选定之后,在实践过程还会遇到许多意想不到的问题。

要想快速的解决开发及上线过程中遇到的系列问题,还需要具备相当深度的Linux知识,恰巧之前工作中使用Linux的经验在大数据领域中还可以充分使用。

笔者不才,就遇到的一些问题,整理出来与诸君共同分享。下文为本系列文章的第二部分(点击访问本系列文章开篇):

Cassandra高并发数据读取实现剖析

本文就spark-cassandra-connector的一些实现细节进行探讨,主要集中于如何快速将大量的数据从Cassandra中读取到本地内存或磁盘。

数据分区

存储在Cassandra中的数据一般都会比较多,记录数在千万级别或上亿级别是常见的事。如何将这些表中的内容快速加载到本地内存就是一个非常现实的问题。

解决这一挑战的思路从大的方面来说是比较简单的,那就是将整张表中的内容分成不同的区域,然后分区加载,不同的分区可以在不同的线程或进程中加载,利用并行化来减少整体加载时间。

顺着这一思路出发,要问的问题就是Cassandra中的数据如何才能分成不同的区域。

不同于MySQL,在Cassandra中是不存在Sequence Id这样的类型的,也就是说无法简单的使用seqId来指定查询或加载的数据范围。

既然没有SequenceID,在Cassandra中是否就没有办法了呢?答案显然是否定的,如果只是仅仅支持串行读取,Cassandra早就会被扔进垃圾桶了。

数据分区在Cassandra中至少可以通过两种途径实现 ,一是通过token range,另一个是slice range。这里主要讲解利用token range来实现目的。

1. Token Range

Cassandra将要存储的记录存储在不同的区域中,判断某一记录具体存储在哪个区域的依据是partition key的Hash值。 

在Cassandra 1.2之前,组成Cassandra集群的所有节点(Node),都需要手动指定该节点的Hash值范围也就是Token Range。

手工计算Token Range显然是很繁琐,同时也不怎么容易维护,在Cassandra 1.2之后,引进了虚拟节点(vnode)的概念,主要目的是减少不必要的人工指定,同时也将token range的划分变得更为细粒度。比如原先手工指定token range,只能达到10000这样一个精度,而有了vnode之后,默认安装是每一个物理节点上有256个虚拟节点,这样子的话每一个range的范围就是10000/256,这样变的更为精细。

有关token range的信息存储在cassandra的system命名空间(keyspace)下的local和peers两张表中。其中local表示本节点的token range情况,而peers表示集群中其它节点的token range情况。这两张表中的tokens字段就存储有详细的信息。如果集群中只由一台机器组成,那么peers中的就会什么内容都没有。

简单实验,列出本节点的token range:

use system;desc table local;select tokens from local;
2. Thrift接口

Token Range告诉我们Cassandra的记录是分片存储的,也就意味着可以分片读取。现在的问题转换成为如何知道每一个Token Range的起止范围。

Cassandra支持的Thrift接口中describe_ring就是用来获取token range的具体起止范围的。我们常用的nodetool工具使用的就是thrift接口,nodetool 中有一个describering指令使用的就是describe_ring原语。

可以做一个简单的实验,利用nodetool来查看某个keyspace的token range具体情况。

nodetool -hcassandra_server_addr describering keyspacename

注意将cassandra_server和keyspacename换成实际的内容。

Spark-Cassandra-Connector

在第一节中讲解了Cassandra中Token Range信息的存储位置,以及可以使用哪些API来获取token range信息。

接下来就分析spark-cassandra-connector是如何以cassandra为数据源将数据加载进内存的。

以简单的查询语句为例,假设用户要从demo这个keyspace的tableX表中加载所有数据,用CQL来表述就是:

select * from demo.tableX
上述的查询使用spark-cassandra-connector来表述就是:

sc.cassandraTable(“demo”,”tableX”)

尽管上述语句没有触发Spark Job的提交,也就是说并不会将数据直正的从Cassandra的tableX表中加载进来,但spark-cassandra-connector还是需要进行一些数据库的操作。要解决的主要问题就是schema相关。

cassandraTable(“demo”,”tableX”)只是说要从tableX中加载数据,并没有告诉connector有哪些字段,每个字段的类型是什么。这些信息对后面使用诸如get[String](“fieldX”)来说却是非常关键的。

为了获取字段类型信息的元数据,需要读取system.schema_columns表,利用如下语句可以得到schema_columns表结构的详细信息:

desc table system.schema_columns
如果在conf/log4j.properties中将日志级别设置为DEBUG,然后再执行sc.cassandraTable语句就可以看到具体的CQL查询语句是什么。

1. CassandraRDDPartitioner

Spark-cassandra-connector添加了一种新的RDD实现,即CassandraRDD。我们知道对于一个Spark RDD来说,非常关键的就是确定getPartitions和compute函数。

getPartitions函数会调用CassandraRDDPartitioner来获取分区数目:

override def getPartitions: Array[Partition] = {    verify // let's fail fast    val tf = TokenFactory.forCassandraPartitioner(cassandraPartitionerClassName)    val partitions = new CassandraRDDPartitioner(connector, tableDef, splitSize)(tf).partitions(where)    logDebug(s"Created total ${partitions.size} partitions for $keyspaceName.$tableName.")    logTrace("Partitions: \n" + partitions.mkString("\n"))    partitions  }
CassandraRDDPartitioner中的partitions的处理逻辑大致如下:

  1. 首先确定token range,使用describe_ring
  2. 然后根据Cassandra中使用的Partitioner来确定某一个token range中可能的记录条数,这么做的原因就是为进一步控制加载的数据,提高并发度。否则并发度就永远是256了,比如有一个物理节点,其中有256个vnodes,也就是256个token分区。如果每个分区中大致的记录数是20000,而每次加载最大只允许1000的话,整个数据就可以分成256x2=512个分区。
  3. 对describeRing返回的token range进一步拆分的话,需要使用splitter,splitter的构建需要根据keyspace中使用了何种Partitioner来决定,Cassandra中默认的Partitioner是Murmur3Partitioner,Murmur3Hash算法可以让Hash值更为均匀的分布到不同节点。
  4. splitter中会利用到配置项spark.cassandra.input.split.size和spark.cassandra.page.row.size,分别表示一个线程最多读取多少记录,另一个表示每次读取多少行。

partitions的源码详见CasssandraRDDParitioner.scala

compute函数就利用确定的token的起止范围来加载内容,这里在理解的时候需要引起注意的就是flatMap是惰性执行的,也就是说只有在真正需要值的时候才会被执行,延迟触发。

数据真正的加载是发生在fetchTokenRange函数,这时使用到的就是Cassandra Java Driver了,平淡无奇。

2. fetchTokenRange

fetcchTokenRange函数使用Cassandra Java Driver提供的API接口来读取数据,利用Java API读取数据一般遵循以下步骤:

val cluster = ClusterBuilder.addContactPoint(“xx.xx.xx.xx”).buildval session = cluster.connectval stmt = new SimpleStatement(queryCQL)session.execute(session)session.closecluster.close

addContactPoint的参数是cassandra server的ip地址,在后面真正执行cql语句的时候,如果集群有多个节点构成,那么不同的cql就会在不同的节点上执行,自动实现了负载均衡。可以在addContactPoint的参数中设定多个节点的地址,这样可以防止某一节点挂掉,无法获取集群信息的情况发生。

session是线程安全的,在不同的线程使用同一个session是没有问题的,建议针对一个keySpace只使用一个session。

3. RDD中使用Session

在Spark RDD中是无法使用SparkContext的,否则会形成RDD嵌套的现象,因为利用SparkContext很容易构造出RDD,如果在RDD的函数中如map中调用SparkContext创建一个新的RDD,则形成深度嵌套进而导致Spark Job有嵌套。

但在实际的情况下,我们需要根据RDD中的值再去对数据库进行操作,那么有什么办法来打开数据库连接呢?

解决的办法就是直接使用Cassandra Java Driver而不再使用spark-cassandra-connector的高级封装,因为不能像这样子来使用cassandraRDD。

sc.cassandraRDD(“ks”,”tableX”).map(x=>sc.cassandraRDD(“ks”,”tableX”).where(filter))
如果是直接使用Cassandra Java Driver,为了避免每个RDD中的iterator都需要打开一个session,那么可以使用foreachPartition函数来进行操作,减少打开的session数。

val  rdd1 = sc.cassandraTable(“keyspace”,”tableX”)	rdd1.foreachPartition( lst => {		val cluster = ClusterBuilder.addContactPoint(“xx.xx.xx.xx”).build		val session = cluster.connect		while ( iter.hasNext ) {		 	val  elem = iter.next			//do something by using session and elem		}		session.close		cluster.close	})

其实最好的办法是在外面建立一个session,然后在不同的partition中使用同一个session,但这种方法不行的原因是在执行的时候会需要”Task not Serializable”的错误,于是只有在foreachPartition函数内部新建session。

数据备份

尽管Cassandra号称可以做到宕机时间为零,但为了谨慎起见,还是需要对数据进行备份。

Cassandra提供了几种备份的方法

  1. 将数据导出成为json格式
  2. 利用copy将数据导出为csv格式
  3. 直接复制sstable文件

导出成为json或csv格式,当表中的记录非常多的时候,这显然不是一个好的选择。于是就只剩下备份sstable文件了。

问题是将sstable存储到哪里呢?放到HDFS当然没有问题,那有没有可能对放到HDFS上的sstable直接进行读取呢,在没有经过任务修改的情况下,这是不行的。

试想一下,sstable的文件会被拆分为多个块而存储到HDFS中,这样会破坏记录的完整性,HDFS在存储的时候并不知道某一block中包含有完成的记录信息。

为了做到记录信息不会被拆分到多个block中,需要根据sstable的格式自行提取信息,并将其存储到HDFS上。这样存储之后的文件就可以被并行访问。

Cassandra中提供了工具sstablesplit来将大的sstable分割成为小的文件。

DataStax的DSE企业版中提供了和Hadoop及Spark的紧密结合,其一个很大的基础就是先将sstable的内容存储到CFS中,大体的思路与刚才提及的应该差不多。

对sstable存储结构的分析是一个研究的热门,可以参考如下的链接。

  • https://www.fullcontact.com/blog/cassandra-sstables-offline/

之所以要研究备份策略是想将对数据的分析部分与业务部分相分离开,避免由于后台的数据分析导致Cassandra集群响应变得缓慢而致前台业务不可用,即将OLTP和OLAP的数据源分离开。

通过近乎实时的数据备份,后台OLAP就可以使用Spark来对数据进行分析和处理。

高级查询 Cassandra+Solr

与传统的RDBMS相比,Cassandra所能提供的查询功能实在是弱的可以,如果想到实现非常复杂的查询功能的,需要将Cassandra和Solr进行结合。

DSE企业版提供了该功能,如果想手工搭建的话,可以参考下面的链接:

  1. http://www.slideshare.net/planetcassandra/an-introduction-to-distributed-search-with-cassandra-and-solr 
  2. https://github.com/Stratio/stratio-cassandra开源方面的尝试 Cassandra和Lucene的结合

共享SparkContext

SparkContext可以被多个线程使用,这意味着同个Spark Application中的Job可以同时提交到Spark Cluster中,减少了整体的等待时间。

在同一个线程中, Spark只能逐个提交Job,当Job在执行的时候,Driver Application中的提交线程是处于等待状态的。如果Job A没有执行完,Job B就无法提交到集群,就更不要提分配资源真正执行了。

那么如何来减少等待时间呢,比如在读取Cassandra数据的过程中,需要从两个不同的表中读取数据,一种办法就是先读取完成表A与读取表B,总的耗时是两者之和。

如果利用共享SparkContext的技术,在不同的线程中去读取,则耗时只是两者之间的最大值。

在Scala中有多种不同的方式来实现多线程,现仅以Future为例来说明问题:

val ll  = (1 to 3 toList).map(x=>sc.makeRDD(1 to 100000 toList, 3))val futures = ll.map ( x => Future {		x.count()	})val fl = Future.sequencce(futures)Await.result(fl,3600 seconds)

  1. 简要说明一下代码逻辑
  2. 创建三个不同的RDD
  3. 在不同的线程(Future)中通过count函数来提交Job
  4. 使用Await来等待Future执行结束

更多《问底》内容

  • 【问底】严澜:数据挖掘入门(一)——分词
  • 【问底】Yao Yu谈Twitter的百TB级Redis缓存实践
  • 【问底】王帅:深入PHP内核(一)——弱类型变量原理探究 
  • 【问底】王帅:深入PHP内核(二)——SAPI探究
  • 【问底】王帅:深入PHP内核(三)——内核利器哈希表与哈希碰撞攻击
  • 【问底】静行:FastJSON实现详解
  • 【问底】李平:大型网站的灵魂——性能
  • 【问底】许鹏:使用Spark+Cassandra打造高性能数据分析平台(一)
  • 【问底】许鹏:使用Spark+Cassandra打造高性能数据分析平台(二)
  • 【问底】徐汉彬:大规模网站架构的缓存机制和几何分形学
  • 【问底】徐汉彬:亿级Web系统搭建——单机到分布式集群
《问底》是CSDN云计算频道新建栏目,以实践为本,分享个人对于新时代软件架构与研发的深刻见解。在含有“【问底】”字样标题的文章中,你会看到某个国外IT巨头的架构分享,会看到国内资深工程师对某个技术的实践总结,更会看到一系列关于某个新技术的探索。《问底》邀请对技术具有独特/深刻见解的你一起打造一片只属于技术的天空,详情可邮件至zhonghao@csdn.net。

CSDN诚邀您参加中国大数据有奖大调查活动,只需回答23个问题就有机会获得最高价值2700元的大奖(共10个), 速度参与进来吧!

第八届中国大数据技术大会(Big Data Technology Conference 2014,BDTC 2014)将于2014年12月12日-14日在北京新云南皇冠假日酒店召开。传承自2008年,历经七届沉淀,“中国大数据技术大会”是目前国内最具影响、规模最大的大数据领域技术盛会。本届会议,你不仅可以了解到Apache Hadoop提交者Uma Maheswara Rao G(兼项目管理委员会成员)、Yi Liu,以及Apache Hadoop和Tez项目管理委员会成员Bikas Saha等分享的通用大数据开源项目的最新成果和发展趋势,还将斩获来自腾讯、阿里、Cloudera、LinkedIn、网易等机构的数十场干货分享。 门票限时折扣中, 预购从速。


免费订阅“CSDN大数据”微信公众号,实时了解最新的大数据进展!

CSDN大数据,专注大数据资讯、技术和经验的分享和讨论,提供Hadoop、Spark、Impala、Storm、HBase、MongoDB、Solr、机器学习、智能算法等相关大数据观点,大数据技术,大数据平台,大数据实践,大数据产业资讯等服务。

比较两个文件-VB资料 采用递归算法删除带有多级子目录的目录-VB资料 菜单项的动态装入 -VB资料 处理加了密码的MDB文件-VB资料 VB创建临时文件 从公共对话框控件中提取多个文件名称 -VB资料 从全路径名中提取文件名 -VB资料 打印MsChart之类的控件 -VB资料 谈谈在VB6.0中如何使用资源文件进行编程 动画图像分解在VB动画设计中的应用 多重文档界面设计方法-VB资料 恢复回收站中的文件 -VB资料 VB获得位图文件的信息 VB获得文本框中光标所在行的内容 VB获取程序工作路径的方法 VB获取文件或文件夹属性 基于VB的通用折行打印程序 基于VB和EXCEL的报表设计及打印 VB建立多级目录 -VB资料 VB建立快捷方式-VB资料 VB建立文件关联 -VB资料 将RichTextBox 之中被选取的内容复制到剪贴簿-VB资料 将我的程序的文本直接送到WORD中(不用粘贴)-VB资料 开启文件属性窗口 -VB资料 快速读取 TextBox 第 N 行的资料 -VB资料 快速选择里List全部项目-VB资料 VB利用 App.Path 读取「应用程序所在之目录」 VB利用 EM_LINESCROLL 信息控制 TextBox 的卷动。 命名的技巧 -VB资料 目录所占的字节数-VB资料 VB判断文件是否在IE的缓存中 高分求助!请问怎么去掉IE的最大化和最小化按钮!! 关于UltraDev中浏览的问题???? 请大家推荐几本vc与汇编混和编程的好书 为什么会这样呢?关不掉的对话框 菜鸟提问:Form 与 Frame 有何区别? 以下是Delphi帮助的说明,谁能帮忙解释一下? 流星花园 我在image的click()方法里定义的变量,为什么在image_dblclick()里不能用?? 请教一下:金山词霸的屏幕取单词,是如何用程序实现的? 用VC怎么实现生成一个虚拟目录? 那位朋友有2000命令行模式下命令操作的帮助手册? IIS虚拟主机的问题,请大家给解决呀! 一个有关ListCtrl中拖动Column的问题。 请问那位大虾有用vc开发openssl的经验和原码? 兄弟我想学习数据库 但学什么好呐 给点意见 急求:将savedialog中多选的文件一次全都添进listview 谁有DirectX开发(SDK),给我一份,或留个连接地址 谁有DirectX开发(SDK),给我一份,或留个连接地址 怎样动态生成函数??? 你好!请问怎样给分? 高分debug!!!!!!! 再加50分请各位高手帮忙:http://www.csdn.net/expert/topic/598/598527.xml?temp=.1428339 请问各位,这种问题如何解决? from now , I'll come here usuauly 为什么邮件的接受时间会超前?高手请进来看看。 请大家推荐几本vc与汇编混和编程的好书 from now ,I 'll often come here. 请问: 中文版的 。NET 如何英文化????????????????? 高分debug!!!!!!! 怎样用vc编出来的程序能够隐藏起来,就象任务管理器那样 如何得到Query1->SQL->Add(select sum(xxx) from Table);的返回值? 谁能告诉我,这样得到的IPaddress 仅是本地dns解析的, 关于getdlgitem的问题? 如何得到登陆到服务器上的所有机器IP地址?????? 怎么样用C#在WEB页上画图形? 谁能告诉我,这样得到的IPaddress 是否仅是本地dns解析的? 请大家推荐几本vc与汇编混和编程的好书,请注明是哪个出版社出版 老问题:一个关于DLL输出函数的问题? 关于Win2K启动时程序自动加载的问题 Win2K里面输入法顺序调整的问题 同时有16个客户端从服务器端用FTP下载文件,但失败率很高,请问是什么问题 问大家一个C语言的教科书问题,谢谢了! 请高手明天,有关于JBUILDER6在XP下安装的问题 SOS ADO数据库中的varBinary字段的存取 TStream 怎么样改变标题颜色(不准用控件) 难道adaptive server anywhere6.0不支持中文吗? 我的窗口怎么处理不了方向键消息? 这是不是CArray的BUG?????????????? 关于如何修改历史记录文件夹属性的问题,,特急!!!!!!!!! 系统存储器和扩展存储器都在内存条上,是不是? 数据流传输的TNMStrm和TNMStrmServ组件和TNMUDP控件有什么不同啊? 在oracle如何这么做? 苹果3gs手机怎样设置重力感应?请知道的告诉我, 分母一定,分子和分数值成正比例. 把4改写成以千分之一为单位的数是( ),减少100个这样的计数单位后是( ),最低位是( ). 人坐在凳子上,人受的重力和人受到凳子的支持力 为什么不是二力平衡? 求教第五题判断题 0.9改写成千分之一为单位是()这是他与原数相比是()他的计数单位变() 蚕豆怎么做 分子一定,分母与分数值.能成正比例吗?并说说原因. 判断:一质点在某段时间内做曲线运动,则在这段时间内加速度一定不断改变. 弹力和摩擦力的方向一定互相垂直么拜托各位了 3Q 芥菜和盖菜的区别 牛顿每千克是不是加速度的国际单位 摩擦力与弹力的方向一定垂直吗?rt 芥菜和芥兰菜有什么区别? 一质点在某时间段内做曲线运动,在这段时间内为什么速度一定在不断的改变,而加速度可以不变 你听说过著名的牛顿万有引力定律吗?任何两个物体之间都有吸引力.如果设两个物体的质量分别为m1,m2,它们之间的距离是d,那么它们之间的引力就是f=gm1m2/d的平方(g为常数).人在地面上所 需要什么原料,具体步骤是什么, "牛顿"这个单位是计量什么的? 摩擦力的大小和什么有关 牛顿万有引力定律的作用都说牛顿发现了万有引力的定律那么他的这一发现对人类有什么好处?万有引力这一定律的用处是什么? 梅菜和雪里红有什么区别呀? 摩擦力大小与什么有关是初三的内容 不考虑什么最大静摩擦摩擦力大小跟什么有关 ?滑动摩擦力大小又和什么有关? 判断题.一个分数的分母不变,分子加上2,分数值就扩大2倍.对还是错,为什么 小白菜和大头菜有什么区别? 在讲高一物理时,滑动摩擦力和接触面的粗糙程度以用压力有关时,是直接给出公式好,还是从实验中得出来好呢?和接触面积无关倒是从一小个例子就可以得出来了,但要说和接触面粗糙程度以 一个数的分子不变,分母缩小2倍,这个分数值缩小2倍,还是扩大2倍,还是大小不变 如果x=九分之y,x和y成不成正比例,为什么 分数的分子一定,分母与分数值成不成正比例,为什么 牛顿的生活故事! 需要什么原料,具体步骤是什么, 怎样做`黄焖猪肉`?``` . 当人体缺碘时,甲状腺激素的合成量减少,甲状腺因此逐渐萎缩。 2.胰能分泌分解蛋白质的酶,也能分泌胰岛素。但胰岛素是由分布在胰腺细胞合成和分 为什么有摩擦力一定要有正压力(弹力)? 需要什么原料,具体步骤是什么, 物体受到在一条直线上大小分别为3N和5N的同方向的两个力的作用,则这个物体所受到的合力大小为--- 关于弹力和摩擦力,下列说法中正确的是() A.两物体间的摩擦力和压力方向一定互相垂直B.两物体间的摩擦力大小与它们间的弹力大小无关C.物体间的摩擦力大小跟接触面积有关D.物体间有弹 0.09的计数单位是 素烧蚕豆怎么做?需要什么原料,具体步骤是什么,谢谢 压力、推力、弹力、摩擦力的本质为什么是电场力?首先,一楼的,不要不懂装懂,再就是三楼四楼,可以思考一下,电磁力,电磁作用的本质还是电场力。 0.09的计数单位是多少 有两个力,一个为3N一个为5N他们的合力大小可能为? 一个最简分数,如果把分子扩大到原来的5倍,分母缩小到原来的6分之1,就变成了14,求原来的分数是多少? 曲线运动是变速运动,因为做曲线运动的物体速度方向在时刻改变, 需要什么原料,具体步骤是什么, 一个最简分数分子扩大5倍,分母缩小2倍得4又6分之1求这个分数是多少 曲线运动是变速运动,加速度一定变化吗 两个大小分别为2N和3N的力,同时作用在质量为1Kg的物体上,物体产生加速度的值是?是0到5N吗 一个最简分数,把它的分子扩大到原来的2倍,分母缩小为原来的2分之1后是2分之1,这个分数是多少?写出计算步骤.学过方程. 牛顿单位换算,我没学过,希望能详细点. 滑动摩擦力中,摩擦力方向与其物体弹力方向有什么关系吗?是永远相互垂直吗?摩擦力方向与其物体弹力方向有什么关系 是否相互垂直 如果不是请举例 机械振动如何测量 平抛运动加速度方向时刻改变是匀变速曲线运动我们把加速度(或合外力)恒定的运动称为“匀变速运动”,把加速度(大小或方向或两者同时)变化的运动称为“变加速运动”.我混乱了 滑动摩擦力的方向与物体间弹力的方向垂直 分子一定 分数值和分母 能否成正比例要用这种格式 例如:圆的周长和直径周长和直径是相关联的量 周长随着直径变化而变化 周长÷直径=π(一定)所以周长和直径成正比例 质量牛顿 单位换算 两物体间弹力方向与摩擦力方向一定垂直,这话正确? 分子一定,分数值与分母成正比例.( ) (是对的还是错的) 做匀变速曲线运动的物体 随着时间的延续 变小 为什么 可以画一个图吗 判断题, 分子一定,分母和分数值,成正比例吗 求伽利略 哥白尼 开普勒 托勒密的天文学观点的不同处和相同处 还有最好能附上他们的观点模型图 和一些如果图片或资料来源于网站的话求地址 如果找到资料了直接给地址也行
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘