Skip to content

Commit 53ed462

Browse files
committed
fix: 优化目录结构
1 parent 23d7d76 commit 53ed462

32 files changed

Lines changed: 409 additions & 21 deletions

File tree

大数据/Scala/Scala-入门.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# 1 函数式编程思想
22
## 1.1 介绍
3-
![](https://upload-images.jianshu.io/upload_images/4685968-2217fa78d2aae90a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
43
![](https://upload-images.jianshu.io/upload_images/4685968-339e97ac6c2f74e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
54
![](https://upload-images.jianshu.io/upload_images/4685968-102c9902ed240289.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
65
![](https://upload-images.jianshu.io/upload_images/4685968-3c5db14174facab2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# 1 角色
2+
RocketMQ由四个角色组成:
3+
- Producer
4+
消息生产者
5+
- Consumer
6+
消费者
7+
- Broker
8+
MQ服务,负责接收、分发消息
9+
- NameServer
10+
负责MQ服务之间的协调
11+
# 2 架构设计
12+
![](https://img-blog.csdnimg.cn/20191025001711704.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_1,color_FFFFFF,t_70)
13+
14+
## NameServer-MQ服务注册发现中心
15+
提供轻量级服务发现和路由。
16+
每个名称服务器记录完整的路由信息,提供相应的读写服务,并支持快速存储扩展。
17+
18+
> NameServer 充当路由信息提供者。生产者/消费者客户查找主题以查找相应的broker列表。
19+
# 3 搭建
20+
## 配置
21+
- runserver.sh 设置小点
22+
![](https://img-blog.csdnimg.cn/20191103145158719.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_1,color_FFFFFF,t_70)
23+
- runbroker.sh 设置小点
24+
![](https://img-blog.csdnimg.cn/20191103145746578.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_1,color_FFFFFF,t_70)
25+
## 启动
26+
```bash
27+
nohup sh bin/mqnamesrv > logs/namesrv.log 2>&1 &
28+
```
29+
```bash
30+
nohup sh bin/mqbroker -n localhost:9876 >
31+
~/logs/rocketmqlogs/broker.log 2>&1 &
32+
```
33+
- 启动报错
34+
![](https://img-blog.csdnimg.cn/20191103151015192.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_1,color_FFFFFF,t_70)
35+
- 查看日志![](https://img-blog.csdnimg.cn/20191103150942509.png)
36+
- 改启动文件,添加JAVA_HOME变量![](https://img-blog.csdnimg.cn/20191103154507585.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_16,color_FFFFFF,t_70)
37+
- 启动成功
38+
![](https://img-blog.csdnimg.cn/20191103154618638.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_1,color_FFFFFF,t_70)
39+
启动broker
40+
```bash
41+
nohup sh bin/mqbroker -c conf/broker.conf -n localhost:9876 > logs/broker.log 2>&1 &
42+
```
43+
![](https://img-blog.csdnimg.cn/20191103155747201.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_1,color_FFFFFF,t_70)
44+
# remoting模块架构
45+
![](https://img-blog.csdnimg.cn/20201008002847207.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_16,color_FFFFFF,t_70#pic_center)

数据存储/消息队列/RocketMQ/RocketMQ 高级特性-消息的有序性.md renamed to 数据存储/消息队列/RocketMQ/RocketMQ实战(3)-消息的有序性.md

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,48 @@
11
# 1 为什么需要消息有序
2-
996 一年终于攒了十万存在银行卡里准备存取款,对应两个异步的短信消息,要保证先存后取:
3-
- M1 - 存钱
4-
- M2 - 取钱
2+
996一辈子了,准备去银行存取款,对应两个异步短信消息,要保证先存后取:
3+
- M1 存钱
4+
- M2 取钱
55
![](https://img-blog.csdnimg.cn/20191110204432867.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9qYXZhZWRnZS5ibG9nLmNzZG4ubmV0,size_1,color_FFFFFF,t_70)
66

7-
而MQ默认发消息到不同queue显然是行不通的,会乱序。因此,需要发往同一queue,依靠其先进先出机制
8-
7+
而MQ默认发消息到不同Q显然是行不通的,会乱序。
8+
因此,需发往同一Q,依赖队列的先进先出机制。
99
# 2 基本概念
10-
有序消息又叫顺序消息(FIFO 消息),指消息的消费顺序和产生顺序相同。
10+
有序消息,又叫顺序消息(FIFO消息),指消息的消费顺序和产生顺序相同。
1111

12-
比如订单的生成、付款、发货,这串消息必须按顺序处理。
13-
顺序消息又分为如下:
12+
如订单的生成、付款、发货,这串消息必须按序处理。顺序消息又可分为:
1413
## 2.1 全局顺序
15-
一个Topic内所有的消息都发布到同一个queue,按照FIFO顺序进行发布和消费
14+
一个Topic内所有的消息都发布到同一Q,按FIFO顺序进行发布和消费
1615
![](https://img-blog.csdnimg.cn/20191110205132371.png)
17-
1816
### 适用场景
1917
性能要求不高,所有消息严格按照FIFO进行消息发布和消费的场景。
20-
2118
## 2.2 分区顺序
22-
对于指定的一个Topic,所有消息按`sharding key`进行区块(queue)分区,同一queue内的消息严格按FIFO发布和消费
19+
对于指定的一个Topic,所有消息按`sharding key`进行区块(queue)分区,同一Q内的消息严格按FIFO发布和消费
2320

2421
- Sharding key是顺序消息中用来区分不同分区的关键字段,和普通消息的Key完全不同。
2522
![](https://img-blog.csdnimg.cn/20191110205442842.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9qYXZhZWRnZS5ibG9nLmNzZG4ubmV0,size_16,color_FFFFFF,t_70)
26-
2723
### 适用场景
2824
性能要求高,根据消息中的sharding key去决定消息发送到哪个queue。
29-
3025
## 2.3 对比
3126
- 发送方式对比
3227
![](https://img-blog.csdnimg.cn/20191110210418100.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9qYXZhZWRnZS5ibG9nLmNzZG4ubmV0,size_16,color_FFFFFF,t_70)
33-
3428
# 3 如何保证消息顺序?
3529
在MQ模型中,顺序需由3个阶段去保障
3630
1. 消息被发送时保持顺序
3731
2. 消息被存储时保持和发送的顺序一致
3832
3. 消息被消费时保持和存储的顺序一致
39-
4033
![](https://img-blog.csdnimg.cn/20191110210708395.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9qYXZhZWRnZS5ibG9nLmNzZG4ubmV0,size_16,color_FFFFFF,t_70)
41-
4234
# 4 RocketMQ 有序消息实现原理
4335
![](https://img-blog.csdnimg.cn/20191110210921254.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9qYXZhZWRnZS5ibG9nLmNzZG4ubmV0,size_1,color_FFFFFF,t_70)
4436

4537
RocketMQ消费端有两种类型:
4638
- MQPullConsumer
4739
- MQPushConsumer
48-
![](https://img-blog.csdnimg.cn/20201114141638859.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_SmF2YUVkZ2U=,size_1,color_FFFFFF,t_70#pic_center)
40+
![](https://img-blog.csdnimg.cn/20201114141638859.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_1,color_FFFFFF,t_70#pic_center)
4941

5042
底层都是通过pull机制实现,pushConsumer是一种API封装而已。
5143
- `MQPullConsumer` 由用户控制线程,主动从服务端获取消息,每次获取到的是一个`MessageQueue`中的消息。
5244
- `PullResult`中的 `List<MessageExt> msgFoundList`
53-
![](https://img-blog.csdnimg.cn/20201114142006113.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_SmF2YUVkZ2U=,size_1,color_FFFFFF,t_70#pic_center)
45+
![](https://img-blog.csdnimg.cn/20201114142006113.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzNTg5NTEw,size_1,color_FFFFFF,t_70#pic_center)
5446

5547
- `MQPushConsumer`由用户注册`MessageListener`来消费消息,在客户端中需要保证调用`MessageListener`时消息的顺序性
5648
![](https://img-blog.csdnimg.cn/20191110212543478.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9qYXZhZWRnZS5ibG9nLmNzZG4ubmV0,size_1,color_FFFFFF,t_70)
@@ -64,7 +56,6 @@ RocketMQ消费端有两种类型:
6456
![](https://img-blog.csdnimg.cn/20191110213124288.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9qYXZhZWRnZS5ibG9nLmNzZG4ubmV0,size_16,color_FFFFFF,t_70)
6557
- 判断是并发的还是有序的,对应不同服务实现类
6658
![](https://img-blog.csdnimg.cn/20191110213603167.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9qYXZhZWRnZS5ibG9nLmNzZG4ubmV0,size_1,color_FFFFFF,t_70)
67-
6859
# 5 有序消息的缺陷
6960
发送顺序消息无法利用集群的Failover特性,因为不能更换MessageQueue进行重试。
7061

File renamed without changes.

重构/OOP三大特性之封装.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
C语言的结构化编程解决了很多问题,但随代码量增多,其局限也越明显:各模块依赖关系太强,不能有效隔离变化。于是,OOP诞生。
2+
3+
习惯结构化编程思维的人,认为:
4+
```java
5+
OO=数据+函数
6+
```
7+
这理解不算错,但程度太低。结构化编程思维就如管中窥豹,只能看到局部。
8+
想要用好OOP,则需有更宏观的视角。
9+
10+
# 如何理解封装
11+
OO是解决更大规模应用开发的一种尝试,它提升了程序员管理程序的尺度。
12+
13+
封装,是OO的根基:
14+
- 它把紧密相关的信息放在一起,形成一个单元
15+
- 若该单元稳定,即可将该单元和其它单元继续组合,构成更大单元
16+
- 同理,继续构建更大单元,层层封装变大
17+
# OO的初心
18+
OO由Alan Kay提出,图灵奖获得者。其最初构想,对象就是细胞。将细胞组织起来,组成身体各器官,再组织起来,就构成人体。而当你去观察人时,就不用再去考虑每个细胞如何。所以,OO提供了更宏观思维。
19+
20+
但这一切的前提:每个对象要构建好,即封装要做好。就像每个细胞都有细胞壁将其与外界隔离,形成一个完整个体。
21+
22+
Kay强调**对象之间只能通过消息通信**
23+
按如今程序设计语言通常做法,发消息就是方法调用,对象之间就是靠方法调用通信。
24+
25+
> 但这方法调用并非简单地把对象内部的数据通过方法暴露。Kay的构想甚至想把数据去掉。
26+
27+
因为封装的重点在于**对象提供了哪些行为,而非有哪些数据**
28+
即便我们把对象理解成数据+函数,数据、函数也不是对等的:
29+
- 函数是接口
30+
接口是稳定的
31+
- 数据是内部的实现
32+
实现是易变的,应该隐藏
33+
34+
很多人的开发习惯:写一个类,写其一堆字段,然后生成一堆getter、setter,暴露这些字段的访问。
35+
这种做法是错误的,它把数据当成设计核心,这一堆getter、setter,就等于暴露实现细节。
36+
37+
**正确做法**
38+
1. 设计一个类,先考虑对象应提供哪些**行为**
39+
2. 然后,根据这些行为提供对应方法
40+
3. 最后考虑实现这些方法要有哪些**字段**
41+
42+
所以连接二者的是方法,其命名就是个大学问了,应体现你的意图,而非具体怎么做的。所以,getXXX和setXXX绝不是个好命名。
43+
比如,设计:用户修改密码。
44+
45+
一些人上手就来:
46+
![](https://img-blog.csdnimg.cn/5ab9f7f30f824b32b24444885ef1c1ee.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASmF2YUVkZ2Uu,size_19,color_FFFFFF,t_70,g_se,x_16)
47+
48+
但推荐写法是表达你的意图:
49+
![](https://img-blog.csdnimg.cn/3d818b23e99d43b7bdbabf50b007ddd3.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASmF2YUVkZ2Uu,size_20,color_FFFFFF,t_70,g_se,x_16)
50+
两段代码只是修改密码的方法名不同,但更重要的差异是:
51+
- 一个在说做什么
52+
- 一个在说怎么做
53+
54+
**将意图与实现分离**,优秀设计须考虑的问题。
55+
56+
实际项目中,有时确实需要暴露一些数据。
57+
所以,当确实需暴露时,再写getter也不迟,你一定要问自己为何要加getter?
58+
关于setter:
59+
- 大概率是你用错名字,应该用一个表达意图的名字
60+
- setter通常意味着修改,这是不推荐的
61+
62+
可变的对象会带来很多的问题,后续再深入讨论。所以,设计中更好的做法是设计不变类。
63+
64+
Lombok很好,少写很多代码,但必须限制它的使用,像Data和Setter都不该用。Java Bean本来也不是应该用在所有情况下的技术,导致很多人误用。
65+
# 减少接口的暴露
66+
之所以需要封装,就是要构建一个内聚单元。所以,要减少该单元对外的暴露:
67+
- 减少内部实现细节的暴露
68+
- 减少对外暴露的接口
69+
70+
OOP语言都支持public、private,日常开发经常会轻率地给一个方法加public,不经意间暴露了一些本是内部实现的部分。
71+
72+
比如,一个服务要停下来时,你可能要把一些任务都停下来:
73+
![](https://img-blog.csdnimg.cn/498578fc8ea2413dadd84961d0067381.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASmF2YUVkZ2Uu,size_14,color_FFFFFF,t_70,g_se,x_16)
74+
75+
别人可能这样调用时:
76+
![](https://img-blog.csdnimg.cn/bd93854e9f3a4acb8ecf56f37b3a7122.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASmF2YUVkZ2Uu,size_13,color_FFFFFF,t_70,g_se,x_16)
77+
78+
突然某天,你发现停止轮询任务必须在停止定时器任务之前,你就不得不要求别人改代码。而这一切就是因为我们很草率地给那两个方法加上public,让别人有机会看到这俩方法。
79+
80+
设计角度,必须谨慎自省:这个方法有必要暴露吗?
81+
其实可仅暴露一个方法:
82+
![](https://img-blog.csdnimg.cn/18eaf9df12fe4f56b6a32cf226053673.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASmF2YUVkZ2Uu,size_14,color_FFFFFF,t_70,g_se,x_16)外部的调用代码也会简化:
83+
![](https://img-blog.csdnimg.cn/85533a09a5cf4e8180b361b02bed0b65.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASmF2YUVkZ2Uu,size_11,color_FFFFFF,t_70,g_se,x_16)
84+
尽可能减少接口暴露,该原则适于类的设计、系统设计。
85+
很多人都特别随意在系统里添加接口,让一个看似不复杂的系统,随便就有成百上千个接口。
86+
87+
后续,当你想改造系统,去掉一些接口时,很可能造成线上事故,因为你根本不知道哪个团队在何时用到了它。
88+
所以,软件设计中,谨慎暴露接口!
89+
90+
可总结出:最小化接口暴露,即每增加一个接口,都要找到一个充分的理由!
91+
# 总结
92+
封装的重点在于对象提供了哪些行为,而不是有哪些数据。封装,除了要减少内部实现细节的暴露,还要减少对外接口的暴露。每暴露一个公共API就增加一份职责,所以在每次暴露API时就要问自己,这个职责是自己必要的,还是有可能会增加不必要的负担。
93+
一个原则是最小化接口暴露。
94+
95+
注意区分:
96+
- OO和 Java 语言
97+
- 传输数据和业务对象
98+
99+
Java语言特点就是一切皆对象,Java中对象的概念跟OO中对象的概念不同:
100+
- 前者是语言特性
101+
- 后者是一种编程范式
102+
103+
在具体编码中,哪些属于对象,哪些不属于对象,应该是程序员掌控。
104+
比如:
105+
- DDD中的领域实体,就是对象,需仔细设计其行为接口
106+
- 一些POJO,可看成数据载体,可直接加getter、setter的(没有这些默认getter、setter,很多第三方数据转化都很不方便,比如JSON,SQL)。使用时,不归结为对象即可
107+
108+
**基于行为进行封装,不要暴露实现细节,最小化接口暴露。**
109+
110+
111+
Demeter 不是一个人,而是一个项目,项目主页 http://www.ccs.neu.edu/research/demeter/。最早提到迪米特法则的论文出版于 1989 年,Assuring good style for object-oriented programs。还有一本书,1996 年出版,Adaptive Object-Oriented Software: The Demeter Method with Propagation Patterns。没有看过。
112+
113+
Demeter 是希腊神话中的大地和丰收女神,也叫做德墨忒尔。
114+
115+
迪米特法则简单的说,分为两个部分:不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。其实如果用另一个名字“最小知识原则”可能更容易理解一些,这个也算是程序员的“黑话”吧。
116+
117+
虽然接触OOP已经很久了,不过写程序时,大多数人还是习惯“一个对象一张表”,也没有太多考虑封装。整个类里都是 getter、setter 的事情也做过,这就像是用“面向对象的语言写面向过程的代码”。
118+
119+
> 参考
120+
> - https://www2.ccs.neu.edu/research/demeter/
File renamed without changes.

0 commit comments

Comments
 (0)