2019-06-14 18:16:03    2    0    0

Chrome插件

uBlock Origin:资源占用较低的广告屏蔽插件
Vimium:支持使用vim快捷键操作chrome,基本告别鼠标
Octotree:github目录树
The Great Suspender:小内存机器福音,支持自动冻结不常用tab,释放大量内存,解冻稍慢,需要1s左右
Personal Blocklist:自定义过滤google搜索结果中的垃圾站

画图工具

drawio:超级方便的开源画图工具,类似收费的processon,提供网页版和本地客户端版。
mermaid:很多markdown编辑器支持的画图语法,画图类似写代码lol。

HBase    2019-05-28 13:14:31    8    0    0

HBase支持对HFile文件的压缩处理,对于以文本数据为主的HFile经过压缩后文件大小往往能缩小一半以上,在不提升硬件的情况下文件系统缓存能够装载更多的数据。HBase查询中在BlockCache miss时会去加载底层HFile文件,压缩能够有效减少这类IO操作的读取时间,但是需要进行解压缩,造成额外的耗时,所以今天测试一下缩是否会带来明显的读取延迟。

测试环境:

  • CDH 6.0.1
  • HBase 2.0.0-cdh6.0.1
  • RegionServer 24G内存、300G HDD单硬盘、2G Heap、6核心 x5台
  • ycsb-hbase20-binding-0.15.0(yahoo开源的数据库benchmark工具)

测试步骤:

  1. 建立测试表:t1,t2,关闭BlockCache(模拟缓存miss,所有数据都从磁盘读取),t1开启snappy压缩,t2不开启
  2. 写入测试数据,t1,t2分别写入150W行数据(HBase数据首先写入内存,未经过压缩,只有memstore刷写hfile时才会进行压缩,所以通常不会有写入延迟)
  3. 对t1,t2执行major_compact
  4. 随机分3次读取1W条记录,进行性能统计

建表语句:

  1. create 'benchmark_test1', {NAME => 'cf', COMPRESSION => 'snappy', BLOCKCACHE=>'FALSE'}, {SPLITS => (1..5).map {|i| "user#{1000+i*(9999-1000)/5}"}}
  2. create 'benchmark_test2', {NAME => 'cf', BLOCKCACHE=>'FALSE'}, {SPLITS => (1..5).map {|i| "user#{1000+i*(9999-1000)/5}"}}

yscb测试计划:

  1. recordcount=1000000
  2. operationcount=10000
  3. workload=com.yahoo.ycsb.workloads.CoreWorkload
  4. readallfields=true
  5. readproportion=1
2019-04-22 14:00:43    23    0    0

国外有大神整理了一张大数据技术栈的图,可以用作技术选型参考
图片标题

spark    2019-04-22 10:54:13    20    0    0

1. 使用场景

在spark开发过程中,最常见的用到广播的场景有两个:

  1. 共享第三方存储客户端和连接池(Redis、HBase等):用于读写第三方存储,如果不使用广播可能造成频繁的创建连接,影响性能(即使基于分区创建连接,在分区数较多的情况下也不能避免)。
  2. 共享只读数据:多次使用的只读数据可以使用广播发送到每个节点,避免重复传输,起到性能优化的作用。

2. 实现方式

广播的实现分为几个步骤:

  1. 序列化:由Driver将数据序列化,生成chunks保存在Driver的BlockManager中。
  2. 传输读取:Executor在使用广播变量时首先尝试从本地BlockManager中获取数据,如果获取失败则从Driver或其他Executor的BlockManager获取,最终在首次使用时将数据反序列化成对象。

传输实现有两种方式:HttpBroadcast所有Executor都从Driver获取广播变量、TorrentBroadcastExecutor之间也可以传输广播变量,避免Driver性能瓶颈。

3.示例

使用广播变量的示例网上有很多,这里只列举一个共享第三方存储客户端和连接池的示例。很多初写spark的同事问完怎么共享Redis连接池后又会问怎么广播的时候报不能序列化的异常NotSerializableException,这里强调下,广播的第一步就是将对象序列化,所以类必须继承Seriable接口,但是很多第三方存储的客户端没有实现该接口,就导致这个问题。

这里我们为了避免这个问题,只需要使用懒加载即可,即在Driver序列化的时候对象是可序列化的就能满足要求:

  1. import org.apache.spark.{SparkConf, SparkContext}
  2. import redis.clients.jedis.{HostAndPort, JedisCluster}
  3. //使用RedisSink来封装Redis连接池,避免直接广播JedisCluster
  4. class RedisSink extends Serializable {
  5. //使用lazy修饰的变量,序列化时不会初始化此变量
  6. lazy val clu
HBase    2019-04-20 15:51:28    35    0    0

1. 场景

推荐相关业务数据存储在HBase中,由线上接口进行实时读写。在推荐系统项目初期,通常采用的是离线规则推荐,数据量少,T+1更新,不会对线上HBase有压力。随着实时推荐和千人千面的开展,大量的HBase读写导致HBase读取出现毛刺,影响线上业务稳定性,需要进行针对性调优。

如图,虽然平均读取时间(蓝色)相对稳定,但经常有个别client出现读取毛刺,导致读取熔断(橙色):
图片标题

2. 目标

在支持后续qps继续上升的基础上,消除90%毛刺

3. 瓶颈分析

调优的第一要素:

无监控不调优

首先需要通过监控分析出当前系统的瓶颈所在,常见的HBase瓶颈指标有:

  1. 磁盘读写、IOPS
  2. GC暂停
  3. 排队时间
  4. BlockCache命中率,逐出率
  5. 热点region

通过查看CDH以及HBase自身的监控指标基本可以确认HBase的性能瓶颈所在,针对性进行调优即可。

4. 性能瓶颈及解决

通过监控发现了一些性能瓶颈,通过调优基本得以解决。

4.1. 磁盘读写峰值导致读写延迟

因为Memstore和BlockCache的存在,磁盘通常不会导致性能出现大幅下降,但在某些极端情况下确实会出现。

场景1
CDH监控发现多个Memstore同时flush,且并未达到默认最大值128M,导致磁盘占用高,检查后发现由于

  1. hbase.regionserver.maxlogs=32

大量写入时WAL文件很快写满,导致写入阻塞和memstore刷写。

场景2
部分离线任务启动后HBase磁盘占用骤增,检查后发现写入HBase使用的是put,换用BulkLoad后解决。

这类问题通常考虑减少或避免集中读写磁盘即可解决。

4.2 GC暂停

GC暂停时工作线程无法工作,导致操作延迟。通常由于Memstore和BlockCache的存在,RegionServer的堆内存都比较大,所以GC优化往往效果明显。

场景1
随着实时写入的数据越来越多,GC时间不断增长,slow read和slow write越来越多。

GC的优化可以考虑以下几种方式:

  1. 对8G以上的大堆使用G1收集器
  2. 使用Buck
2019-04-18 17:51:25    58    0    0

1. 服务限流

1.1 什么是服务限流

​ 针对服务最高处理能力设定阈值,对超过该阈值的请求做特殊化处理(排队、降级、拦截等),避免后端服务因突发流量或持续高位流量导致宕机。

1.2 限流的基本思想

​ 限流的本质在于流量整形(Traffic Shaping)和速率限制(Rate Limiting)。限流有两类算法实现:简单计数限流时间窗口限流

图片标题

1.2.1 简单总量计数限流

​ 简单总量计数限流实现非常简单,常见的实现思路有:

  1. 针对整个资源调用总次数进行计数,达到限制后禁止调用

  2. 针对特定参数调用总次数进行计数(用户IP、令牌),特定参数达到限制后禁止调用简单计数限流实现简单,应用也非常广泛:连接池、线程池等,但是最大的问题在于不能限制平均速率

1.2.2 时间窗口限流

​ 为了弥补简单总量计数限流无法限制平均速率的问题引入了基于时间窗口的限流。

令牌桶算法 - Token Bucket

每次调用前去桶中取1个令牌,取到令牌才发起调用,定期向桶中添加令牌,达到限速目的

图片标题

漏斗桶算法 - Leaky Bucket

将每次调用放到漏斗桶中,如果没有溢出则可以正常调用,漏斗桶流出速率固定。

图片标题

令牌桶和漏斗桶的区别在于:令牌桶允许突发流量,而漏斗桶则只允许恒定流量。

为了突出令牌桶允许突发流量的特性,进一步提出了租借令牌,当桶中没有令牌时允许临时获取一定量的令牌(剩余令牌数可为负),但后续调用必须等令牌补充归还后才可获取令牌。(Nginx基于此算法实现)

Linux网络限速是典型的流控算法应用场景,运用了更多高级算法CBQ流量队列控制、HTB分层令牌桶等https://www.ibm.com/developerworks/cn/linux/1412_xiehy_tc/index.html">https://www.ibm.com/developerworks/cn/linux/1412_xiehy_tc/index.html

2. 服务熔断与降级

2.1 什么是服务熔断与降级

熔断是指当某个下游服务出现异常时停止对该服务的调用。

降级则是指某些服务出现熔

redis spring boot    2019-04-18 17:47:47    32    0    0

今天在测试redis节点主备切换时出现了大量连接超时的情况,正常情况下redis客户端连接到任意可用server入口节点都可以获取到整个集群的拓扑,一旦集群节点有变动也会迅速刷新拓扑,保证高可用性。

测试集群共有4主,4备,经检查发现4台备节点被运维迁移了,程序使用的一半是老地址,但是这也无法解释超时的问题(上面说过,成功连接到一台就可以获取整个集群的拓扑)。

经过调试发现,SpringBoot2默认使用Lettuce 作为redis客户端,在默认配置下关闭了拓扑更新功能。。。 上面说过,超时是在主从切换的时候出现的,也就是之前的从节点全部失效,主节点又变为了从节点,而Lettuce为了保证一致性默认只从主节点读写数据(开启从节点读可以参考这里),而拓扑没有更新导致读写主节点(其实已经是从节点了)重定向到当前拓扑不存在的节点,Lecttuce无法使用非集群中的节点,导致超时

  1. public class ClusterTopologyRefreshOptions {
  2. public static final boolean DEFAULT_PERIODIC_REFRESH_ENABLED = false; //定时更新关闭
  3. public static final long DEFAULT_REFRESH_PERIOD = 60;
  4. public static final TimeUnit DEFAULT_REFRESH_PERIOD_UNIT = TimeUnit.SECONDS;
  5. public static final Duration DEFAULT_REFRESH_PERIOD_DURATION = Duration.ofSeconds(DEFAULT_REFRESH_PERIOD);
  6. public static final boolean DEFAULT_DYNAMIC_REFRESH_SOURCES = true;
  7. public static final Set<RefreshTrigger> DEFAULT_ADAPTIVE_REFRESH_TRIGGERS = Collections.emptyS