牛逼之路

<转自> [http://www.hollischuang.com/archives/489](http://www.hollischuang.com/archives/489) # 一、基础篇 ## 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133 http://ifeve.com/jmm-faq/ 1.1.2. 了解JVM各种参数及调优 1.1.3. 学习使用Java工具 jps, jstack, jmap, jconsole, jinfo, jhat, javap, … http://kenai.com/projects/btrace http://www.crashub.org/ https://github.com/taobao/TProfiler https://github.com/CSUG/HouseMD http://wiki.cyclopsgroup.org/jmxterm https://github.com/jlusdy/TBJMap 1.1.4. 学习Java诊断工具 http://www.eclipse.org/mat/ http://visualvm.java.net/oqlhelp.html 1.1.5. 自己编写各种outofmemory,stackoverflow程序 HeapOutOfMemory Young OutOfMemory MethodArea OutOfMemory ConstantPool OutOfMemory DirectMemory OutOfMemory Stack OutOfMemory Stack OverFlow 1.1.6. 使用工具尝试解决以下问题,并写下总结 当一个Java程序响应很慢时如何查找问题 当一个Java程序频繁FullGC时如何解决问题,如何查看垃圾回收日志 当一个Java应用发生OutOfMemory时该如何解决,年轻代、年老代、永久代解决办法不同,导致原因也不同 1.1.7. 参考资料 http://docs.oracle.com/javase/specs/jvms/se7/html/ http://www.cs.umd.edu/~pugh/java/memoryModel/ http://gee.cs.oswego.edu/dl/jmm/cookbook.html 1.2. Java基础知识 1.2.1. 阅读源代码 java.lang.String java.lang.Integer java.lang.Long java.lang.Enum java.math.BigDecimal java.lang.ThreadLocal java.lang.ClassLoader & java.net.URLClassLoader java.util.ArrayList & java.util.LinkedList java.util.HashMap & java.util.LinkedHashMap & java.util.TreeMap java.util.HashSet & java.util.LinkedHashSet & java.util.TreeSet 1.2.2. 熟悉Java中各种变量类型 1.2.3. 熟悉Java String的使用,熟悉String的各种函数 1.2.4. 熟悉Java中各种关键字 1.2.5. 学会使用List,Map,Stack,Queue,Set 上述数据结构的遍历 上述数据结构的使用场景 Java实现对Array/List排序 java.uti.Arrays.sort() java.util.Collections.sort() Java实现对List去重 Java实现对List去重,并且需要保留数据原始的出现顺序 Java实现最近最少使用cache,用LinkedHashMap 1.2.6. Java IO&Java NIO,并学会使用 java.io.* java.nio.* nio和reactor设计模式 文件编码,字符集 1.2.7. Java反射与javassist 反射与工厂模式 java.lang.reflect.* 1.2.8. Java序列化 java.io. Serializable 什么是序列化,为什么序列化 序列化与单例模式 google序列化protobuf 1.2.9. 虚引用,弱引用,软引用 java.lang.ref.* 实验这些引用的回收 1.2.10. 熟悉Java系统属性 java.util.Properties 1.2.11. 熟悉Annotation用法 java.lang.annotation.* 1.2.12. JMS javax.jms.* 1.2.13. JMX java.lang.management.* javax.management.* 1.2.14. 泛型和继承,泛型和擦除 1.2.15. 自动拆箱装箱与字节码 1.2.16. 实现Callback 1.2.17. java.lang.Void类使用 1.2.18. Java Agent,premain函数 java.lang.instrument 1.2.19. 单元测试 Junit,http://junit.org/ Jmockit,https://code.google.com/p/jmockit/ djUnit,http://works.dgic.co.jp/djunit/ 1.2.20. Java实现通过正则表达式提取一段文本中的电子邮件,并将@替换为#输出 java.lang.util.regex.* 1.2.21. 学习使用常用的Java工具库 commons.lang, commons.*… guava-libraries 1.2.22. 什么是API&SPI http://en.wikipedia.org/wiki/Application_programming_interface http://en.wikipedia.org/wiki/Service_provider_interface 1.2.23. 参考资料 JDK src.zip 源代码 http://openjdk.java.net/ http://commons.apache.org/ https://code.google.com/p/guava-libraries/ http://netty.io/ http://stackoverflow.com/questions/2954372/difference-between-spi-and-api http://stackoverflow.com/questions/11404230/how-to-implement-the-api-spi-pattern-in-java 1.3. Java并发编程 1.3.1. 阅读源代码,并学会使用 java.lang.Thread java.lang.Runnable java.util.concurrent.Callable java.util.concurrent.locks.ReentrantLock java.util.concurrent.locks.ReentrantReadWriteLock java.util.concurrent.atomic.Atomic* java.util.concurrent.Semaphore java.util.concurrent.CountDownLatch java.util.concurrent.CyclicBarrier java.util.concurrent.ConcurrentHashMap java.util.concurrent.Executors 1.3.2. 学习使用线程池,自己设计线程池需要注意什么 1.3.3. 锁 什么是锁,锁的种类有哪些,每种锁有什么特点,适用场景是什么 在并发编程中锁的意义是什么 1.3.4. synchronized的作用是什么,synchronized和lock 1.3.5. sleep和wait 1.3.6. wait和notify 1.3.7. 写一个死锁的程序 1.3.8. 什么是守护线程,守护线程和非守护线程的区别以及用法 1.3.9. volatile关键字的理解 C++ volatile关键字和Java volatile关键字 happens-before语义 编译器指令重排和CPU指令重排 http://en.wikipedia.org/wiki/Memory_ordering http://en.wikipedia.org/wiki/Volatile_variable http://preshing.com/20130702/the-happens-before-relation/ 1.3.10. 以下代码是不是线程安全?为什么?如果为count加上volatile修饰是否能够做到线程安全?你觉得该怎么做是线程安全的? public class Sample { private static int count = 0; public static void increment() { count++; } } 1.3.11. 解释一下下面两段代码的差别 // 代码1 public class Sample { private static int count = 0; synchronized public static void increment() { count++; } } // 代码2 public class Sample { private static AtomicInteger count = new AtomicInteger(0); public static void increment() { count.getAndIncrement(); } } 1.3.12. 参考资料 http://book.douban.com/subject/10484692/ http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html #二、 进阶篇 2.1. Java底层知识 2.1.1. 学习了解字节码、class文件格式 http://en.wikipedia.org/wiki/Java_class_file http://en.wikipedia.org/wiki/Java_bytecode http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ http://asm.ow2.org/ 2.1.2. 写一个程序要求实现javap的功能(手工完成,不借助ASM等工具) 如Java源代码: public static void main(String[] args) { int i = 0; i += 1; i *= 1; System.out.println(i); } 编译后读取class文件输出以下代码: public static void main(java.lang.String[]); Code: Stack=2, Locals=2, Args_size=1 0: iconst_0 1: istore_1 2: iinc 1, 1 5: iload_1 6: iconst_1 7: imul 8: istore_1 9: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 12: iload_1 13: invokevirtual #3; //Method java/io/PrintStream.println:(I)V 16: return LineNumberTable: line 4: 0 line 5: 2 line 6: 5 line 7: 9 line 8: 16 2.1.3. CPU缓存,L1,L2,L3和伪共享 http://duartes.org/gustavo/blog/post/intel-cpu-caches/ http://mechanical-sympathy.blogspot.com/2011/07/false-sharing.html 2.1.4. 什么是尾递归 2.1.5. 熟悉位运算 用位运算实现加、减、乘、除、取余 2.1.6. 参考资料 http://book.douban.com/subject/1138768/ http://book.douban.com/subject/6522893/ http://en.wikipedia.org/wiki/Java_class_file http://en.wikipedia.org/wiki/Java_bytecode http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings 2.2. 设计模式 2.2.1. 实现AOP CGLIB和InvocationHandler的区别 http://cglib.sourceforge.net/ 动态代理模式 Javassist实现AOP http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ ASM实现AOP http://asm.ow2.org/ 2.2.2. 使用模板方法设计模式和策略设计模式实现IOC 2.2.3. 不用synchronized和lock,实现线程安全的单例模式 2.2.4. nio和reactor设计模式 2.2.5. 参考资料 http://asm.ow2.org/ http://cglib.sourceforge.net/ http://www.javassist.org/ 2.3. 网络编程知识 2.3.1. Java RMI,Socket,HttpClient 2.3.2. 用Java写一个简单的静态文件的HTTP服务器 实现客户端缓存功能,支持返回304 实现可并发下载一个文件 使用线程池处理客户端请求 使用nio处理客户端请求 支持简单的rewrite规则 上述功能在实现的时候需要满足“开闭原则” 2.3.3. 了解nginx和apache服务器的特性并搭建一个对应的服务器 http://nginx.org/ http://httpd.apache.org/ 2.3.4. 用Java实现FTP、SMTP协议 2.3.5. 什么是CDN?如果实现?DNS起到什么作用? 搭建一个DNS服务器 搭建一个 Squid 或 Apache Traffic Server 服务器 http://www.squid-cache.org/ http://trafficserver.apache.org/ http://en.wikipedia.org/wiki/Domain_Name_System 2.3.6. 参考资料 http://www.ietf.org/rfc/rfc2616.txt http://tools.ietf.org/rfc/rfc5321.txt http://en.wikipedia.org/wiki/Open/closed_principle 2.4. 框架知识 spring,spring mvc,阅读主要源码 ibatis,阅读主要源码 用spring和ibatis搭建java server 2.5. 应用服务器知识 熟悉使用jboss,https://www.jboss.org/overview/ 熟悉使用tomcat,http://tomcat.apache.org/ 熟悉使用jetty,http://www.eclipse.org/jetty/ # 三、 高级篇 3.1. 编译原理知识 3.1.1. 用Java实现以下表达式解析并返回结果(语法和Oracle中的select sysdate-1 from dual类似) sysdate sysdate - 1 sysdate - 1/24 sysdate - 1/(12*2) 3.1.2. 实现对一个List通过DSL筛选 QList<Map<String, Object>> mapList = new QList<Map<String, Object>>; mapList.add({"name": "hatter test"}); mapList.add({"id": -1,"name": "hatter test"}); mapList.add({"id": 0, "name": "hatter test"}); mapList.add({"id": 1, "name": "test test"}); mapList.add({"id": 2, "name": "hatter test"}); mapList.add({"id": 3, "name": "test hatter"}); mapList.query("id is not null and id > 0 and name like '%hatter%'"); 要求返回列表中匹配的对象,即最后两个对象; 3.1.3. 用Java实现以下程序(语法和变量作用域处理都和JavaScript类似): 代码: var a = 1; var b = 2; var c = function() { var a = 3; println(a); println(b); }; c(); println(a); println(b); 输出: 3 2 1 2 3.1.4. 参考资料 http://en.wikipedia.org/wiki/Abstract_syntax_tree https://javacc.java.net/ http://www.antlr.org/ 3.2. 操作系统知识 Ubuntu Centos 使用linux,熟悉shell脚本 3.3. 数据存储知识 3.3.1. 关系型数据库 MySQL 如何看执行计划 如何搭建MySQL主备 binlog是什么 Derby,H2,PostgreSQL SQLite 3.3.2. NoSQL Cache Redis Memcached Leveldb Bigtable HBase Cassandra Mongodb 图数据库 neo4j 3.3.3. 参考资料 http://db-engines.com/en/ranking http://redis.io/ https://code.google.com/p/leveldb/ http://hbase.apache.org/ http://cassandra.apache.org/ http://www.mongodb.org/ http://www.neo4j.org/ 3.4. 大数据知识 3.4.1. Zookeeper,在linux上部署zk 3.4.2. Solr,Lucene,ElasticSearch 在linux上部署solr,solrcloud,,新增、删除、查询索引 3.4.3. Storm,流式计算,了解Spark,S4 在linux上部署storm,用zookeeper做协调,运行storm hello world,local和remote模式运行调试storm topology。 3.4.4. Hadoop,离线计算 Hdfs:部署NameNode,SecondaryNameNode,DataNode,上传文件、打开文件、更改文件、删除文件 MapReduce:部署JobTracker,TaskTracker,编写mr job Hive:部署hive,书写hive sql,得到结果 Presto:类hive,不过比hive快,非常值得学习 3.4.5. 分布式日志收集flume,kafka,logstash 3.4.6. 数据挖掘,mahout 3.4.7. 参考资料 http://zookeeper.apache.org/ https://lucene.apache.org/solr/ https://github.com/nathanmarz/storm/wiki http://hadoop.apache.org/ http://prestodb.io/ http://flume.apache.org/,http://logstash.net/,http://kafka.apache.org/ http://mahout.apache.org/ 3.5. 网络安全知识 3.5.1. 什么是DES、AES 3.5.2. 什么是RSA、DSA 3.5.3. 什么是MD5,SHA1 3.5.4. 什么是SSL、TLS,为什么HTTPS相对比较安全 3.5.5. 什么是中间人攻击、如果避免中间人攻击 3.5.6. 什么是DOS、DDOS、CC攻击 3.5.7. 什么是CSRF攻击 3.5.8. 什么是CSS攻击 3.5.9. 什么是SQL注入攻击 3.5.10. 什么是Hash碰撞拒绝服务攻击 3.5.11. 了解并学习下面几种增强安全的技术 http://www.openauthentication.org/ HOTP http://www.ietf.org/rfc/rfc4226.txt TOTP http://tools.ietf.org/rfc/rfc6238.txt OCRA http://tools.ietf.org/rfc/rfc6287.txt http://en.wikipedia.org/wiki/Salt_(cryptography) 3.5.12. 用openssl签一个证书部署到apache或nginx 3.5.13. 参考资料 http://en.wikipedia.org/wiki/Cryptographic_hash_function http://en.wikipedia.org/wiki/Public-key_cryptography http://en.wikipedia.org/wiki/Transport_Layer_Security http://www.openssl.org/ https://code.google.com/p/google-authenticator/ #四、 扩展篇 4.1. 相关知识 4.1.1. 云计算,分布式,高可用,可扩展 4.1.2. 虚拟化 https://linuxcontainers.org/ http://www.linux-kvm.org/page/Main_Page http://www.xenproject.org/ https://www.docker.io/ 4.1.3. 监控 http://www.nagios.org/ http://ganglia.info/ 4.1.4. 负载均衡 http://www.linuxvirtualserver.org/ 4.1.5. 学习使用git https://github.com/ https://git.oschina.net/ 4.1.6. 学习使用maven http://maven.apache.org/ 4.1.7. 学习使用gradle http://www.gradle.org/ 4.1.8. 学习一个小语种语言 Groovy Scala LISP, Common LISP, Schema, Clojure R Julia Lua Ruby 4.1.9. 尝试了解编码的本质 五、 推荐书籍 《深入Java虚拟机》 《深入理解Java虚拟机》 《Effective Java》 《七周七语言》 《七周七数据》 《Hadoop技术内幕》 《Hbase In Action》 《Mahout In Action》 《这就是搜索引擎》 《Solr In Action》 《深入分析Java Web技术内幕》 《大型网站技术架构》 《高性能MySQL》 《算法导论》 《计算机程序设计艺术》 《代码大全》 《JavaScript权威指南》

flume与hive/impala配合使用时问题记录

工作中日志收集以及分析 通过Flume+hive/impala实现 期间遇到一些问题 记录:

问题一:

使用过程中时常会遇到.tmp文件无法找到的问题。
impala 查询时这个问题尤为严重。 hive查询时也会时常出现这个问题。
明白Flume写文件处理方式,以及hive/impala 数据查询时的实际处理方式,就能明白为什么会出现这些问题

  1. Flume日志写入操作时 会将正在写入的文件加上.tmp后缀。 当文件写入完成(一定时间没有写入/达到设置的阀值)时,会将./tmp文件重命名,去掉.tmp后缀
  2. Hive查询时是根据hive元数据库中的信息进行文件扫描,即对应map/reduce的输入。
  3. Impala共享hive的元数据

所以这时就会出现上面遇到的问题

  1. 如果Hive在执行过程中,恰好Flume对写入文件进行了重命名操作,即将xxx.tmp重命名为xxx,这时Hive会报错 .tmp找不到。。。
  2. impala这个错 更加平凡是因为impala同步hive元数据并不是实时操作,所以xxx.tmp被重命名掉的概率更大
处理办法:
  1. impala的简单解决办法 即手动同步元数据。 执行refresh 文件对应的表, 或者直接执行 invalidate metadata 刷新元数据

  2. hive的处理办法
    因为hdfs java api 读取HDFS文件时,会忽略以”.”和”_”开头的文件
    类似于Linux中.xx是隐藏的一样,所以应用程序读取HDFS文件时默认也不读取.xxx和_xxx这样名称的文件
    所以可以利用这一点 将Flume正在写入的.tmp文件设置为以‘.’开头,这样可以避免.tmp文件被读取到 Flume配置项:hdfs.inUsePrefix
    另一种解决办法 重写hive的PathFilter

     package com.willgo.util;
    	
     import java.io.IOException;
     import java.util.ArrayList;
     import java.util.List;
     import org.apache.hadoop.fs.Path;
     import org.apache.hadoop.fs.PathFilter;
    	
     public class FileFilterExcludeTmpFiles implements PathFilter {
         public boolean accept(Path p) {
             String name = p.getName();
             return !name.startsWith(“_”) && !name.startsWith(“.”) && !name.endsWith(“.tmp”);
         }
     }
    

hive-site.xml:

	<property>
	    <name>mapred.input.pathFilter.class</name>
	    <value>com.willgo.util.FileFilterExcludeTmpFiles</value>
	</property>

问题二:

数据写入延时
日志上报端 反映日志上报到集群后 查询时有不同情况的延时问题。 但自己测试时有几乎没有延时的问题。。。
考虑如下:

  1. Flume channel选择 (but 已是内存)
  2. hdfs写入机制,hdfs文件按block存储,正在写入的block 对文件系统是隐藏的。
    hdfs文件原则:
    创建文件,这个文件可以立即可见
    写入文件的数据则不被保证可见了,哪怕是执行了刷新操作(flush/sync)。只有数据量大于1个BLOCK时,第一个BLOCK的数据才会被看到,后续的BLOCK也同样的特性。正在写入的BLOCK始终不会被其他用户看到!
    基于以上两点 遇到的延时问题 基本上判断是第二点引起的。
    处理办法:

    调小Flume写入文件分割的阀值:hdfs.rollInterval。
    现在是按小时分割,是否可以考虑按分钟分割……
    这样又将产生大量小文件的问题以及namenode压力问题,小文件可以采用线下合并以及使用归档的方式处理。

博客操作记录

在_config.yml配置站点信息,详细配置如下:

blog: name: # 博客名称 description: # 博客描述 title: # 网页标题 url: # 博客地址 duoshuo: # 多说ID tongji: # 百度统计ID qiniu: # 七牛云地址 author: name: # 作者名称 email: # 邮箱地址 weibo: # 微博地址 github: # GitHub地址 douban: name: # 豆瓣地址名称 key: # 豆瓣API Key

多说评论框 _posts文章默认开启评论框,而简版页面默认关闭。 _posts文章可以在开头设置duoshuo: false来关闭。 简版页面可以在开头设置duoshuo: true来开启。

MathJax数学公式 需要在页面开头添加math: true来开启

在需要用到公式的地方用[ ]或括起来

例如:

行内公式: \E=mc^2\

行间公式: 效果:

\E=mc^2\

E=mc2 创建文章/页面
定位到博客目录,可以运行以下命令

创建文章:rake post title=”Post Name”
创建简版页面:rake life title=”Page Name”
创建页面: rake page title=”Page name”
页面的使用
修改的都是markdown文件

普通页面
layout项改为blog
简版页面
layout项改为life
文章
_posts文件夹下的markdown文件的layout项改为post,使用简版页面就改成life
生成静态博客
把你的博客推送到GitHub或者其它支持Jekyll的代码托管网站就可以了。
具体可以到Jekyll官网或GitHub Pages查看详细教程。

Sqoop密码和SA用户问题记录

sqoop 定时job 运行时需要输入密码问题 1.可以使用except 脚本,实现交互输入密码

  1. 配置sqoop,将密码保存至sqoop的metadata中
    sqoop-site.xml:

    sqoop.metastore.client.record.password true If true, allow saved passwords in the metastore.
  2. sqoop 出现Caused by: java.sql.SQLException: User not found: SA 错误

未知问题,看起来像是并发执行sqoop引起的问题 导致无法连接sqoop的metadata库
不知如何解决, 可以采取的办法
1.换个用户执行 貌似可以(。。。。。)
2.更改metadata数据库 如修改成MySQL 如下:

<property>  
    <name>sqoop.metastore.client.autoconnect.url</name>  
    <value>jdbc:mysql://192.168.117.7:3306/sqoop</value>  
</property>  
<property>  
    <name>sqoop.metastore.client.autoconnect.username</name>
    <value>scm987</value>  
</property>  
<property>  
    <name>sqoop.metastore.client.autoconnect.password</name>
    <value>scm258</value>  
</property>  


<property>
     <name>sqoop.metastore.client.enable.autoconnect</name>
     <value>true</value>
</property>

Sql on hadoop 选择笔记

Hive展现出他强大的批处理能力 但在实时交互式查询时方面却难以满足,现在已经出现的低延时交互式处理方案已经有很多 如:Hive on Tez, Hive on Spark, Spark SQL, Impala等

Hive/Tez/Stinger
目前的主要推动者是hortonworks和Yahoo!。2015 Hadoop Summit(San Jose)上,Yahoo分享了他们目前生产环境中Hive on Tez的一些情况。显示和Hive 0.10(RCFile)相比,目前的Hive on Tez在1TB的数据量查询的加速比平均为6.2倍。目前的Hive on Tez已经是production-ready。Tez这个执行引擎和Spark比较类似,原来的MR只能执行Map和Reduce两种操作,现在的Tez可以把Job解析成DAG来执行。除此之外还有一些进一步优化Hive执行效率的工作,例如Vectorized Execution和ORCFile等。Dropbox也透露他们的Hive集群下一步的升级目标就是Hive on Tez。

Hive on Spark
目前的主要推动者是Cloudera,可以认为是Hive社区这边搞的”Spark SQL”。刚刚release了第一个使用版本,目前不能用于生产环境。Hive on Spark既能利用到现在广泛使用的Hive的前端,又能利用到广泛使用的Spark作为后端执行引擎。对于现在既部署了Hive,又部署了Spark的公司来说,节省了运维成本。

对于上面提到的Hive on Tez和Hive on Spark两种系统都具备的优点是:
1,现存的Hive jobs可以透明、无缝迁移到Hive on ***平台,可以利用Hive现有的ODBC/JDBC,metastore, hiveserver2, UDF,auditing, authorization, monitoring系统,不需要做任何更改和测试,迁移成本低。
2,无论后端执行引擎是MapReduce也好,Tez也好,Spark也好,整个Hive SQL解析、生成执行计划、执行计划优化的过程都是非常类似的。而且大部分公司都积累了一定的Hive运维和使用经验,那么对于bug调试、性能调优等环节会比较熟悉,降低了运维成本。

Spark SQL
主要的推动者是Databricks。提到Spark SQL不得不提的就是Shark。Shark可以理解为Spark社区这边搞的一个”Hive on Spark”,把Hive的物理执行计划使用Spark计算引擎去执行。这里面会有一些问题,Hive社区那边没有把物理执行计划到执行引擎这个步骤抽象出公共API,所以Spark社区这边要自己维护一个Hive的分支,而且Hive的设计和发展不太会考虑到如何优化Spark的Job。但是前面提到的Hive on Spark却是和Hive一起发布的,是由Hive社区控制的。
所以后来Spark社区就停止了Shark的开发转向Spark SQL(“坑了”一部分当时信任Shark的人)。 Spark SQL是把SQL解析成RDD的transformation和action,而且通过catalyst可以自由、灵活的选择最优执行方案。对数据库有深入研究的人就会知道,SQL执行计划的优化是一个非常重要的环节, Spark SQL在这方面的优势非常明显,提供了一个非常灵活、可扩展的架构。但是Spark SQL是基于内存的,元数据放在内存里面,不适合作为数据仓库的一部分来使用。所以有了Spark SQL的HiveContext,就是兼容Hive的Spark SQL。它支持HiveQL, Hive Metastore, Hive SerDes and Hive UDFs以及JDBC driver。这样看起来很完美,但是实际上也有一些缺点:Spark SQL依赖于Hive的一个snapshot,所以它总是比Hive的发布晚一个版本,很多Hive新的feature和bug fix它就无法包括。而且目前看Spark社区在Spark的thriftserver方面的投入不是很大,所以感觉它不是特别想朝着这个方向发展。还有一个重要的缺点就是Spark SQL目前还不能通过分析SQL来预测这个查询需要多少资源从而申请对应的资源,所以在共享集群上无法高效地分配资源和调度任务。
特别是目前Spark社区把Spark SQL朝向DataFrame发展,目标是提供一个类似R或者Pandas的接口,把这个作为主要的发展方向。DataFrame这个功能使得Spark成为机器学习和数据科学领域不可或缺的一个组件,但是在数据仓库(ETL,交互式分析,BI查询)领域感觉已经不打算作为他们主要的发展目标了。

Impala
主要的推动者是Cloudera,自从推出以来一直不温不火。Impala是一种MPP架构的执行引擎,查询速度非常快,是交互式BI查询最好的选择,即使是在并发性非常高的情况下也能保证查询延迟,所以在multi-tenant, shared clusters上表现比较好。Impala的另外一个重要的优点就是支持的SQL是在以上这些系统中是最标准的,也就是跟SQL99是最像的,所以对于传统企业来说可能是个不错的选择。 Impala的主要缺点是社区不活跃,由C++开发,可维护性差,目前系统稳定性还有待提高。

Presto
是Facebook开发的,目前也得到了Teradata的支持。目前Presto的主要使用者还是互联网公司,像Facebook,Netflix等。Presto的代码用了Dependency Injection, 比较难理解和debug。另外还有一些系统,像Apache Drill,Apache Tajo等,都是非常小众的系统了。

总的来说,目前来看Hive依然是批处理/ETL 类应用的首选。Hive on Spark能够降低Hive的延迟,但是还是达不到交互式BI查询的需求。目前交互式BI查询最好的选择是Impala。Spark SQL/DataFrame是Spark用户使用SQL或者DataFrame API构建Spark pipeline的一种选择,并不是一个通用的支持交互式查询的引擎,更多的会用在基于Spark的机器学习任务的数据处理和准备的环节。

JVM笔记

JVM根据实现不同结构有所不同,大多数将内存分为:
Method Area 方法区
Heap 堆 Program Counter register 程序计数器
Java method stack Java方法栈
native method stack 本地方法栈 (Hot Spot 中将Java method和native合称为方法区)
direct memory 直接内存区(此区域并不归JVM管理)

指令 数据 方法 实例 属性。。。
方法是指令操作码的一部分保存在stack中
方法内部变量作为指令的操作数部分,跟在指令的操作码之后,保存在Stack中(实际上是简单类型保存在Stack中,对象类型在Stack中保存地址,在Heap 中保存值);指令操作码和指令操作数构成了完整的Java 指令。对象实例包括其属性值作为数据,保存在数据区Heap 中
非静态的对象属性作为对象实例的一部分保存在Heap 中,而对象实例必须通过Stack中保存的地址指针才能访问到。因此能否访问到对象实例以及它的非静态属性值完全取决于能否获得对象实例在Stack中的地址指针。

静态/非静态方法
非静态方法有一个隐含的传入参数,该参数是JVM给它的,和我们怎么写代码无关,这个隐含的参数就是对象实例在Stack中的地址指针。So我们在调用前都要new,获得Stack中的地址指针。
静态方法无此隐含参数,因此也不需要new对象,只要class文件被ClassLoader load进入JVM的Stack,该静态方法即可被调用。当然此时静态方法是存取不到Heap 中的对象属性的。

静/动态属性
实例以及动态属性都是保存在Heap 中的, Heap 必须通过Stack中的地址指针才能够被指令(类的方法)访问到。
静态属性是保存在Stack中的,而不同于动态属性保存在Heap 中。正因为都是在Stack中,而Stack中指令和数据都是定长的,因此很容易算出偏移量,也因此不管什么指令,都可以访问到类的静态属性。也正因为静态属性被保存在Stack中,所以具有了全局属性。
在JVM中,静态属性保存在Stack指令内存区,动态属性保存在Heap数据内存区。


Stack(栈)是JVM的内存指令区。Stack的速度很快,管理很简单,并且每次操作的数据或者指令字节长度是已知的。所以Java 基本数据类型,Java 指令代码,常量都保存在Stack中。
是 Java 程序的运行区,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题。
栈中数据都是以栈帧(stack frame)的形式存在,栈帧是一个内存块一个有关方法和运行期数据的数据集,遵循 先进后出原则(方法 A 被调用时就产生了一个栈帧 F1,并被压入到栈中,A 方法又调用了 B 方法,于是产生栈帧 F2 也被压入栈,执行完毕后,先弹出 F2栈帧,再弹出 F1 栈帧) 栈帧中主要保存三类数据:
local variable 本地变量(输入参数和输出参数以及方法内的变量)
operand stack栈操作 (出栈进栈记录)
frame data栈帧数据 (类文件 方法等)

Heap
JVM的内存数据区 管理复杂,用于保存对象的实例
Heap 中分配一定的内存来保存对象实例,实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中),在Heap 中分配一定的内存保存对象实例和对象的序列化比较类似。而对象实例在Heap 中分配好以后,需要在Stack中保存一个4字节的Heap 内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。

Java中堆是由所有的线程共享的一块内存区域。
Heap 中分配一定的内存来保存对象实例,实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中),在Heap 中分配一定的内存保存对象实例和对象的序列化比较类似。而对象实例在Heap 中分配好以后,需要在Stack中保存一个4字节的Heap 内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。
Java中堆是由所有的线程共享的一块内存区域。

Perm
Perm代主要保存class,method,filed对象,这部门的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。

Tenured
Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。

Young
Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,其中Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Young区间变满的时候,minor GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到Tenured区间。

The pc Register 程序计数器寄存器
JVM支持多个线程同时运行。每个JVM都有自己的程序计数器。在任何一个点,每个JVM线程执行单个方法的代码,这个方法是线程的当前方法。如果方法不是native的,程序计数器寄存器包含了当前执行的JVM指令的地址,如果方法是 native的,程序计数器寄存器的值不会被定义。 JVM的程序计数器寄存器的宽度足够保证可以持有一个返回地址或者native的指针。

Method Area 方法区
Object Class Data(类定义数据) 是存储在方法区的。除此之外,常量、静态变量、JIT 编译后的代码也都在方法区。正因为方法区所存储的数据与堆有一种类比关系,所以它还被称为 Non-Heap。方法区也可以是内存不连续的区域组成的,并且可设置为固定大小,也可以设置为可扩展的,这点与堆一样。 方法区内部有一个非常重要的区域,叫做运行时常量池(Runtime Constant Pool,简称 RCP)。在字节码文件中有常量池(Constant Pool Table),用于存储编译器产生的字面量和符号引用。每个字节码文件中的常量池在类被加载后,都会存储到方法区中。值得注意的是,运行时产生的新常量也可以被放入常量池中,比如 String 类中的 intern() 方法产生的常量。

内存分配:
1、对象优先在EDEN分配
2、大对象直接进入老年代
3、长期存活的对象将进入老年代
4、适龄对象也可能进入老年代:动态对象年龄判断
动态对象年龄判断:
虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,当Survivor空间的相同年龄的所有对象大小总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中指定的年龄

1、对象优先在Eden分配,这里大部分对象具有朝生夕灭的特征,Minor GC主要清理该处
2、大对象(占内存大)、老对象(使用频繁)
3、Survivor无法容纳的对象,将进入老年代,Full GC的主要清理该处

JVM的GC机制
第一个线程负责回收Heap的Young区
第二个线程在Heap不足时,遍历Heap,将Young 区升级为Older区
Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能。
堆内存GC
       JVM(采用分代回收的策略),用较高的频率对年轻的对象(young generation)进行YGC,而对老对象(tenured generation)较少(tenured generation 满了后才进行)进行Full GC。这样就不需要每次GC都将内存中所有对象都检查一遍。
非堆内存不GC
      GC不会在主程序运行期对PermGen Space进行清理,所以如果你的应用中有很多CLASS(特别是动态生成类,当然permgen space存放的内容不仅限于类)的话,就很可能出现PermGen Space错误。
内存申请过程
1.JVM会试图为相关Java对象在Eden中初始化一块内存区域;
2.当Eden空间足够时,内存申请结束。否则到下一步;
3.JVM试图释放在Eden中所有不活跃的对象(minor collection),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
4.Survivor区被用来作为Eden及old的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区;
5.当old区空间不够时,JVM会在old区进行major collection;
6.完全垃圾收集后,若Survivor及old区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”Out of memory错误”;

对象衰老过程
1.新创建的对象的内存都分配自eden。Minor collection的过程就是将eden和在用survivor space中的活对象copy到空闲survivor space中。对象在young generation里经历了一定次数(可以通过参数配置)的minor collection后,就会被移到old generation中,称为tenuring。

类的加载方式
1):本地编译好的class中直接加载
2):网络加载:java.net.URLClassLoader可以加载url指定的类
3):从jar、zip等等压缩文件加载类,自动解析jar文件找到class文件去加载util类
4):从java源代码文件动态编译成为class文件

类加载的时机

  1. 类加载的 生命周期 :加载(Loading)–>验证(Verification)–>准备(Preparation)–>解析(Resolution)–>初始化(Initialization)–>使用(Using)–>卸载(Unloading)
    2. 加载:这有虚拟机自行决定。
    3. 初始化阶段:
    a) 遇到new、getstatic、putstatic、invokestatic这4个字节码指令时,如果类没有进行过初始化,出发初始化操作。
    b) 使用java.lang.reflect包的方法对类进行反射调用时。
    c) 当初始化一个类的时候,如果发现其父类还没有执行初始化则进行初始化。
    d) 虚拟机启动时用户需要指定一个需要执行的主类,虚拟机首先初始化这个主类。
    注意:接口与类的初始化规则在第三点不同,接口不要气所有的父接口都进行初始化。

双亲委派机制
JVM在加载类时默认采用的是 双亲委派 机制。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。