网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技术,提供稳定流畅、低时延、高并发的视频直播、录制、存储、转码及点播等音视频的PAAS服务,在线教育、远程医疗、娱乐秀场、在线金融等各行业及企业用户只需经过简单的开发即可打造在线音视频平台。现在,网易视频云的技术专家给大家分享一则技术文:Facebook memcache优化经验。
memcache是facebook的重要基础设施, 有数据为证: 缓存了T级记录, 支持每秒G级别访问次数, 单页面经常访问上千次memcache。 facebook从memcache节点、集群、region、跨region等各层次对memcache做了大量优化和改造, 本文简单介绍facebook在memcache节点和集群层次做的一些优化工作。
降低延迟的方法:
并行请求。根据数据依赖关系构建DAG, 无依赖的数据批量发送到memache服务端, 根据统计平均每个请求包括24个key。
通讯优化。get操作使用UDP,删除和更新操作使用TCP, 响应时间降低20%。
流量控制。通过滑动窗口控制单个客户端发出的并发请求数目,避免服务器过载。
降低负载的方法:
Lease, 用于解决 memcache应用过程常见的两个问题: (1)stale sets, 由于并发更新请求发生乱序, 导致memcache中存储了旧的数据; (2)thundering herds(惊群), 读写率特别高的键值, 写操作失效memcache时,大量读操作不命中,导致后端压力激增。 lease的原理是, memcache读不命中时,返回一个64位token给客户端, 只有当token有效时, 才允许客户端加载数据到memcache。 服务端接收到delete请求时(写操作之前应用一般会发送delete请求去失效memcache),则失效键值对应的所有token, 从而避免读不命中的客户端加载老数据到缓存。 memcache服务器限制每个键值10s内只产生一个token, token产生后10s内, 其他客户端若读不到键值,则等待一小段时间之后,再次重试。 由于新的value很快就加载到缓存中, 重试一次读到最新value的概率非常大, 这就彻底避免了thundering herds问题。 根据facebook的实测结果, 在某些场景下有lease能将数据库的qps从17K降低到1.3K。 此外, 删除键值时,只在数据上做一个已删除标志,让数据在缓存中保留一段时间。由于很多应用能够容忍读取旧数据,保留已删除数据可进一步提高效率。
memcache pool。 memcache划分成为不同pool, 以应对应用负载的多样性。
复制。 pool内部实现复制, 提高性能, 复制由客户端控制。
处理节点失败的策略:
保留大约1%节点组成一个Gutter集群, 当memcache服务端无响应时, 转而将数据缓存到gutter集群中。 采用gutter而不是rehash到其他节点的原因是避免负载不均(例如一个key承担了20%致其他节点级联失败。
单机memcached优化技术:
使用可扩展哈希,已经贡献到社区。
多线程, 已经贡献到社区。
每个线程独立监听一个UDP端口,避免冲突。
Adaptive Slab Allocator。 允许多个Slab之间相互替换内存。
优化之后的memcached性能惊人, 32字节GET达到1.8M次每秒( Xeon X5650 ,2.67GHZ, 12cores, 12hyperthreads, intel 82574L 千兆以太网, memcached服务器开了24个线程)。
参考资料:
《scaling memcache at facebook》
Categories:存储Tags:
June 21st, 2013书包不见了Comments off
基本概念:
mysql在做主备复制时,如果主备库的表定义不同, 也就意味着要做异构复制。 attribute promotion 就是当定义Binlog_Format = Row ,并且列属性不同时,slave端在apply binlog时做的结构转换。
按照官方文档来说,在mysql-5.1.21版本开始支持不同表定义之间的复制,主备上列的数目可以不同,属性也可以不同。列数目不同,意味着master的列数目要小于等于slave的列数目,两者的列顺序要一致,slave额外的列需要有defaults值.
主要来看列属性的不同的情况:
在5.1版本中:
row binlog 只支持类似于char(10) 到 char(25) 这样的复制,不允许不同int之间的转换,也不支持char类型的和大对象转换,只有在binlog中使用相同类型表示的列属性间可以转换。并且只支持master端列宽小于slave端的转换方式,而反之会导致truncate的转换是不被支持的。其次所有的前缀唯一索引,必须保证主备的前缀长度一致(否则会导致唯一性错误)
5.1支持的转换类型 (来自官方文档)
From (Master)
To (Slave)
BINARY CHAR
BLOB TEXT
CHAR BINARY
DECIMAL NUMERIC
NUMERIC DECIMAL
TEXT BLOB
VARBINARY VARCHAR
VARCHAR VARBINARY
5.1 不支持的转换类型:
INT (including TINYINT, SMALLINT, MEDIUMINT, BIGINT).
SET or ENUM.
FLOAT or DOUBLE.
All of the data types relating to dates, times, or both: DATE, TIME, DATETIME, TIMESTAMP, and YEAR.
5.5.3版本开始,mysql按照之前mysql cluster的做法,引入了row binlog 的异构复制
row binlog 开始支持更多种类的列属性转换:
引入新参数 slave_type_conversion ,可以设置4个值 ALL_LOSSY(数据被truncate), ALL_NON_LOSSY(不需要被truncate的转换), ALL_LOSSY,ALL_NON_LOSSY(可以兼容以上两种转换), EMPTY(不支持属性转换)
5.5 支持的转换类型(来自官方文档)
Between any of the integer types TINYINT, SMALLINT, MEDIUMINT, INT, and BIGINT.
Between any of the decimal types DECIMAL, FLOAT, DOUBLE, and NUMERIC.
Between any of the string types CHAR, VARCHAR, and TEXT, including conversions between different widths.(不同字符集列之间不支持复制, 会出现主备不一致的状态)
Between any of the binary data types BINARY, VARBINARY, and BLOB, including conversions between different widths.
Between any 2 BIT columns of any 2 sizes.
分析行级binlog attribute promotion的源代码
以下以mysql-5.5.22为例,主要的入口函数为 sql/log_event.cc 中的 Rows_log_event::do_apply_event(Relay_log_info const *rli),在打开表并加完锁之后需要检查是否需要转换。
TABLE *conv_table;
if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),
ptr->table, &conv_table))
{
...
}
ptr->m_conv_table= conv_table;
mysql 遍历所有binlog涉及的表,检测主库binlog传过来的表信息是否和当前slave端的表定义相吻合。如果需要进行列属性转换,则为attribute promote 建立一张内存的临时表来完成,否则传出的conv_table为NULL
compatible_with() 方法流程
1. 检测主备库的最小列数
2. 针对这些列进行是否能转换的检测can_convert_field_to()
a. 判断field->real_type 是否相等
b. 如果real type 相等:
i. 判断metadata是否为0,metadata的size取决于field的real type(例如固定大小的int 类型metaData就为0,而char,varchar类型都有)
ii. 如果metadata为0,直接返回成功,否则的话要比较主备两列的field size 再调用is_conversion_ok()
(i) 根据slave_type_conversion 参数来判断是否能进行转换
c. 如果real type 不相等,又没有设置slave_type_conversion(也就是采用默认值EMPTY),返回上层错误
d. 判断不同用类型之间能否转换(int之间,char到text等等) 先比较列的长度 compare_length()
i. 调用 max_display_length() 方法获得列的最大长度
再判断列类型能否转 is_conversion_ok()
3. 如果检测出结果需要转换,并且临时表为NULL,则建立一张临时转换表create_conversion_table()
4. 如果检测到列类型不能转换,向上层抛错
5. 设置临时转换表中的属性类型
在设置完临时表convert table之后,真正使用是在unpack_current_row 中调用 rpl_record.cc 中的unpack_row
unpack_row () 方法流程:
1. 根据本地表起始指针和结束指针,依次获取每个属性
a. 判断对应的convert_table 是否是NULL, 如果不是NULL则采用convert_table的列,否则采用原本slave 表本身的列, 暂时称这列为f
b. 检测f列的bitmap,并设置null_bits 和 null_mask, 如果有必要的话,设置default值
c. 调用Field::unpack 方法,解析master传过来的binlog数据内容, 拷贝到f列
d. 如果是该列是转换列那么source 和target 各自根据系统字符集开辟一块buffer, 此处是做真正的列类型转换, convert列和master一致,这里采用一个临时的Copy_field做转换,Copy_field是mysql专门用作列转换的辅助类,通过不同的source和target列类型,设置转换函数指针,将convert table中的数据拷贝到最终的slave对应的列中
i. copy.set(*field_ptr, f, TRUE); 设置转换类的各个参数,包括转换函数
ii. (*copy.do_copy)(©); 做拷贝操作
2. 将master data 中复制用不到的那些列丢弃
3. 设置master side 的记录长度
自此attribute promotion 的主要流程完成。
更多技术交流,请关注网易视频云哦!