SlideShare une entreprise Scribd logo
1  sur  37
阿斯旺与驼峰




hongjiang 2011.7.27
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% 之间。
解决方法

►   1) 缓存全部没有意义,找热点

►   2) 即使只缓存热点,想要达到较高的命中
    率,也依然要缓存很大量的数据。千万级的
    数据量,必须采用分布式
思路:冷热交换
       出队          入队


Head


   权
   重
   大
   的
   排
   在
   队
   首
            Head



       入队          出队
Aswan 的架构
Client    Client       Client               Client       Client    Client




              Index                                        Index


                                Scheduler




    Storage           Storage    Storage             Storage       Storage
服务器端的角色
►   1) Scheduler: 调度 / 配置 / 注册中心。事件的中心。
    并通过一致性哈希来将数据分布在各台 Storage 上
    。

►   2) Index: 索引服务器,用于定位某个 key 存储在
    哪个 Storage 上。 Index 可配置单台或多台,上面
    的数据是一致的。多台主要起到负载均衡的作用。

►   3) Storage: 存储服务器,根据数据权重的变化自
    动调节其级别。
客户端
►     与 memcached 的 client 不同,“轻”客户
    端, client 知道的很少,服务器端的变化对
    client 来说是透明的,比如新增 / 减少
    Storage ,对 client 来说是无需了解的。

►   client 定时从配置中心获取可用的 Index 列
    表。实现方式同 napoli
Client 的一次请求过程
1) 未命中的情况:
   Client       2 未命中,
                返回 null


   1 Query                       6 更新 Index
                       Index


                           3 发送事件         Scheduler


                          4 定位并通知


             Storage
                               5 更新后反馈
Client 的一次请求过程
2) Index 命中 , Storage 未命中的情况:
                      1 Query
        Client
                                  Index
                    2 命中,返回存储节点

5 Set

        4 返回        3 Get
        location
        Val 为空

          Storage
数据更新的解决
►    使用 napoli 监听变更

                           remove
              Scheduler             Task   napoli




                  remove



    Storage   Storage         Storage
存储结构
► 借鉴 Redis 的做法,提供   K-V, K-Hash, K-
 List
 等结构
应用场景:
 1) 页面的异步加载,同一个 id 对应几个
 value ,可采用 K-Hash

 2) 交易订单数, A 页面显示 20 条, B 页面
 显示 10 条,可采用 K-List
通讯框架的选择
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
通讯框架的选择
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 在并发较高时衰减的较快,性能不佳。
Jetty 的调优
►   1) 增加 jetty.acceptors    以应对高并发
         使用 apache ab 50 并发测试, acceptors=8 比 2 有
        明显提高

       http 在并发情况下的衰减 (acceptors=2) :
       1 个线程 http 耗时平均 1.7ms 左右,
       10 个线程并发将衰减到 5ms 左右,
       20 个线程并发将衰减到 10ms ,
       50 个线程降到 20ms
Jetty 的调优
►   2) Http-KeepAlive 是否起了作用?




开启 keepAlive , SelectChannelEndPoint 的实
 例数应该是较稳定的。
事件过程 : 上 -> 下
                                       Storage


IndexServer
EventQueue          Scheduler

                    BlockingQueue

EventQueue                      消费端
              多线程
                                单线程串
                                行通知
事件过程 : 上 -> 下

IndexServer              Scheduler
  EventQueue             BlockingQueue     消费者:
                                           单线程



               Storage: ChangeRecorder



        消费者:
                消费者                  生产者
        单线程     缓冲区                  缓冲区

                 Exchanger :达到一定量再消费
事件过程 : 下 -> 上
Storage

                        Scheduler
Exchanger     多线程


Exchanger




                    异
                    步
                              Exchanger
                                          单线程串
Exchanger                                 行通知



                    Index



                     Index
事件队列
► 借鉴         AWT 中的 EventQueue
    com.alibaba.aswan.server.index.WeightingChangeEventQueue.java


►    事件的合并: coalesceEvent ,对于离散事
    件意义不大。

►     锁分离: 两把锁, putlock 和 tacklock
      参考 LinkedBlockingQueue
缓冲区的设计
Exchanger : 简单好用。需考虑缓冲区的大小。生产
 者的节奏与消费者的节奏是否匹配的上。

Queue: 需考虑批量消费的需求。自实现批量出列,
 或者单个出列后累计一定量再一并处理。如果是
 BlockingQueue 注意初始容量,太小会导致高并发
 情况下生产者阻塞。进而可能引起网络阻塞等连锁
 反应。 Aswan 在第一个测试版本遇到过。
一致性哈希的选择
► Ketama  通过 MD5 实现
 last.fm 最早采用, spy/xmemcached 等
 client 也采用。
 测试中发现 240 个虚拟节点最佳。
 see: com.alibaba.aswan.server.schedule.locator.KetamaLocator.java



► MurmurHash ,更高效的 Hash , Redis 的
 java-client 中采用
权重因素
►   1) 访问次数: 越多越好
►   2) 最后访问事件:越近越好

权重公式:权重值 = 访问次数 * 系数
系数与最后访问时间有关,越近系数越高:
系数公式: Math.pow(WEEK_FACTOR, lastAccTime - startTime)

// week_factor 是一个经验值
public static final float WEEK_FACTOR = 1.35F
权重因素

► 3)
  增加优先级属性,某些过大的对象优先
 级设置低一些,比如大于 1m 的只能沦为二
 等公民,不能存储在 L1 中
Storage 的内部结构




                       L2                L1
ColdPool
                  Val 存在磁盘          Val 存在内存




           Swap              Swap
双向队列的实现
      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
性能的考虑
► 1)千万级对象,需要分成很多个区域
    否则同步问题成了瓶颈,参考
 ConcurrentHashMap 的做法,每 1 万个元素存储在
 一个 Segment 上

► 2)
  避免频繁的堆排序,堆中元素改变超过一个阈值
 再进行重排序。

► 3)
  双向堆注意关联影响,对 referent 做一层包装,
 清除元素时避免引起堆的调整 , 手动排序。
GC 策略与内存调优




对象太大,采用 Gzip 压缩后平均每个线上
 的 OfferDO 对象 5.5k (detail 字段占了大
 头)
吞吐量优先还是应用响应优先
►   UseParallelOldGC or CMS or G1 ?

►   一次 Full GC 的代价?
     旧生代的空间有 3.5G
按代 GC 策略的组合方式




http://blogs.oracle.com/jonthecollector/entry/our_collectors
线上前台应用的 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 位系统
►    默认老年代到 92% 才进行 GC (一些老版
    本的 JVM 是 68% )

► 可通过
-XX:CMSInitiatingOccupancyFraction=80
 指定为 80% 时进行
精简 HashMap
► HashMap 中的 Entry 存在浪费


► 修改 HashMap ,实现一个 MyHashMap
将其初始容量与增长因子设的紧凑一些

► 千万对象,内存节省了约 300m
架构的缺陷
► 1) 角色较多
► 2) 2 次网络访问,比 memcached 等多一次
 网络开销。
► 3) 想要做到 server 端透明的增减服务器,
 但实际这种需求不强烈。
► 4) hump ,一个简化版的热点 cache ,将采
 用 dubbo-remoting/fastjson ,类似
 memcached 方式。包含 K-List, K-Hash 等
 存储结构。
分布式领域的一些技术
►    Gossip 协议 : 去中心化
      又被称为反熵( Anti-Entropy ),反熵就是在杂
    乱无章中寻求一致
    Gossip 的特点:在一个有界网络中,每个节点都随
    机地与其他节点通信,经过一番杂乱无章的通信,
    最终所有节点的状态都会达成一致。每个节点可能
    知道所有其他节点,也可能仅知道几个邻居节点,
    只要这些节可以通过网络连通,最终他们的状态都
    是一致的,这也是疫情传播的特点。
分布式领域的一些技术
Gossip 的案例 :

►    Cassandra

►    Redis 的分布式实现草案。
    http://redis.io/presentation/Redis_Cluster.pdf
分布式领域的一些技术
►   Paxos 算法 : 解决数据一致性。
      算法比较复杂。

Yahoo! 开源的 ZooKeeper 是一个开源的类
  Paxos 实现

Google Chubby 也基于 paxos 算法
参考
►   << 面向模式的软件架构 - 第 4 卷 : 分布式
    计算的模式语言 >>

►   Napoli Client

►   Jedis https://github.com/xetorthio/jedis.git
     Redis 的一个 java 客户端

Contenu connexe

Tendances

深入剖析Concurrent hashmap中的同步机制(上)
深入剖析Concurrent hashmap中的同步机制(上)深入剖析Concurrent hashmap中的同步机制(上)
深入剖析Concurrent hashmap中的同步机制(上)
wang hongjiang
 
Java线上应用问题排查方法和工具(空望)
Java线上应用问题排查方法和工具(空望)Java线上应用问题排查方法和工具(空望)
Java线上应用问题排查方法和工具(空望)
ykdsg
 
Java cpu
Java cpuJava cpu
Java cpu
ykdsg
 
Btrace intro(撒迦)
Btrace intro(撒迦)Btrace intro(撒迦)
Btrace intro(撒迦)
ykdsg
 
Sun jdk 1.6内存管理 -使用篇
Sun jdk 1.6内存管理 -使用篇Sun jdk 1.6内存管理 -使用篇
Sun jdk 1.6内存管理 -使用篇
bluedavy lin
 
基于MHA的MySQL高可用方案
基于MHA的MySQL高可用方案基于MHA的MySQL高可用方案
基于MHA的MySQL高可用方案
Louis liu
 

Tendances (20)

深入剖析Concurrent hashmap中的同步机制(上)
深入剖析Concurrent hashmap中的同步机制(上)深入剖析Concurrent hashmap中的同步机制(上)
深入剖析Concurrent hashmap中的同步机制(上)
 
Java线上应用问题排查方法和工具(空望)
Java线上应用问题排查方法和工具(空望)Java线上应用问题排查方法和工具(空望)
Java线上应用问题排查方法和工具(空望)
 
并发编程交流
并发编程交流并发编程交流
并发编程交流
 
Java cpu
Java cpuJava cpu
Java cpu
 
Effective linux.1.(commandline)
Effective linux.1.(commandline)Effective linux.1.(commandline)
Effective linux.1.(commandline)
 
Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)
 
Mysql展示功能与源码对应
Mysql展示功能与源码对应Mysql展示功能与源码对应
Mysql展示功能与源码对应
 
高性能的Java代码编写及常见问题排查
高性能的Java代码编写及常见问题排查高性能的Java代码编写及常见问题排查
高性能的Java代码编写及常见问题排查
 
Btrace intro(撒迦)
Btrace intro(撒迦)Btrace intro(撒迦)
Btrace intro(撒迦)
 
Sun jdk 1.6内存管理 -使用篇
Sun jdk 1.6内存管理 -使用篇Sun jdk 1.6内存管理 -使用篇
Sun jdk 1.6内存管理 -使用篇
 
主库自动切换 V2.0
主库自动切换 V2.0主库自动切换 V2.0
主库自动切换 V2.0
 
基于MHA的MySQL高可用方案
基于MHA的MySQL高可用方案基于MHA的MySQL高可用方案
基于MHA的MySQL高可用方案
 
IOS入门分享
IOS入门分享IOS入门分享
IOS入门分享
 
Effective linux.2.(tools)
Effective linux.2.(tools)Effective linux.2.(tools)
Effective linux.2.(tools)
 
Docker進階探討
Docker進階探討Docker進階探討
Docker進階探討
 
Java内存管理问题案例分享
Java内存管理问题案例分享Java内存管理问题案例分享
Java内存管理问题案例分享
 
UseNUMA做了什么?(2012-03-14)
UseNUMA做了什么?(2012-03-14)UseNUMA做了什么?(2012-03-14)
UseNUMA做了什么?(2012-03-14)
 
JVM及其调优
JVM及其调优JVM及其调优
JVM及其调优
 
Rpc原理与实现
Rpc原理与实现Rpc原理与实现
Rpc原理与实现
 
为啥别读HotSpot VM的源码(2012-03-03)
为啥别读HotSpot VM的源码(2012-03-03)为啥别读HotSpot VM的源码(2012-03-03)
为啥别读HotSpot VM的源码(2012-03-03)
 

En vedette

Scala function-and-closures
Scala function-and-closuresScala function-and-closures
Scala function-and-closures
wang hongjiang
 
深入剖析Concurrent hashmap中的同步机制(下)
深入剖析Concurrent hashmap中的同步机制(下)深入剖析Concurrent hashmap中的同步机制(下)
深入剖析Concurrent hashmap中的同步机制(下)
wang hongjiang
 

En vedette (20)

聊一些电影
聊一些电影聊一些电影
聊一些电影
 
善用工具
善用工具善用工具
善用工具
 
Enum开锁
Enum开锁Enum开锁
Enum开锁
 
中等创业公司后端技术选型
中等创业公司后端技术选型中等创业公司后端技术选型
中等创业公司后端技术选型
 
Scala function-and-closures
Scala function-and-closuresScala function-and-closures
Scala function-and-closures
 
functional-scala
functional-scalafunctional-scala
functional-scala
 
Scala类型系统
Scala类型系统Scala类型系统
Scala类型系统
 
Hash map导致cpu100% 的分析
Hash map导致cpu100% 的分析Hash map导致cpu100% 的分析
Hash map导致cpu100% 的分析
 
深入剖析Concurrent hashmap中的同步机制(下)
深入剖析Concurrent hashmap中的同步机制(下)深入剖析Concurrent hashmap中的同步机制(下)
深入剖析Concurrent hashmap中的同步机制(下)
 
Real world akka recepies v3
Real world akka recepies v3Real world akka recepies v3
Real world akka recepies v3
 
Automatic Scaling Iterative Computations
Automatic Scaling Iterative ComputationsAutomatic Scaling Iterative Computations
Automatic Scaling Iterative Computations
 
Behavioral Simulations in MapReduce
Behavioral Simulations in MapReduceBehavioral Simulations in MapReduce
Behavioral Simulations in MapReduce
 
Apache Kafka, and the Rise of Stream Processing
Apache Kafka, and the Rise of Stream ProcessingApache Kafka, and the Rise of Stream Processing
Apache Kafka, and the Rise of Stream Processing
 
Apache Kafka at LinkedIn
Apache Kafka at LinkedInApache Kafka at LinkedIn
Apache Kafka at LinkedIn
 
Building Realtim Data Pipelines with Kafka Connect and Spark Streaming
Building Realtim Data Pipelines with Kafka Connect and Spark StreamingBuilding Realtim Data Pipelines with Kafka Connect and Spark Streaming
Building Realtim Data Pipelines with Kafka Connect and Spark Streaming
 
Building a Replicated Logging System with Apache Kafka
Building a Replicated Logging System with Apache KafkaBuilding a Replicated Logging System with Apache Kafka
Building a Replicated Logging System with Apache Kafka
 
Building Stream Infrastructure across Multiple Data Centers with Apache Kafka
Building Stream Infrastructure across Multiple Data Centers with Apache KafkaBuilding Stream Infrastructure across Multiple Data Centers with Apache Kafka
Building Stream Infrastructure across Multiple Data Centers with Apache Kafka
 
Building Reactive Distributed Systems For Streaming Big Data, Analytics & Mac...
Building Reactive Distributed Systems For Streaming Big Data, Analytics & Mac...Building Reactive Distributed Systems For Streaming Big Data, Analytics & Mac...
Building Reactive Distributed Systems For Streaming Big Data, Analytics & Mac...
 
Introduction to Kafka Streams
Introduction to Kafka StreamsIntroduction to Kafka Streams
Introduction to Kafka Streams
 
泛型总结
泛型总结泛型总结
泛型总结
 

Similaire à Aswan&hump

基于MySQL开放复制协议的同步扩展
基于MySQL开放复制协议的同步扩展基于MySQL开放复制协议的同步扩展
基于MySQL开放复制协议的同步扩展
Sky Jian
 
Apache trafficserver
Apache trafficserverApache trafficserver
Apache trafficserver
Din Dindin
 
大型视频网站单点分析与可用性提升-Qcon2011
大型视频网站单点分析与可用性提升-Qcon2011大型视频网站单点分析与可用性提升-Qcon2011
大型视频网站单点分析与可用性提升-Qcon2011
Yiwei Ma
 
Cassandra简介.ppt
Cassandra简介.pptCassandra简介.ppt
Cassandra简介.ppt
james tong
 
阿里云技术实践
阿里云技术实践阿里云技术实践
阿里云技术实践
drewz lin
 
Track2 -刘继伟--openstack in gamewave
Track2 -刘继伟--openstack in gamewaveTrack2 -刘继伟--openstack in gamewave
Track2 -刘继伟--openstack in gamewave
OpenCity Community
 
Bypat博客出品-服务器运维集群方法总结3
Bypat博客出品-服务器运维集群方法总结3Bypat博客出品-服务器运维集群方法总结3
Bypat博客出品-服务器运维集群方法总结3
redhat9
 
Java垃圾收集原理
Java垃圾收集原理Java垃圾收集原理
Java垃圾收集原理
yin gong
 
Java垃圾收集原理
Java垃圾收集原理Java垃圾收集原理
Java垃圾收集原理
yin gong
 

Similaire à Aswan&hump (20)

Web请求异步处理和海量数据即时分析在淘宝开放平台的实践
Web请求异步处理和海量数据即时分析在淘宝开放平台的实践Web请求异步处理和海量数据即时分析在淘宝开放平台的实践
Web请求异步处理和海量数据即时分析在淘宝开放平台的实践
 
Large-Scale Cluster Mangement & Kubernetes Under The Hood
Large-Scale Cluster Mangement & Kubernetes Under The HoodLarge-Scale Cluster Mangement & Kubernetes Under The Hood
Large-Scale Cluster Mangement & Kubernetes Under The Hood
 
基于MySQL开放复制协议的同步扩展
基于MySQL开放复制协议的同步扩展基于MySQL开放复制协议的同步扩展
基于MySQL开放复制协议的同步扩展
 
Apache trafficserver
Apache trafficserverApache trafficserver
Apache trafficserver
 
大型视频网站单点分析与可用性提升-Qcon2011
大型视频网站单点分析与可用性提升-Qcon2011大型视频网站单点分析与可用性提升-Qcon2011
大型视频网站单点分析与可用性提升-Qcon2011
 
Cassandra简介.ppt
Cassandra简介.pptCassandra简介.ppt
Cassandra简介.ppt
 
Golang 高性能实战
Golang 高性能实战Golang 高性能实战
Golang 高性能实战
 
My sql管理基础 李春_v2
My sql管理基础 李春_v2My sql管理基础 李春_v2
My sql管理基础 李春_v2
 
Hacking Nginx at Taobao
Hacking Nginx at TaobaoHacking Nginx at Taobao
Hacking Nginx at Taobao
 
容器云对研发工作的挑战与机遇
容器云对研发工作的挑战与机遇 容器云对研发工作的挑战与机遇
容器云对研发工作的挑战与机遇
 
阿里云技术实践
阿里云技术实践阿里云技术实践
阿里云技术实践
 
丁原:海量数据迁移方案
丁原:海量数据迁移方案丁原:海量数据迁移方案
丁原:海量数据迁移方案
 
MongoDB at Qihoo 360
MongoDB at Qihoo 360MongoDB at Qihoo 360
MongoDB at Qihoo 360
 
Nosql三步曲
Nosql三步曲Nosql三步曲
Nosql三步曲
 
Track2 -刘继伟--openstack in gamewave
Track2 -刘继伟--openstack in gamewaveTrack2 -刘继伟--openstack in gamewave
Track2 -刘继伟--openstack in gamewave
 
Bypat博客出品-服务器运维集群方法总结3
Bypat博客出品-服务器运维集群方法总结3Bypat博客出品-服务器运维集群方法总结3
Bypat博客出品-服务器运维集群方法总结3
 
Linux内存管理
Linux内存管理Linux内存管理
Linux内存管理
 
Linux内存管理
Linux内存管理Linux内存管理
Linux内存管理
 
Java垃圾收集原理
Java垃圾收集原理Java垃圾收集原理
Java垃圾收集原理
 
Java垃圾收集原理
Java垃圾收集原理Java垃圾收集原理
Java垃圾收集原理
 

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
  • 8. Client 的一次请求过程 1) 未命中的情况: Client 2 未命中, 返回 null 1 Query 6 更新 Index Index 3 发送事件 Scheduler 4 定位并通知 Storage 5 更新后反馈
  • 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 中
  • 24. Storage 的内部结构 L2 L1 ColdPool Val 存在磁盘 Val 存在内存 Swap Swap
  • 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 做一层包装, 清除元素时避免引起堆的调整 , 手动排序。
  • 27. GC 策略与内存调优 对象太大,采用 Gzip 压缩后平均每个线上 的 OfferDO 对象 5.5k (detail 字段占了大 头)
  • 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 的特点:在一个有界网络中,每个节点都随 机地与其他节点通信,经过一番杂乱无章的通信, 最终所有节点的状态都会达成一致。每个节点可能 知道所有其他节点,也可能仅知道几个邻居节点, 只要这些节可以通过网络连通,最终他们的状态都 是一致的,这也是疫情传播的特点。
  • 35. 分布式领域的一些技术 Gossip 的案例 : ► Cassandra ► Redis 的分布式实现草案。 http://redis.io/presentation/Redis_Cluster.pdf
  • 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

  1. 红色箭头代表事件。 Scheduler 是中心。