Zacard's Notes


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

  • 搜索
close
Zacard's Notes

X-UID:分布式唯一id服务

发表于 2018-04-24 | 分类于 软件技术 | | 阅读次数

背景

之前开发的分布式唯一id比较简陋。这段时间重新设计优化,变成一个独立的项目X-UID。这里记录下设计优化的一些东西

基本算法还是基于snowflake。因为需求就是要一个long型数字,snowflake算法简单高效。

snowflake简单介绍

算法生成的id结构图:

说明:

  • 1-bit:符号位,一般不设置,默认为0
  • 41-bit:时间戳,大约能用69年
  • 10-bit:工作机器id,最大支持1024个workerId
  • 12-bit:序列号,毫秒内的自增序列。这也决定了其QPS的上限为400w/s这个数量级
阅读全文 »
Zacard's Notes

mysql等数据库索引为什么偏爱b+tree

发表于 2018-03-30 | 分类于 软件技术 | | 阅读次数

背景

类似mysql等数据库偏爱用b+tree这个数据结构作为索引,这是为什么呢?要解释这个原因,必须先讲下计算机组成原理中的磁盘数据存取原理。

磁盘数据读取原理

这里指普通的机械磁盘。

先看下磁盘的结构:

阅读全文 »
Zacard's Notes

elasticsearch写入优化记录

发表于 2018-03-27 | 分类于 软件技术 | | 阅读次数

背景

  • 基于elasticsearch-5.6.0
  • 机器配置:3个阿里云ecs节点,16G,4核,机械硬盘

优化前,写入速度平均3000条/s,一遇到压测,写入速度骤降,甚至es直接频率gc、oom等;优化后,写入速度平均8000条/s,遇到压测,能在压测结束后30分钟内消化完数据,各项指标回归正常。

阅读全文 »
Zacard's Notes

阿里中间件6轮面试被砍的血泪总结

发表于 2018-03-20 | 分类于 面试 | | 阅读次数

背景

年前在v2ex遇到阿里中间件的哥们,内推面试。从2018.02.01开始到今天2018.03.20,一场浩浩荡荡,跨年,持续了1个半月时间的残酷面试终于尘埃落定。遗憾的未能加入阿里中间件部门这个大家庭,让我深感痛惜。

最终未能如愿的原因是“名额有限,有更适合的同学”。这也可能是内推大哥为了顾及我的感受的说辞,可能是最后一面面的不好。

这里凭借隐约的记忆,总结下面试经过。让我自己引以为戒,奋发自强,继续前行

阅读全文 »
Zacard's Notes

分布式锁研究

发表于 2018-03-20 | 分类于 软件技术 | | 阅读次数

背景

公司使用基于redis setNX的分布式锁偶现失效,对此深入研究一番

场景

大体来说,分布式锁的场景有两种:

  1. 为了效率:相当于去重,避免各个系统做重复的事情。比如重复发送一封email
  2. 为了正确性:不允许出现任何的失效,不然就可能造成数据不一致

基于单节点的redis实现

为什么强调单节点?因为我们就一个redis主从,没有redis集群。而且redis有官方的分布式锁redlock是基于redis集群的,这个对我们不适用,而且感觉有点过重。

我们一开始的方案是基于setNX(key,value,timeout)。后来发现原来这是jedis的封装,这其实是2个redis命令:setnx+expire。也就是说这不是个原子操作,很可能setnx成功,但是设置过期时间失败导致锁永远无法释放

翻看redlock的套路才知道,应该这样操作:

  1. 获取锁:set key randomValue NX PX 3000

    redis的set操作有NX(if not exist)选项和PX(过期时间)选项,可以实现原子操作

  2. 释放锁:需要使用LUA脚本实现复合操作的原子性:

    1
    2
    3
    (1) get key
    (2) 比较random value
    (3) random value一致即删除key
阅读全文 »
Zacard's Notes

rocketmq源码阅读之message发送

发表于 2018-03-18 | 分类于 软件技术 | | 阅读次数

背景

基于rocketmq 4.2.0

先不关注顺序消息和事务消息,后面独立看。

发送消息入口

DefaultMQProducer#send(Message)

默认的是同步发送。最终调用的是DefaultMQProducerImpl#sendDefaultImpl,直接看代码:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
private SendResult sendDefaultImpl(
Message msg,
final CommunicationMode communicationMode,
final SendCallback sendCallback,
final long timeout
) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
// 确保producer已经启动
this.makeSureStateOK();
// 校验message,例如topic不能为空
Validators.checkMessage(msg, this.defaultMQProducer);
// 目前来看,仅在日志输出时标示此次调用
final long invokeID = random.nextLong();
long beginTimestampFirst = System.currentTimeMillis();
long beginTimestampPrev = beginTimestampFirst;
long endTimestamp = beginTimestampFirst;
// 获取topic发布路由信息 -- 会先尝试缓存中获取,其次从namesrv中获取
TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
if (topicPublishInfo != null && topicPublishInfo.ok()) {
MessageQueue mq = null;
Exception exception = null;
SendResult sendResult = null;
// 同步发送默认重试3次
int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1;
int times = 0;
String[] brokersSent = new String[timesTotal];
for (; times < timesTotal; times++) {
String lastBrokerName = null == mq ? null : mq.getBrokerName();
/*
* 选择一个消息队列
* 规则:1)默认情况,不开启发送的延迟容错策略时,RoundRobin形式的选择一个不属于上一次发送的broker队列
* 2)开启延迟容错策略时:
* 2.1)优先从上一次的发送的broker中RoundRobin形式选择一个可用队列
* 2.2)其次按照可用性排名(是否可用>延迟时间>开始时间)从前半数中RoundRobin选
* 2.3)最次,啥都不管,RoundRobin选
*/
MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName);
if (mqSelected != null) {
mq = mqSelected;
brokersSent[times] = mq.getBrokerName();
try {
beginTimestampPrev = System.currentTimeMillis();
// 核心消息投递方法
sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout);
endTimestamp = System.currentTimeMillis();
// 更新延迟容错信息
this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
switch (communicationMode) {
case ASYNC:
return null;
case ONEWAY:
return null;
case SYNC:
if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
if (this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()) {
continue;
}
}
return sendResult;
default:
break;
}
} catch (RemotingException e) {
// ...省略部分代码
}
} else {
break;
}
}
// ...省略部分代码
}
// ...省略部分代码
}
阅读全文 »
Zacard's Notes

分布式追踪系统x-apm拾遗之伪共享与缓存行填充

发表于 2018-02-26 | 分类于 软件技术 | | 阅读次数

背景

之前开发分布式追踪系统x-apm的时候,确认了2个目标:

  1. x-apm的异常绝不能影响业务系统
  2. x-apm应该尽可能的少暂用系统资源的前提下,尽可能的快(实时)

针对第2点,用来暂存追踪数据的数据结构碰到了伪共享的问题,导致收集发送的效率不够高,所以使用的缓存行填充。

这里记录下伪共享和缓存行填充的相关内容。

基础简介

cpu cache

一个典型的cpu cache架构:

访问速度:寄存器<L1 cache<L2 cache<L3 cache<主存

所以,充分利用它的结构和机制,可以有效的提高程序的性能

这里需要注意:一个cpu中的多核共享L3 cache,而L1、L2 cache是每个核心各自拥有的;一个缓存行一般缓存64byte大小的数据

阅读全文 »
Zacard's Notes

分布式追踪系统x-apm开发拾遗之synthetic与bridge方法

发表于 2018-02-13 | 分类于 软件技术 | | 阅读次数

背景

之前开发x-apm的时候,自定义增强一个spring bean的时候,出现了一个奇怪的异常 – 找不到无参构造方法,导致bean初始化失败。原来是bytebuddy这个类库在增强类的时候,会自动增加一个synthetic的构造方法,导致spring无法找打正确的构造方法初始化。这里记录下synthetic方法和bridge方法。

synthetic方法

synthetic方法是什么呢?先来看个实际例子:

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
public class SyntheticTest {
private int i;
public void setI(int i) {
this.i = i;
}
public class A {
private int j;
public int sum() {
return j + i;
}
public void setJ(int j) {
this.j = j;
}
}
public static void main(String[] args) {
SyntheticTest syntheticTest = new SyntheticTest();
A a = syntheticTest.new A();
a.setJ(1);
System.out.println("sum=" + a.sum());
}
}
阅读全文 »
Zacard's Notes

Service Mesh - 服务网格

发表于 2018-02-12 | 分类于 软件技术 | | 阅读次数

什么是service mesh

服务网格是一个基础设施层,功能在于处理服务间通信,职责是负责实现请求的可靠传递。在实践中,服务网格通常实现为轻量级网络代理,通常与应用程序部署在一起,但是对应用程序透明

可以将它比作是微服务间的TCP/IP,负责服务之间的网络调用、限流、熔断、监控等功能。对于编写应用程序来说一般无须关心TCP/IP这一层(比如通过HTTP协议的RESTful应用),同样使用service mesh也就无须关心服务之间的那些原来是通过应用程序或者其他框架实现的事情,比如spring cloud,现在只要交给service mesh就可以了

另一方面,service mesh更强调由这些代理连接而形成的网络,而不仅仅是一个网络代理(sidecar)。

为什么要有service mesh

因为,基于框架或者类库实现的网络代理存在诸多弊端

阅读全文 »
Zacard's Notes

分布式追踪系统x-apm开发拾遗之javaagent

发表于 2018-02-09 | 分类于 软件技术 | | 阅读次数

背景

x-apm开发周期比较短,开发过程中用到的一些知识点没有深入理解,这里记录下apm用到的入口知识点 – javaagent

什么是javaagent

javaagent是Java中用来增强JVM上的应用的一种方式,这样的agent有机会修改目标应用或者应用所运行的环境。它可通过访问Java Instrumentation API来修改目标应用程序的class字节码

为什么要有javaagent

  1. 暴露一些特定功能。比如运行时获得所有已加载类的字节码
  2. 对于特定类做低侵入甚至无侵入的增强。比如对某个类的某个方法插入特定逻辑

所以,javaagent的主要功能其实类似aop,但是其原理是加载class文件之前做拦截,直接修改字节码,或者运行时动态修改字节码;而aop是生成一个新的代理类

阅读全文 »
12…7
zacard

zacard

优生笑,菜鸟哭

61 日志
2 分类
96 标签
RSS
GitHub Weibo ZhiHu
Links
  • DingDang's Notes
© 2015 - 2018 zacard
由 Hexo 强力驱动
主题 - NexT.Mist