Git CheatSheet
ps:本指南会持续更新
其实一般情况下,只需要掌握git的几个常用命令即可,但是在使用的过程中难免会遇到各种复杂的需求,这时候经常需要搜索,非常麻烦,故总结了一下自己平常会用到的git操作。
上图所示,使用git的流程一般如此,通常使用图中的六个命令即可。
ps:本指南会持续更新
其实一般情况下,只需要掌握git的几个常用命令即可,但是在使用的过程中难免会遇到各种复杂的需求,这时候经常需要搜索,非常麻烦,故总结了一下自己平常会用到的git操作。
上图所示,使用git的流程一般如此,通常使用图中的六个命令即可。
ps: 本文完成于2015年12月31号
对于一个公司来说,要想健康长久的发展,招聘是一个永久的话题。而对于一个互联网公司,尤其是以产品为主的公司来说,研发是招聘中的关键职位,高质量的研发人才也是所有企业都急缺的。一直持有一个观点:招一个优秀的人给他两倍的薪资带来的效果远远大于招两个普通的人。也一直秉着这个观点来招聘。
本人一直从事的是服务端开发工作,写前端貌似有点跑题,不过自己初中也就是2000年左右的时候,引领我进入计算机大门的也的确是前端,后来也做过不少的前端工作。于是,就想着从自己的角度写点前端这些年的发展。但毕竟不是专业所长,有所纰漏在所难免。
说起github,大家应该都是非常熟悉的。正是github的兴起,带来了开源的一个高潮,也诞生了无数优秀的开源项目。最最著名的Linux也在github上有了自己的repository。当然,github的核心技术git也是李纳斯的代表作。
记得几年前由于项目的需要,曾尝试自己去搭建一套git服务给项目组使用,折腾了好久,才总算搭建了一个基础的系统, 刚刚能用,权限控制都没有(http://srhang.iteye.com/blog/1339110)。但最终因为git的上手门槛有点高,还是选择了svn。后来随着github的兴起,git才如火如荼地在国内火了起来。许多大的互联网公司,也都开始把项目由svn转到git。但如果仅仅是搭建一个git服务,那么github这种网站提供的可视化ui带来的便捷却也不复存在了。对于一些小的有钱的团队,使用github的收费私人repository倒也是一种解决办法。但是,对于大部分公司来说,还是不会把公司内部的代码放到这种公共服务上的。这种需求场景下,就诞生了很多github的克隆实现,以方便部署内网的github。
—本文于2015.12.23最新更新—
互联网时代,高并发是一个老生常谈的话题。无论对于一个web站点还是app应用,高峰时能承载的并发请求都是衡量一个系统性能的关键标志。像阿里双十一顶住了上亿的峰值请求、订单也确实体现了阿里的技术水平(当然有钱也是一个原因)。
那么,何为系统负载能力?怎么衡量?相关因素有哪些?又如何优化呢?
半结构化或非结构化数据
对于数据结构字段不够确定或杂乱无章很难按一个概念去进行抽取的数据适合用HBase。当业务发展需要增加存储比如一个用户的email,phone,address信息时RDBMS需要停机维护,而HBase支持动态增加.
记录非常稀疏
RDBMS的行有多少列是固定的,为null的列浪费了存储空间。而如上文提到的,HBase为null的Column不会被存储,这样既节省了空间又提高了读性能。
多版本数据
根据Row key和Column key定位到的Value可以有任意数量的版本值,因此对于需要存储变动历史记录的数据,用HBase就非常方便了。对于某一值,业务上一般只需要最新的值,但有时可能需要查询到历史值。
超大数据量
当数据量越来越大,RDBMS数据库撑不住了,就出现了读写分离策略,通过一个Master专门负责写操作,多个Slave负责读操作,服务器成本倍增。随着压力增加,Master撑不住了,这时就要分库了,把关联不大的数据分开部署,一些join查询不能用了,需要借助中间层。随着数据量的进一步增加,一个表的记录越来越大,查询就变得很慢,于是又得搞分表,比如按ID取模分成多个表以减少单个表的记录数。经历过这些事的人都知道过程是多么的折腾。采用HBase就简单了,只需要加机器即可,HBase会自动水平切分扩展,跟Hadoop的无缝集成保障了其数据可靠性(HDFS)和海量数据分析的高性能(MapReduce)
Row key
行主键, HBase不支持条件查询和Order by等查询,读取记录只能按Row key(及其range)或全表扫描,因此Row key需要根据业务来设计以利用其存储排序特性(Table按Row key字典序排序如1,10,100,11,2)提高性能。
Column Family(列族)
在表创建时声明,每个Column Family为一个存储单元。
Column(列)
HBase的每个列都属于一个列族,以列族名为前缀,如列article:title和article:content属于article列族,author:name和author:nickname属于author列族。
Column不用创建表时定义即可以动态新增,同一Column Family的Columns会群聚在一个存储单元上,并依Column key排序,因此设计时应将具有相同I/O特性的Column设计在一个Column Family上以提高性能。
Timestamp
HBase通过row和column确定一份数据,这份数据的值可能有多个版本,不同版本的值按照时间倒序排序,即最新的数据排在最前面,查询时默认返回最新版本。Timestamp默认为系统当前时间(精确到毫秒),也可以在写入数据时指定该值。
Value
每个值通过4个键唯一索引,tableName+RowKey+ColumnKey+Timestamp=>value
存储类型
将HTable的存储结构理解为
即HTable按Row key自动排序,每个Row包含任意数量个Columns,Columns之间按Column key自动排序,每个Column包含任意数量个Values。理解该存储结构将有助于查询结果的迭代。
列族的数量以及列族的势
列族的数量越少越好,牵扯到了hbase的flushing;同一个表中不同列族所存储的记录数量的差别也需要考虑(列族的势),会造成记录数量少的列族的数据分散在多个region上,影响查询效率。
行键的设计
避免使用时序或者单调(递增/递减)行键,否则会导致连续到来的数据会被分配到统一region中。
尽量最小化行键和列族的大小
避免hbase的索引过大,加重系统存储的负担
版本的数量
HColumnDescriptor设置版本的数量,避免设置过大,版本保留过多。
Kafka的consumer是以pull的形式获取消息数据的。不同于队列和发布-订阅模式,kafka采用了consumer group的模式。通常的,一般采用一个consumer中的一个group对应一个业务,配合多个producer提供数据。
在user level上,一旦消费过topic里的数据,那么就无法再次用同一个groupid消费同一组数据。如果想要再次消费数据,要么换另一个groupid,要么使用镜像:
此外,low level的api提供了一些机制去设置partion和offset。
kafka会记录offset到zk中。但是,zk client api对zk的频繁写入是一个低效的操作。0.8.2 kafka引入了native offset storage,将offset管理从zk移出,并且可以做到水平扩展。其原理就是利用了kafka的compacted topic,offset以consumer group,topic与partion的组合作为key直接提交到compacted topic中。同时Kafka又在内存中维护了
This API is centered around iterators, implemented by the KafkaStream class. Each KafkaStream represents the stream of messages from one or more partitions on one or more servers. Each stream is used for single threaded processing, so the client can provide the number of desired streams in the create call. Thus a stream may represent the merging of multiple server partitions (to correspond to the number of processing threads), but each partition only goes to one stream.
根据官方文档所说,stream即指的是来自一个或多个服务器上的一个或者多个partition的消息。每一个stream都对应一个单线程处理。因此,client能够设置满足自己需求的stream数目。总之,一个stream也许代表了多个服务器partion的消息的聚合,但是每一个partition都只能到一个stream。
负载低的情况下可以每个线程消费多个partition。但负载高的情况下,Consumer 线程数最好和Partition数量保持一致。如果还是消费不过来,应该再开 Consumer 进程,进程内线程数同样和分区数一致。(多谢 @shadyxu 指出)
bin/kafka-run-class.sh kafka.tools.ConsumerOffsetChecker –group pv
可以看到当前group offset的状况。
bin/kafka-run-class.sh kafka.tools.UpdateOffsetsInZK earliest config/consumer.properties page_visits
3个参数,
[earliest | latest],表示将offset置到哪里
consumer.properties ,这里是配置文件的路径
topic,topic名,这里是page_visits
kafka的low-level接口,使用场景:
用这个接口需要注意一下几点:
使用步骤:
本文一、二部分内容主要来自官方文档。
下载代码
https://www.apache.org/dyn/closer.cgi?path=/kafka/0.8.2.0/kafka_2.10-0.8.2.0.tgz
tar -xzf kafka_2.10-0.8.2.0.tgz
cd kafka_2.10-0.8.2.0
启动服务器
kafka依赖zookeeper,所以需要首先安装并启动zookeeper。可以使用kafka自带的zookeeper。
bin/zookeeper-server-start.sh config/zookeeper.properties
然后即可启动kafka
bin/kafka-server-start.sh config/server.properties
创建topic
消息传输需要指定topic。所以首先要创建一个topic。
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
之后,可以看到已经创建的topic.其中的replication-factor指的是复制因子,即log冗余的份数,这里的数字不能大于broker的数量。
bin/kafka-topics.sh --list --zookeeper localhost:2181
也可以不用手动创建topic,只需要配置broker的时候设置为auto-create topic when a non-existent topic is published to.
发送消息
kafka提供了一个命令行客户端,可以从一个文件或者标准输入里读取并发送到kafka集群。默认的,每一行都作为一个单独的消息。
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
在命令行输入消息并回车即可发送消息。
启动一个消费者
kafka也提供了一个命令行消费者,接受消息并打印到标准输出。
bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning
设置多broker集群
首先需要为每一个broker创建一个配置文件。
cp config/server.properties config/server-1.properties
cp config/server.properties config/server-2.properties
config/server-1.properties:
broker.id=1
port=9093
log.dirs=/tmp/kafka-logs-1
config/server-2.properties:
broker.id=2
port=9094
log.dirs=/tmp/kafka-logs-2
然后启动这两个结点:
bin/kafka-server-start.sh config/server-1.properties &
bin/kafka-server-start.sh config/server-2.properties &
现在一共有了三个结点,三个broker,那么这样就可以形成一个集群。
创建一个复制引子为3的topic
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic
如果想查看目前这个topic的partion在broker上的分布情况
bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic
更多细节参见kafka.consumer.ProducerConfig类。
更多细节参见kafka.consumer.ConsumerConfig类。
Kafka很多使用场景是输出消息到Storm的,Storm本身也提供了storm-kafka的包,在使用Storm的KafkaSpout时需要注意以下几点:
在采用基于SimpleConsumer的消费端实现时,我们遇到过一个情况是大量的轮询导致整个环境网络的流量异常,原因是该topic一直没有新消息,consumer端的轮询没有设置等待参数,也没有在client线程里判断进行一个短暂的sleep。几乎是以死循环的方式不断跟server端通讯,尽管每次的数据包很小,但只要有几个这样的消费端足以引起网络流量的异常。这里需要设置maxWait参数,但是此参数必须与minBytes配合使用才有效。但是在storm-kafka的KafkaUtils中的fetchMessages方法中对minBytes没有设置,因此即使设置了maxWait也没有效果。这里需要自己重写KafkaUtils来解决。
FetchRequest fetchRequest = builder.addFetch(topic, partitionId, offset, config.fetchSizeBytes). clientId(config.clientId).maxWait(config.fetchMaxWait).minBytes(1).build(); // 此处是修复了原来代码里没有设置minBytes
修复了上述问题后,后来还是遇到网络流量异常的情况,后来在追踪KafkaSpout源码的过程中,发现当kafka中的消息过大时,如果不设置合适的bufferSizeBytes以及fetchSizeBytes(至少要大于kafka中最大消息的大小),那么很容易造成客户端由于bufferSizeBytes或者fetchSize设置过小,无法将消息放入buffer中也不能成功fetch而不停地去轮询服务端,从而导致网络流量异常。
最近公司需要上基于nginx log的数据统计系统。其中一个重要的结点即分布式日志收集。在调研了多种方案之后,最终确定了flume+kafka+storm+hbase的系统架构。其中kafka则是linkedin一个专门为日志而产生的service。官方文档上如是说:Kafka是一个分布式、分区、冗余的commit日志service。它提供了一种特殊设计的消息系统功能。