[TOC]

1. Hadoop概述

官网:https://hadoop.apache.org/

Hadoop包含以下模块:

  1. Hadoop Common: 支撑其他模块的通用工具
  2. Hadoop Distributed File System(HDFS): 分布式文件系统,提供高吞吐数据读取
  3. Hadoop YARN: 作业调度与资源管理框架
  4. Hadoop MapReduce: 基于YARN的大数据并行处理。

开源的分布式存储与分布式计算平台

1.1 Hadoop能做什么

  • 搜索引擎
  • 日志分析
  • 商业智能
  • 数据挖掘

2. Hadoop核心组件

2.1 分布式文件系统HDFS

Read more »

[toc]

德雷福斯模型

德雷福斯是一个专业人员能力成长模型,这个模型认为所有专业人员都需要经历 5 个成长阶段,不管是医生还是律师,或者是软件开发,任何专业技能的从业者都需要经历新手、高级新手、胜任者、精通者、专家 5 个阶段。

link

通常一个人进入专业的技能领域,即使在学校已经系统学习过这个专业的相关知识,但依然无法独立完成工作,必须在有经验的同事指导下,学习相关的技能。这里主要学习的是有关工作的规则和套路。比如用什么工具、什么框架,如何开发程序,如何开会、写周报,如何和同事合作,业务领域的名词术语是什么意思等等这些各种各样和工作有关的大小事情。这个阶段叫做新手阶段。

通常说来,一个人大约工作两三年后,就差不多掌握了工作的各种套路,可以摆脱新手阶段,独立完成一些基本的工作了。通过新手阶段的人,少部分会直接进入胜任者阶段,而大多数则进入高级新手阶段。

高级新手其实是新手的自然延续,他不需要别人指导工作,也不需要学习工作的规则和套路,因为高级新手已经在新手阶段掌握了这些套路,他可以熟练应用这些规则套路完成他的工作。但是高级新手的能力也仅限于此,他不明白这些规则是如何制定出来的,为什么使用这个框架开发而不是另一个框架,也不明白这个框架是如何开发出来的。

一个悲观的事实是,新手会自然进入高级新手阶段,而高级新手却无法自然进入其后的其他等级阶段。实际上,在各个专业领域中,超过半数的人终其一生都停留在高级新手阶段,也就是说,大多数人一生的工作就是基于其专业领域的规则在进行重复性的劳动。他们不了解这些规则背后的原理,也无法在面对新的问题时,开创出新的方法和规则。那些简历上十多年如一日使用相同的技术方案、开发类似软件项目的资深工程师大部分都是高级新手。

导致一个人终身停留在高级新手阶段的原因有很多,其中一个重要的原因是:高级新手不知道自己是高级新手。高级新手觉得自己在这个专业领域混得很不错,做事熟练,经验丰富。

事实上,这种熟练只是对既有规则的熟练,如果岁月静好,一切都循规蹈矩,也没什么问题。而一旦行业出现技术变革或者工作出现新情况,高级新手就会遇到巨大的工作困难。事实上,各行各业都存在大量的高级新手,只是软件开发领域的技术变革更加频繁,问题变化也更加快速,使高级新手问题更加突出。

Read more »

[toc]

对于规模不太大的软件系统,我们可以将概要设计文档和详细设计文档合并成一个设计文档。这一篇文章中,我会展现一个设计文档示例模板,你可以参考这个模板编写你的设计文档。

文档开头是设计概述,简单描述业务场景要解决的核心问题领域是什么。至于业务场景,应该在专门的需求文档中描述,但是在设计文档中,必须要再简单描述一下,以保证设计文档的完整性,这样,即使脱离需求文档,阅读者也能理解主要的设计。

此外,在设计概述中,还需要描述设计的非功能约束,比如关于性能、可用性、维护性、安全性,甚至开发和部署成本方面的设计目标。

然后就是具体的设计了,第一张设计图应该是部署图,通过部署图描述系统整个物理模型蓝图,包括未来系统长什么样。

如果系统中包含几个子系统,那么还需要描述子系统间的关系,可以通过子系统序列图,子系统活动图进行描述。

子系统内部的最顶层设计就是组件图,描述子系统由哪些组件组成,不同场景中,组件之间的调用序列图是什么样的。

每个组件内部,需要用类图进行建模描述,对于不同场景,用时序图描述类之间的动态调用关系,对于有复杂状态的类,用状态图描述其状态转换。

具体示例模板如下:

1 设计概述

Read more »

[TOC]

分布式架构

arch

缓存架构:如何减少不必要的计算?

缓存分为通读缓存旁路缓存

通读缓存

通读(read-through)缓存,应用程序访问通读缓存获取数据的时候,如果通读缓存有应用程序需要的数据,那么就返回这个数据;如果没有,那么通读缓存就自己负责访问数据源,从数据源获取数据返回给应用程序,并将这个数据缓存在自己的缓存中。这样,下次应用程序需要数据的时候,就可以通过通读缓存直接获得数据了。

read-through

互联网应用中主要使用的通读缓存是 CDN 和反向代理缓存。

cdn

Read more »

设计模式基础

设计模式的精髓是对多态的使用

装饰器模式

装饰模式最大的特点是,通过类的构造函数传入一个同类对象,也就是每个类实现的接口和构造函数传入的对象是同一个接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public interface AnyThing {
void exe();
}

public class Moon implements AnyThing {
private AnyThing a;
public Moon(AnyThing a) {
this.a = a;
}
public void exe() {
System.out.print("明月装饰了");
a.exe();
}
}

public class Dream implements AnyThing {
private AnyThing a;
public Dream(AnyThing a) {
this.a=a;
}
public void exe() {
System.out.print("梦装饰了");
a.exe();
}
}

public class You implements AnyThing {
private AnyThing a;
public You(AnyThing a) {
this.a = a;
}
public void exe() {
System.out.print("你");
}
}

调用:

1
2
3
4
5
6
7
8
9
10
AnyThing t = new Moon(new Dream(new You(null)));
t.exe();

输出:明月装饰了梦装饰了你


AnyThing t = new Dream(new Moon(new You(null)));
t.exe();

输出:梦装饰了明月装饰了你

面试官让你“聊聊设计模式”,也许你可以这样回答:“除了单例和工厂,我更喜欢适配器和观察者,还有,组合模式在处理树形结构的时候也非常有用。”

组合模式遍历树:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class DefaultModule implements Module {

private final String value;

public DefaultModule(String value) {
this.value = value;
}

@Override
public void print() {
System.out.println(value);
}
}

public class ComponentModule implements Module {

private final Module currentModule;

private final List<Module> modules;

public ComponentModule(Module currentModule, Module... modules) {
this.currentModule = currentModule;
this.modules = Arrays.asList(modules);
}

@Override
public void print() {
this.currentModule.print();
this.modules.forEach(Module::print);
}
}

public interface Module {

void print();

static void main(String[] args) {
ComponentModule subModule31 = new ComponentModule(
new DefaultModule("31"),
new DefaultModule("311"),
new DefaultModule("312"),
new DefaultModule("313")
);

ComponentModule subModule3 = new ComponentModule(
new DefaultModule("3"),
subModule31,
new DefaultModule("32"),
new DefaultModule("33")
);

ComponentModule module = new ComponentModule(
new DefaultModule("0"),
new DefaultModule("1"),
new DefaultModule("2"),
subModule3
);

module.print();
}
}
Read more »

设计的两个基本原则:高内聚,低耦合。

开闭原则:不修改代码实现变更

OCP

开闭原则:软件实体(模块、类、函数等等)应该对扩展是开放的,对修改是关闭的。

1. 使用策略模式实现开闭原则

strategy

2. 使用适配器模式实现开闭原则

adapter

3. 使用观察者模式实现开闭原则: 如果要实现多个控制,使用观察者模式+策略+适配器模式

observer

Read more »

4+1架构视图

img

  1. 逻辑视图:描述软件的功能逻辑,由哪些模块组成,模块中包含哪些类,其依赖关系如何。
  2. 开发视图:包括系统架构层面的层次划分,包的管理,依赖的系统与第三方的程序包。开发视图某些方面和逻辑视图有一定重复性,不同视角看到的可能是同一个东西,开发视图中一个程序包,可能正好对应逻辑视图中的一个功能模块。
  3. 过程视图:描述程序运行期的进程、线程、对象实例,以及与此相关的并发、同步、通信等问题。
  4. 物理视图:描述软件如何安装并部署到物理的服务上,以及不同的服务器之间如何关联、通信。
  5. 场景视图:针对具体的用例场景,将上述 4 个视图关联起来,一方面从业务角度描述,功能流程如何完成,一方面从软件角度描述,相关组成部分如何互相依赖、调用。

UML

类图

详细设计阶段需求分析阶段使用。

一个类包含三个部分:类的名字、类的属性列表和类的方法列表。类之间有 6 种静态关系:关联、依赖、组合、聚合、继承、泛化。

在需求分析阶段,可以将关键的领域模型对象用类图画出来,在这个阶段中,我们需要关注的是领域对象的识别及其关系,所以用简化的类图来描述,只画出类的名字及关系就可以了。

序列图

序列图通常用于表示对象之间的交互,这个对象可以是类对象,也可以是更大粒度的参与者,比如组件、服务器、子系统等,总之,只要是描述不同参与者之间交互的,都可以使用序列图,也就是说,在软件设计的不同阶段,都可以画序列图。

Read more »

1. 为什么需要分布式架构

  • 增大系统容量
  • 增强系统可用性

2. 分布式系统技术栈

分布式技术栈是为了增大系统容量、增强系统可用性来服务的,因此主要是完成两件事情:

  • 大流量处理:提高性能,通过集群技术把大规模并发请求的负载分散到不同的机器上。
  • 关键业务保护:提高后台服务的可用性,把故障隔离起来阻止多米诺骨牌效应(雪崩效应)。如果流量过大,需要对业务降级,以保护关键业务流转。

2.1 提高性能

提高性能

  • 缓存系统

[toc]

类(Class)

类定义

1
2
3
4
5
6
class className {

/* All member variables
and member functions*/

}; // 注意,类定义必须以分号结尾

创建对象

1
2
3
4
5
6
7
8
class className {
...
};

int main() {
int i; //integer object
className c; // className object
}

类访问范围

私有:

1
2
3
4
5
6
7
8
9
10
class Class1 {
int num; // 1. 默认时私有的
...
};

class Class2 {
private: // 也可以显示声明私有
int num;
...
};

public & protected

Read more »
0%