forked from aalansehaiyang/technology-talk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9b21f87
commit ef012ef
Showing
13 changed files
with
299 additions
and
7 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
## 强引用、软引用、弱引用、幻象引用 | ||
--- | ||
|
||
* 强引用 | ||
|
||
常见的普通对象引用,只要还有强引用指向一个对象,就表示这个对象还“活着”,垃圾回收不会回收这种对象。对于一个普通对象,如果没有其他引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为null,就可以被垃圾收集了。 | ||
|
||
* 软引用 | ||
|
||
SoftReference,相对强引用弱一些,可以让对象豁免一些垃圾收集,只有当JVM 认为内存不足时,才会去试图回收软引用指向的对象。 | ||
|
||
JVM会确保在抛出OutofMemoryError之前,清理软引用指向的对象。这样保证了使用缓存的同时,不会耗尽内存。 | ||
|
||
* 弱引用 | ||
|
||
并不能使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下对象的途经。 | ||
|
||
如果试图获取时对象还在,就使用它,否则重新实例化,它同样是很多缓存实现的选择。 | ||
|
||
* 幻象引用 | ||
|
||
也叫虚引用,你不能通过它访问对象。仅仅提供了对象被finalize以后,做某些事情的机制,比如 Post-Mortem清理机制 | ||
|
||
|
||
对象可达性状态流转图: | ||
|
||
![image](img/31.jpeg) | ||
|
||
|
||
所有引用类型,都是抽象类 java.lang.ref.Reference的子类,提供了get()方法。 | ||
|
||
**除了幻象引用(get返回null),如果对象没有被销毁,都可以通过get()方法获取原有对象,我们可以将访问到的对象,重新指向强引用,也就是人为的改变对象的可达性状态。** | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
## 流量调度 | ||
--- | ||
|
||
### 主要功能: | ||
|
||
1、根据系统运行的情况,自动地进行流量调度,无需人工干预的情况下,提升整个系统的稳定性。 | ||
|
||
如:对于一个机构有a、b、c三个口子,分别各用10%的流量探测各口子的成功率,依据结果将剩下的70%分流到成功率较高的口子上。 | ||
|
||
2、当系统遇到爆品时,弹性计算,动态扩容、缩容。 | ||
|
||
### 其它相关 | ||
|
||
* 服务流控 | ||
|
||
服务发现、路由、熔断、服务保护 | ||
|
||
* 流量控制 | ||
|
||
负载均衡、流量分配、流量控制、异地多活 | ||
|
||
* 流量管理 | ||
|
||
协议转换、请求校验、数据缓存、数据计算 | ||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
## 幂等性设计 | ||
--- | ||
|
||
服务间调用有三种状态:成功;失败;超时。前两个状态明确,但超时状态完全不知道是什么状态。 | ||
|
||
可能是请求没有到达,也可能是请求到达了,但返回结果没有到达。我们不知道下游系统是否收到了请求,而收到了请求是否处理了。 | ||
|
||
例如: | ||
|
||
* 创建订单接口,第一次调用超时,然后client重试了一次,是否会多创建一笔订单? | ||
* 用户付款时,服务端发生扣款行为,接口响应超时,调用方重试了一次,是否会多扣一次钱? | ||
|
||
**解决方案:** | ||
|
||
* 下游系统提供查询接口,上游系统在timout后去查询一次,并根据结果执行不同的策略 | ||
* 幂等处理。上游只管重试,下游系统保证一次和多次的请求结果是一样的。(推荐方式) | ||
|
||
### 全局id | ||
|
||
|
||
[Twitter的分布式自增ID算法snowflake ](https://www.cnblogs.com/relucent/p/4955340.html) | ||
|
||
snowflake的结构如下(每部分用-分开): | ||
|
||
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 | ||
|
||
* 第一位为未使用 | ||
* 接下来的41位为毫秒级时间(41位的长度可以使用69年) | ||
* 然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点) | ||
* 最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号) | ||
|
||
一共加起来刚好64位,为一个Long型。(转换成字符串后长度最多19) | ||
|
||
snowflake生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和workerId作区分),并且效率较高。经测试snowflake每秒能够产生26万个ID。 | ||
|
||
**本机测试,每秒产生约4W个id** | ||
|
||
### 处理流程 | ||
|
||
以交易为例,当收到交易请求时,先去查,有没有创建过?如果查到了就不做处理 | ||
|
||
一般可以采用乐观锁,基本CAS方式。 | ||
|
||
``` | ||
update 订单表 set status="交易成功" where id=#orderId# and status="等待买家确认收货" | ||
``` | ||
|
||
或者 | ||
|
||
以论坛发贴为例,在表单中隐藏一个token,防止用户多次点击表单提交按钮。防重复。 | ||
|
||
|
||
|
||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
## 隔离设计 | ||
--- | ||
|
||
### 常见方式 | ||
|
||
1、服务的种类来做分离 | ||
|
||
2、用户维度做分离 | ||
|
||
### 服务种类分离 | ||
|
||
![image](img/13.jpeg) | ||
|
||
以微服务形式,将业务拆分为用户中心,商品中心,评论中心,各自采用独立的服务器集群部署,独立的数据库。达到物理层面的隔离。 | ||
|
||
### 用户维度分离 | ||
|
||
![image](img/14.jpeg) | ||
|
||
将用户分成不同的组,并把后端的同一个服务根据这些不同的组分成不同的实例。同一个服务对于不同的用户进行冗余和隔离。这样一个服务实例挂掉,只会影响一部分用户。 | ||
|
||
“多租户”模式。针对一些大的客户,专用集群。 | ||
|
||
* 特点: | ||
|
||
增加设计的复杂度,资源上存在浪费。 | ||
|
||
* 多租户模式分为三种: | ||
|
||
1、完全独立。每个租户有自己完全独立的服务和数据。 | ||
|
||
2、独立的数据分区,服务共享。(较推荐方式) | ||
|
||
3、共享服务,共享数据分区。 | ||
|
||
### 设计要点 | ||
|
||
* 定义好隔离业务的大小和粒度。过大、过小都不好。需要结合具体业务来看。 | ||
|
||
* 考虑系统的复杂度、成本、性能、资源使用的问题。找到合适的均衡方案。 | ||
|
||
* 配置一些高可用、重试、异步、消息中间件、流控、熔断等框架 | ||
|
||
* 自动化运维工具,象容器或虚拟化技术帮助我们更方便的管理 | ||
|
||
* 非常完善的监控系统 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
## 重试 | ||
--- | ||
|
||
**重试: 这个故障是暂时的,不是永久的,我们才会去重试。** | ||
|
||
设计重试时,一定要结合业务场景,定义出什么情况下需要重试。(比如:调用超时) | ||
|
||
**一些错误最好不要重试,如:** | ||
|
||
* 没有权限 | ||
* 非法请求数据 | ||
* 数据格式不正确 | ||
|
||
### 设计要点 | ||
|
||
* 要确定什么样的错误才需要重试 | ||
* 重试的时间和重试的次数 | ||
* 超时重试次数,或是一段时间,那么重试就没有意义了。此后对于新来的请求,就没有必要再进行重试了。此时新来的请求直接返回错误即可。 | ||
* 重试要考虑被调用方是否支持幂等设计 | ||
* 可以借助框架,如 Spring Annotation,不用侵入业务代码 | ||
* 对于有事务相关的操作。我们可能会希望能重试成功,而不至于走业务补偿那样的复杂的回退流程。对此,我们可能需要一个比较长的时间来做重试,但是我们需要保存住请求的上下文,这可能对程序的运行有比较大的开销,因此,有一些设计会先把这样的上下文暂存在本机或是数据库中,然后腾出资源来去做别的事,过一会再回来把之前的请求从存储中捞出来重试。 | ||
|
||
|
||
### 重试的策略 | ||
|
||
要有最大值,经过一段时间的重试后,没有必要再重试了。重试可能加重网络负担。 | ||
|
||
Exponential Backoff (指数策略) | ||
|
||
如:第一次等 200ms;第二次等400ms;第三次等800ms | ||
|
||
### Spring 重试策略 | ||
|
||
https://github.com/spring-projects/spring-retry | ||
|
||
以AOP的方式通过Annotation的方式使用。 | ||
|
||
``` | ||
@Service | ||
public interface MyService { | ||
@Retryable( | ||
value = { SQLException.class }, | ||
maxAttempts = 2, | ||
backoff = @Backoff(delay = 5000)) | ||
void retryService(String sql) throws SQLException; | ||
... | ||
} | ||
``` | ||
|
||
配置 @Retryable 注解,只对 SQLException 的异常进行重试,重试两次,每次延时 5000ms。相关的细节可以看相应的文档。我在这里,只想让你看一下 Spring 有哪些重试的策略。 | ||
|
||
|
||
``` | ||
RetryTemplate template = new RetryTemplate(); | ||
TimeoutRetryPolicy policy = new TimeoutRetryPolicy(); | ||
policy.setTimeout(30000L); | ||
template.setRetryPolicy(policy); | ||
Foo result = template.execute(new RetryCallback<Foo>() { | ||
public Foo doWithRetry(RetryContext context) { | ||
// Do stuff that might fail, e.g. webservice operation | ||
return result; | ||
} | ||
}); | ||
``` | ||
* NeverRetryPolicy:只允许调用 RetryCallback 一次,不允许重试。 | ||
|
||
* AlwaysRetryPolicy:允许无限重试,直到成功,此方式逻辑不当会导致死循环。 | ||
|
||
* SimpleRetryPolicy:固定次数重试策略,默认重试最大次数为 3 次,RetryTemplate 默认使用的策略。 | ||
|
||
* TimeoutRetryPolicy:超时时间重试策略,默认超时时间为 1 秒,在指定的超时时间内允许重试。 | ||
|
||
* CircuitBreakerRetryPolicy:有熔断功能的重试策略,需设置 3 个参数 openTimeout、resetTimeout 和 delegate;关于熔断,会在后面描述。 | ||
|
||
* CompositeRetryPolicy:组合重试策略。有两种组合方式,乐观组合重试策略是指只要有一个策略允许重试即可以,悲观组合重试策略是指只要有一个策略不允许重试即不可以。但不管哪种组合方式,组合中的每一策略都会执行。 | ||
|
||
|
||
|
||
|
||
|