TA(Tencent Analytics,腾讯分析)是一款面向第三方站长的免费网站分析系统,在数据稳定性、及时性方面广受站长好评,其秒级的实时数据更新频率也获得业界的认可。本文将从实时数据处理、数据存储等多个方面带你深入探寻TA的系统架构及实现原理。

网站分析(Web Analytics)主要指的是基于网站的用户浏览行为,对网站的点击流数据和运营数据进行分析,以监控网站的运营状况,为网站的优化提供决策依据。网站分析系统已成为站长日常运营必不可少的工具,业界比较流行的网站分析系统主要有Google Analytics、CNZZ和百度统计等产品。

TA作为网站分析产品的后起之秀在社区分析、用户画像、网站工具等多方面形成了自己的特色,其秒级的实时数据更新频率更是业界翘楚。在数据稳定性、准确性和及时性方面,TA在站长圈也是享有良好的口碑。随着接入业务量的不断发展,TA日均需要处理和计算的数据量达到TB级。如此庞大的数据量想要达到秒级实时且保证系统的高可用并非件易事。

TA的实时计算框架借鉴了一些业界流行的流式计算系统的思路。虽然在构建系统中遇到了一些问题,但由于海量数据的实时处理、实时存储具备一定的典型性与通用性,所以将TA的解决方案分享出来,希望能给大家一些启示。

Google C++ Style Guide是业界最为著名的C++编程规范之一。本文对其核心要点进行梳理总结,涵盖头文件管理、命名规范、类设计、内存管理等方面。

1. 头文件(Header Files)

通常每个 .cc 文件应该有一个配套的 .h 文件. 常见的例外情况包括单元测试和仅有 main() 函数的 .cc 文件.
正确使用头文件会大大改善代码的可读性和执行文件的大小、性能.

  • 每个.cc文件都应有一个对应的.h文件
  • 使用#define保护头文件防止多重包含,格式:PROJECT_PATH_FILE_H_
  • 尽量使用前置声明(Forward Declarations)减少 #include 的数量
  • 内联函数不超过10行

这一阵子一直都在忙着写论文,改论文,改论文,再改论文,还是该论文,上周末终于抽出一点时间去离杭州不远的徽杭古道玩了两天,这周又忙于专利、预审、写开题报告、考驾照等等等,所以拖到现在才写这个游记(其实主要是帖照片了),我也是醉了。

下面是徽杭古道安徽绩溪入口处,大约12点左右就到这儿了。注意要在这个地方买票哦(全价¥68),检票口在后面。。。

匆匆又一年。

这段时间一直都在忙着写毕业论文,快一个月没有更新博客了,昨天是2014最后一天,也是学校举行的第一个学生节,在去紫荆港吃免费晚餐前将论文的模板提交到了github,这也是2014年最后一次commit了。在校园的最后一个跨年和元旦,就这样一个人在风雨操场看现场晚会度过了。今天是新年的第一天,又是一个人宅在实验室边听着二次元plus萌系的SNH48的『化作樱花树』边写着这篇本该昨天写的年终总结。

豆瓣链接:你不可不知道的音乐大师及其名作

花了接近两个月的时间,终于把这本厚达623页的书看完了,这本书主要讲述了31位在音乐史上赫赫有名、贡献卓著的音乐大师的生平及其著名代表作,主要是西方古典音乐大师,包括我们耳熟能详的巴赫、海顿、莫扎特、贝多芬、舒伯特、肖邦等等,本文整理一下书中这些音乐大师及其代表作。

1、巴赫(Bach,1685-1750,音乐之父):1685年3月21日,出生于今日德国埃森纳赫的一个音乐世家,10岁是父母双亡,也是在这个年龄就开始担任教堂的“女高音”。巴赫的职业生涯可以分为三个阶段——魏玛时代、科腾时代和莱比锡时代。魏玛时代的创作风格洋溢着青春的热情,科腾时代主要是管弦乐与室内乐的创作,而莱比锡时代主要是为宗教奉献的。代表作有《D大调前凑曲与赋格曲》、《A大调前凑曲与赋格曲》、《G小调赋格曲》、《C大调托卡塔、慢板与赋格曲》、《勃兰登堡协凑曲》、《管弦乐组曲》、《无伴凑大提琴组曲》、《无伴凑小提琴凑名曲和组曲》、《平均律钢琴曲集》、《约翰受难曲》、《马太受难曲》等。我个人比较喜欢的还是他的《E调前奏曲》、《B小调帕蒂塔 - Ⅵ 布列舞曲》、《G大调小步舞曲》和《布兰登堡舞曲》等。

前后花了大概快六个月的时间(从6月8日到11月23),终于把侯捷的《STL 源码剖析》看完了,同时也把 SGI 实现 STL 的最新版本看完了。在这段时间里,几乎是每个周末花大约一天的时间来看书和代码,并将相应内容在博客中加以归纳和总结。由于基本上都是在周末抽时间看的,所以周期拉得比较长,但收获还是挺多的,其中印象比较深刻的是 STL 中的迭代器与型别萃取、空间配置与内存池的实现、双端队列 (deque) 的实现、红黑树的实现、排序等算法的实现、类与函数的偏特化、函数对象与适配器等等,对 STL 的整体架构也有了比较深入的认识。这段时间也经历了很多事情,看书和代码的过程中也遇到了很多问题,有些经过反复琢磨自己解决了,还有些仍未完全弄清楚,需要再回过头去看一遍。另外,在看书和代码的过程中,基本没有去写代码、去实践,只停留在理论上,再看一遍的时候可以写些测试的代码或自己实现一个相应的模块或功能。

这里再把之前写的深入理解 STL 源码的系列文章进行一个归档:

STL 简介

  1. 深入理解STL源码(0) STL简介

STL 空间配置器

  1. 深入理解STL源码(1) 空间配置器(allocator)

STL 迭代器

  1. 深入理解STL源码(2) 迭代器(Iterators)和Traits

1. 概述

适配器(adaptor/adapter)在STL组件的灵活运用功能上,扮演着轴承、转换器的角色,将一种容器或迭代器装换或封装成另一种容器或迭代器,例如基于deque容器的stack和queue。Adaptor这个概念,实际上是一种设计模式(design pattern),是《Design Pattern》一书中提及到的23个设计模式之一,其中对adaptor的定义如下:

将一个class的接口转换为另一个class的接口,使原本因接口不兼容而不能合作的classes,可以一起运作。

在STL中,除了上面提到的容器或迭代器的适配器之外,还可以对函数或更广义的仿函数使用适配器,改变其接口,这种称为function adaptor,相应的针对容器或迭代器的适配器则分别称为container adaptor,iterator adaptor,下面将分别介绍这三种适配器。

2. 容器适配器

容器适配器相对而言比较简单,比较典型的就是上面提到的低层由deque构成的stack和queue,其基本实现原理是,在 stack 和 queue 内部定义一个 protected 的 deque 类型的成员变量,然后只对外提供 deque 的部分功能或其异构,如 stack 的 push 和 pop 都是从 deque 的尾部进行插入和删除,而 queue 的 push 和 pop 分别是从尾部和头部进行插入和删除,这样 stack 和 queue 都可以看做是适配器,作用于容器 deque 之上的适配器。关于 stack 和 queue 的具体内容请参见之前将容器的文章 深入理解STL源码(3.3) 序列式容器之deque和stack、queue

1. 仿函数|函数对象概述

在STL的六大组件中,仿函数可说是体积最小、观念最简单、实现最容易的一个,但小兵也能立大功——他扮演一种“策略”角色,可以让STL算法具有更加灵活的“演出”。

在STL的历史上,仿函数(functor)是早期的命名,C++标准规格定下来后采用了新的名称——函数对象(function object)。就实际意义而言,函数对象的称谓更加贴切:一种具有函数特质的对象。函数对象对调用者而言可以向函数调用一样地被调用,而对被调用者而言则是以对象所定义的函数调用操作符(function call operator)。

在C++中,函数调用操作符是指左右小括弧 () ,该操作符是可以重载的。许多 STL 算法都提供了两个版本,一个用于一般情况(例如排序时使用 operator< 以递增方式排列),一个用于特殊情况(例如排序时按照使用者自定义的大小关系进行排序)。这有点类似于C语言中的函数指针,但函数指针无法满足STL对抽象性的要求,也不能和STL其他组件(如配接器adaptor)搭配,产生更灵活的变化,关于这一点下一节将详细介绍。

2. 可适配(Adaptable)的关键

STL算法非常灵活的一个关键因素之一在于STL仿函数的可配接性(adaptability),即函数可以被配接器修饰,彼此相积木一样地串接。为了拥有配接能力,每一个仿函数必须定义自己的相应型别(associate types),就像迭代器如果要融入整个STL大家庭,也必须依照规定定义自己的5个相应型别一样。这样做是为了让配接器能够获得函数的一些特性。相应型别都只是一些 typedef,所有必要操作在编译期就就全部完成了,对程序的执行效率没有任何影响,不带来任何额外负担。

仿函数相应型别主要用来表示函数的参数型别和返回值型别,为了方便,stl_function.h 中定义了两个基类,分别是 unary_functionbinary_function,分别表示一元函数和二元函数,其中都是一些型别的定义,仿函数只需要继承其中一个类,就可以拥有配接能力了。

本文主要介绍STL中的稍微复杂的算法,主要涉及到的源码文件有 stl_algo.h 等。

在文件 stl_algo.h 中有很多常用的算法,包括查找、计数、旋转、删除、排序、合并、集合的交并等运算、求极值、排列组合等等,本文将按源码中各算法的实现顺序来介绍其具体实现细节。由于本文涉及到的算法和相关代码太多,在文中就尽量不贴出代码了,详细的代码及相关注释请参见 stl_algo.h

1. 求三个数的中值 median
该算法比较简单,几个if-else语句就解决了。该函数只提供内部算法使用,并不对外提供接口,也不是STL标准中的算法,限于篇幅这里就不贴代码了。另外,该算法有两个版本,一个是使用默认的大小比较,另一个是可以指定比较函数。

2. for_each
也很简单,就是对区间 [first, last) 中的每一个元素执行一个给定函数的运算,就一行语句:

for ( ; __first != __last; ++__first) __f(*__first);

其中 __f 为用户传入的一个指定的仿函数。该算法的返回值仍为传入的仿函数 __f