Contenu connexe
Similaire à Aswan&hump (20)
Aswan&hump
- 2. OfferDetail 访问统计
► 1)大数据量:每天 2000 万 PV 左右,每周 pv 超过
1 亿。去重后 offer 量在 5000~7000 万之间。
► 2)离散性:统计连续的 5 周,对访问去重后将近
1.5 亿 ( 总 offer 为 2.4 亿 ) 。每天有 80% 的 offer
只访问了 1 次,放大到一周,仍有 30% 多的 offer
只被访问 1 次。
► 3)
重叠率不高:以周为单位,第 1 周访问过 offer
在第 2 周又被访问到的约 40~55% 之间。
- 3. 解决方法
► 1) 缓存全部没有意义,找热点
► 2) 即使只缓存热点,想要达到较高的命中
率,也依然要缓存很大量的数据。千万级的
数据量,必须采用分布式
- 4. 思路:冷热交换
出队 入队
Head
权
重
大
的
排
在
队
首
Head
入队 出队
- 5. Aswan 的架构
Client Client Client Client Client Client
Index Index
Scheduler
Storage Storage Storage Storage Storage
- 6. 服务器端的角色
► 1) Scheduler: 调度 / 配置 / 注册中心。事件的中心。
并通过一致性哈希来将数据分布在各台 Storage 上
。
► 2) Index: 索引服务器,用于定位某个 key 存储在
哪个 Storage 上。 Index 可配置单台或多台,上面
的数据是一致的。多台主要起到负载均衡的作用。
► 3) Storage: 存储服务器,根据数据权重的变化自
动调节其级别。
- 7. 客户端
► 与 memcached 的 client 不同,“轻”客户
端, client 知道的很少,服务器端的变化对
client 来说是透明的,比如新增 / 减少
Storage ,对 client 来说是无需了解的。
► client 定时从配置中心获取可用的 Index 列
表。实现方式同 napoli
- 9. Client 的一次请求过程
2) Index 命中 , Storage 未命中的情况:
1 Query
Client
Index
2 命中,返回存储节点
5 Set
4 返回 3 Get
location
Val 为空
Storage
- 10. 数据更新的解决
► 使用 napoli 监听变更
remove
Scheduler Task napoli
remove
Storage Storage Storage
- 11. 存储结构
► 借鉴 Redis 的做法,提供 K-V, K-Hash, K-
List
等结构
应用场景:
1) 页面的异步加载,同一个 id 对应几个
value ,可采用 K-Hash
2) 交易订单数, A 页面显示 20 条, B 页面
显示 10 条,可采用 K-List
- 12. 通讯框架的选择
1, 序列化
1) protocolBuffers: 不适宜在现有业务上采用。
2) json/hessian: 性价比未必高
3) Thrift : 想采用,但不熟悉
4) 现在采用 java serialize + gzip 以后再优化
这里有一个详细的对比:
https://github.com/eishay/jvm-serializers
反馈给温少后,他很快对 fastjson 做了优化,后又根
据江航的建议采用 asm 优化,最 1.1.1 版 fastjson
已经超过了 protoBuffers
- 13. 通讯框架的选择
2, 通讯协议
1) mina/netty : 缺乏 NIO 网络编程的经验,其中的
陷阱也不少。
http://www.slideshare.net/killme2008/nio-trick-and-trap-8464155
2) tb-remoting: dubbo 最初采用的。基于 mina ,
后来 dubbo 开发了自己 dubbo-remoting 通讯框架
,基于 netty3 ,但在写 Aswan 时还没有发布。
3) http: 采用嵌入式 jetty 用于 http 连接管理。简
单,但 http 在并发较高时衰减的较快,性能不佳。
- 14. Jetty 的调优
► 1) 增加 jetty.acceptors 以应对高并发
使用 apache ab 50 并发测试, acceptors=8 比 2 有
明显提高
http 在并发情况下的衰减 (acceptors=2) :
1 个线程 http 耗时平均 1.7ms 左右,
10 个线程并发将衰减到 5ms 左右,
20 个线程并发将衰减到 10ms ,
50 个线程降到 20ms
- 15. Jetty 的调优
► 2) Http-KeepAlive 是否起了作用?
开启 keepAlive , SelectChannelEndPoint 的实
例数应该是较稳定的。
- 16. 事件过程 : 上 -> 下
Storage
IndexServer
EventQueue Scheduler
BlockingQueue
EventQueue 消费端
多线程
单线程串
行通知
- 17. 事件过程 : 上 -> 下
IndexServer Scheduler
EventQueue BlockingQueue 消费者:
单线程
Storage: ChangeRecorder
消费者:
消费者 生产者
单线程 缓冲区 缓冲区
Exchanger :达到一定量再消费
- 18. 事件过程 : 下 -> 上
Storage
Scheduler
Exchanger 多线程
Exchanger
异
步
Exchanger
单线程串
Exchanger 行通知
Index
Index
- 19. 事件队列
► 借鉴 AWT 中的 EventQueue
com.alibaba.aswan.server.index.WeightingChangeEventQueue.java
► 事件的合并: coalesceEvent ,对于离散事
件意义不大。
► 锁分离: 两把锁, putlock 和 tacklock
参考 LinkedBlockingQueue
- 20. 缓冲区的设计
Exchanger : 简单好用。需考虑缓冲区的大小。生产
者的节奏与消费者的节奏是否匹配的上。
Queue: 需考虑批量消费的需求。自实现批量出列,
或者单个出列后累计一定量再一并处理。如果是
BlockingQueue 注意初始容量,太小会导致高并发
情况下生产者阻塞。进而可能引起网络阻塞等连锁
反应。 Aswan 在第一个测试版本遇到过。
- 21. 一致性哈希的选择
► Ketama 通过 MD5 实现
last.fm 最早采用, spy/xmemcached 等
client 也采用。
测试中发现 240 个虚拟节点最佳。
see: com.alibaba.aswan.server.schedule.locator.KetamaLocator.java
► MurmurHash ,更高效的 Hash , Redis 的
java-client 中采用
- 22. 权重因素
► 1) 访问次数: 越多越好
► 2) 最后访问事件:越近越好
权重公式:权重值 = 访问次数 * 系数
系数与最后访问时间有关,越近系数越高:
系数公式: Math.pow(WEEK_FACTOR, lastAccTime - startTime)
// week_factor 是一个经验值
public static final float WEEK_FACTOR = 1.35F
- 23. 权重因素
► 3)
增加优先级属性,某些过大的对象优先
级设置低一些,比如大于 1m 的只能沦为二
等公民,不能存储在 L1 中
- 25. 双向队列的实现
DoubleEndedPriorityQueue
维持 2 个 heap,minheap 和 maxheap
2 7
5 4 6 2
6 7 5 4
Min heap Max heap
http://www.cise.ufl.edu/~sahni/dsaaj/enrich/c13/double.htm
- 26. 性能的考虑
► 1)千万级对象,需要分成很多个区域
否则同步问题成了瓶颈,参考
ConcurrentHashMap 的做法,每 1 万个元素存储在
一个 Segment 上
► 2)
避免频繁的堆排序,堆中元素改变超过一个阈值
再进行重排序。
► 3)
双向堆注意关联影响,对 referent 做一层包装,
清除元素时避免引起堆的调整 , 手动排序。
- 28. 吞吐量优先还是应用响应优先
► UseParallelOldGC or CMS or G1 ?
► 一次 Full GC 的代价?
旧生代的空间有 3.5G
- 30. 线上前台应用的 GC 策略
以 Exodus2 为例: -server -Xmx2g -Xms2g -Xmn512m
-XX:PermSize=128m -XX:MaxPermSize=196m -Xss256k
-XX:+DisableExplicitGC // 禁止外部应用程序强制进行垃圾收集 ,
将 System.gc() 调用转换成一个空操作
-XX:+UseConcMarkSweepGC // 启用 CMS
-XX:+CMSParallelRemarkEnabled // 尽量减少 mark 的时间
-XX:+UseCMSCompactAtFullCollection // 对 live object 进行整理,使
memory 碎片减少
-XX:+UseFastAccessorMethods // 对 get 、 set 方法转成本地代码
-XX:+UseCMSInitiatingOccupancyOnly // 只有在 old generation 在达到初
始化的比例后启动收集
-XX:+UseCompressedOops // 压缩普通对象指针,针对 64 位系统
- 31. ► 默认老年代到 92% 才进行 GC (一些老版
本的 JVM 是 68% )
► 可通过
-XX:CMSInitiatingOccupancyFraction=80
指定为 80% 时进行
- 32. 精简 HashMap
► HashMap 中的 Entry 存在浪费
► 修改 HashMap ,实现一个 MyHashMap
将其初始容量与增长因子设的紧凑一些
► 千万对象,内存节省了约 300m
- 33. 架构的缺陷
► 1) 角色较多
► 2) 2 次网络访问,比 memcached 等多一次
网络开销。
► 3) 想要做到 server 端透明的增减服务器,
但实际这种需求不强烈。
► 4) hump ,一个简化版的热点 cache ,将采
用 dubbo-remoting/fastjson ,类似
memcached 方式。包含 K-List, K-Hash 等
存储结构。
- 34. 分布式领域的一些技术
► Gossip 协议 : 去中心化
又被称为反熵( Anti-Entropy ),反熵就是在杂
乱无章中寻求一致
Gossip 的特点:在一个有界网络中,每个节点都随
机地与其他节点通信,经过一番杂乱无章的通信,
最终所有节点的状态都会达成一致。每个节点可能
知道所有其他节点,也可能仅知道几个邻居节点,
只要这些节可以通过网络连通,最终他们的状态都
是一致的,这也是疫情传播的特点。
- 36. 分布式领域的一些技术
► Paxos 算法 : 解决数据一致性。
算法比较复杂。
Yahoo! 开源的 ZooKeeper 是一个开源的类
Paxos 实现
Google Chubby 也基于 paxos 算法
- 37. 参考
► << 面向模式的软件架构 - 第 4 卷 : 分布式
计算的模式语言 >>
► Napoli Client
► Jedis https://github.com/xetorthio/jedis.git
Redis 的一个 java 客户端
Notes de l'éditeur
- 红色箭头代表事件。 Scheduler 是中心。