
正文
php数据分布图 php 数据分析 图
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
php的memcached分布式hash算法,如何解决分布不均?crc32这个算法没办法把key值均匀的分布出去
memcachedphp数据分布图的总结和分布式一致性hash
当前很多大型的web系统为php数据分布图了减轻数据库服务器负载php数据分布图,会采用memchached作为缓存系统以提高响应速度。
目录: ()
memchached简介
hash
取模
一致性hash
虚拟节点
源码解析
参考资料
1. memchached简介
memcached是一个开源的高性能分布式内存对象缓存系统。
其实思想还是比较简单的php数据分布图,实现包括server端(memcached开源项目一般只单指server端)和client端两部分:
server端本质是一个in-memory key-value storephp数据分布图,通过在内存中维护一个大的hashmap用来存储小块的任意数据,对外通过统一的简单接口(memcached protocol)来提供操作。
client端是一个library,负责处理memcached protocol的网络通信细节,与memcached server通信,针对各种语言的不同实现分装了易用的API实现了与不同语言平台的集成。
web系统则通过client库来使用memcached进行对象缓存。
2. hash
memcached的分布式主要体现在client端,对于server端,仅仅是部署多个memcached server组成集群,每个server独自维护自己的数据(互相之间没有任何通信),通过daemon监听端口等待client端的请求。
而在client端,通过一致的hash算法,将要存储的数据分布到某个特定的server上进行存储,后续读取查询使用同样的hash算法即可定位。
client端可以采用各种hash算法来定位server:
取模
最简单的hash算法
targetServer = serverList[hash(key) % serverList.size]
直接用key的hash值(计算key的hash值的方法可以自由选择,比如算法CRC32、MD5,甚至本地hash系统,如java的hashcode)模上server总数来定位目标server。这种算法不仅简单,而且具有不错的随机分布特性。
但是问题也很明显,server总数不能轻易变化。因为如果增加/减少memcached server的数量,对原先存储的所有key的后续查询都将定位到别的server上,导致所有的cache都不能被命中而失效。
一致性hash
为了解决这个问题,需要采用一致性hash算法(consistent hash)
相对于取模的算法,一致性hash算法除了计算key的hash值外,还会计算每个server对应的hash值,然后将这些hash值映射到一个有限的值域上(比如0~2^32)。通过寻找hash值大于hash(key)的最小server作为存储该key数据的目标server。如果找不到,则直接把具有最小hash值的server作为目标server。
为了方便理解,可以把这个有限值域理解成一个环,值顺时针递增。
如上图所示,集群中一共有5个memcached server,已通过server的hash值分布到环中。
如果现在有一个写入cache的请求,首先计算x=hash(key),映射到环中,然后从x顺时针查找,把找到的第一个server作为目标server来存储cache,如果超过了2^32仍然找不到,则命中第一个server。比如x的值介于A~B之间,那么命中的server节点应该是B节点
可以看到,通过这种算法,对于同一个key,存储和后续的查询都会定位到同一个memcached server上。
那么它是怎么解决增/删server导致的cache不能命中的问题呢?
假设,现在增加一个server F,如下图
此时,cache不能命中的问题仍然存在,但是只存在于B~F之间的位置(由C变成了F),其他位置(包括F~C)的cache的命中不受影响(删除server的情况类似)。尽管仍然有cache不能命中的存在,但是相对于取模的方式已经大幅减少了不能命中的cache数量。
虚拟节点
但是,这种算法相对于取模方式也有一个缺陷:当server数量很少时,很可能他们在环中的分布不是特别均匀,进而导致cache不能均匀分布到所有的server上。
如图,一共有3台server – 1,2,4。命中4的几率远远高于1和2。
为解决这个问题,需要使用虚拟节点的思想:为每个物理节点(server)在环上分配100~200个点,这样环上的节点较多,就能抑制分布不均匀。
当为cache定位目标server时,如果定位到虚拟节点上,就表示cache真正的存储位置是在该虚拟节点代表的实际物理server上。
另外,如果每个实际server的负载能力不同,可以赋予不同的权重,根据权重分配不同数量的虚拟节点。
// 采用有序map来模拟环
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//用MD5来计算key和server的hash值
// 计算总权重
if ( this.totalWeight for ( int i = 0; i this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 为每个server分配虚拟节点
for ( int i = 0; i servers.length; i++ ) {
// 计算当前server的权重
int thisWeight = 1;
if ( this.weights != null this.weights[i] != null )
thisWeight = this.weights[i];
// factor用来控制每个server分配的虚拟节点数量
// 权重都相同时,factor=40
// 权重不同时,factor=40*server总数*该server权重所占的百分比
// 总的来说,权重越大,factor越大,可以分配越多的虚拟节点
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j factor; j++ ) {
// 每个server有factor个hash值
// 使用server的域名或IP加上编号来计算hash值
// 比如server - "172.45.155.25:11111"就有factor个数据用来生成hash值:
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// 每个hash值生成4个虚拟节点
for ( int h = 0 ; h 4; h++ ) {
Long k =
((long)(d[3+h*4]0xFF) 24)
| ((long)(d[2+h*4]0xFF) 16)
| ((long)(d[1+h*4]0xFF) 8 )
| ((long)(d[0+h*4]0xFF));
// 在环上保存节点
consistentBuckets.put( k, servers[i] );
}
}
// 每个server一共分配4*factor个虚拟节点
}
// 采用有序map来模拟环
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//用MD5来计算key和server的hash值
// 计算总权重
if ( this.totalWeight for ( int i = 0; i this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 为每个server分配虚拟节点
for ( int i = 0; i servers.length; i++ ) {
// 计算当前server的权重
int thisWeight = 1;
if ( this.weights != null this.weights[i] != null )
thisWeight = this.weights[i];
// factor用来控制每个server分配的虚拟节点数量
// 权重都相同时,factor=40
// 权重不同时,factor=40*server总数*该server权重所占的百分比
// 总的来说,权重越大,factor越大,可以分配越多的虚拟节点
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j factor; j++ ) {
// 每个server有factor个hash值
// 使用server的域名或IP加上编号来计算hash值
// 比如server - "172.45.155.25:11111"就有factor个数据用来生成hash值:
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// 每个hash值生成4个虚拟节点
for ( int h = 0 ; h 4; h++ ) {
Long k =
((long)(d[3+h*4]0xFF) 24)
| ((long)(d[2+h*4]0xFF) 16)
| ((long)(d[1+h*4]0xFF) 8 )
| ((long)(d[0+h*4]0xFF));
// 在环上保存节点
consistentBuckets.put( k, servers[i] );
}
}
// 每个server一共分配4*factor个虚拟节点
}
// 用MD5来计算key的hash值
MessageDigest md5 = MD5.get();
md5.reset();
md5.update( key.getBytes() );
byte[] bKey = md5.digest();
// 取MD5值的低32位作为key的hash值
long hv = ((long)(bKey[3]0xFF) 24) | ((long)(bKey[2]0xFF) 16) | ((long)(bKey[1]0xFF) 8 ) | (long)(bKey[0]0xFF);
// hv的tailMap的第一个虚拟节点对应的即是目标server
SortedMap tmap = this.consistentBuckets.tailMap( hv );
return ( tmap.isEmpty() ) ? this.consistentBuckets.firstKey() : tmap.firstKey();
更多问题到问题求助专区()
相关问答
Q1: 用 PHP 实现的简单线性回归
在这个由两部分组成的系列文章的第 部分(“ 用 PHP 实现的简单线性回归”)中 php数据分布图我说明php数据分布图了数学库对 PHP 有用的原因 php数据分布图我还演示了如何用 PHP 作为实现语言来开发和实现简单线性回归算法的核心部分
本文的目标是向您展示如何使用第 部分中讨论的 SimpleLinearRegression 类来构建一个重要的数据研究工具
简要回顾 概念
简单线性回归建模背后的基本目标是从成对的 X值和 Y值(即 X和 Y测量值)组成的二维平面中找到最吻合的直线 一旦用 最小方差法找到这条直线 就可以执行各种统计测试 以确定这条直线与观测到的 Y值的偏离量吻合程度
线性方程( y = mx + b)有两个参数必须根据所提供的 X和 Y数据估算出来 它们是斜率( m)和 y 轴截距( b) 一旦估算出这两个参数 就可以将观测值输入线性方程 并观察方程所生成的 Y预测值
要使用最小方差法估算出 m和 b参数 就要找到 m 和 b 的估计值 使它们对于所有的 X值得到的 Y值的观测值和预测值最小 观测值和预测值之差称为误差( y i (mx i+ b) ) 并且 如果对每个误差值都求平方 然后求这些残差的和 其结果是一个被称为 预测平方差的数 使用最小方差法来确定最吻合的直线涉及寻找使预测方差最小的 m和 b的估计值
可以用两种基本方法来找到满足最小方差法的估计值 m和 b 第一种方法 可以使用数值搜索过程设定不同的 m和 b值并对它们求值 最终决定产生最小方差的估计值 第二种方法是使用微积分找到用于估算 m和 b 的方程 php数据分布图我不打算深入讨论推导出这些方程所涉及的微积分 但我确实在 SimpleLinearRegression 类中使用了这些分析方程 以找到 m和 b 的最小平方估计值(请参阅 SimpleLinearRegression 类中的 getSlope() 和 getYIntercept 方法)
即使拥有了可以用来找到 m和 b的最小平方估计值的方程 也并不意味着只要将这些参数代入线性方程 其结果就是一条与数据良好吻合的直线 这个简单线性回归过程中的下一步是确定其余的预测方差是否可以接受
可以使用统计决策过程来否决“直线与数据吻合”这个备择假设 这个过程基于对 T 统计值的计算 使用概率函数求得随机大的观测值的概率 正如第 部分所提到的 SimpleLinearRegression 类生成了为数众多的汇总值 其中一个重要的汇总值是 T 统计值 它可以用来衡量线性方程与数据的吻合程度 如果吻合良好 则 T 统计值往往是一个较大的值 如果 T 值很小 就应该用一个缺省模型代替您的线性方程 该模型假定 Y值的平均值是最佳预测值(因为一组值的平均值通常可以是下一个观测值的有用的预测值)
要测试 T 统计值是否大到可以不用 Y值的平均值作为最佳预测值 需要计算随机获得 T 统计值的概率 如果概率很低 那就可以不采用平均值是最佳预测值这一无效假设 并且相应地可以确信简单线性模型是与数据良好吻合的 (有关计算 T 统计值概率的更多信息 请参阅第 部分 )
回过头讨论统计决策过程 它告诉您何时不采用无效假设 却没有告诉您是否接受备择假设 在研究环境中 需要通过理论参数和统计参数来建立线性模型备择假设
您将构建的数据研究工具实现了用于线性模型(T 测试)的统计决策过程 并提供了可以用来构造理论和统计参数的汇总数据 这些参数是建立线性模型所需要的 数据研究工具可以归类为决策支持工具 供知识工作者在中小规模的数据集中研究模式
从学习的角度来看 简单线性回归建模值得研究 因为它是理解更高级形式的统计建模的必由之路 例如 简单线性回归中的许多核心概念为理解多次回归(Multiple Regression) 要素分析(Factor Analysis)和时间序列(Time Series)等建立了良好的基础
简单线性回归还是一种多用途的建模技术 通过转换原始数据(通常用对数或幂转换) 可以用它来为曲线数据建模 这些转换可以使数据线性化 这样就可以使用简单线性回归来为数据建模 所生成的线性模型将被表示为与被转换值相关的线性公式
回页首
概率函数
在前一篇文章中 我通过交由 R 来求得概率值 从而避开了用 PHP 实现概率函数的问题 我对这个解决方案并非完全满意 因此我开始研究这个问题 开发基于 PHP 的概率函数需要些什么
我开始上网查找信息和代码 一个两者兼有的来源是书籍 Numerical Recipes in C 中的概率函数 我用 PHP 重新实现了一些概率函数代码( gammln c 和 betai c 函数) 但我对结果还是不满意 与其它一些实现相比 其代码似乎多了些 此外 我还需要反概率函数
幸运的是 我偶然发现了 John Pezzullo 的 Interactive Statistical Calculation John 关于 概率分布函数的网站上有我需要的所有函数 为便于学习 这些函数已用 JavaScript 实现
我将 Student T 和 Fisher F 函数移植到了 PHP 我对 API 作了一点改动 以便符合 Java 命名风格 并将所有函数嵌入到名为 Distribution 的类中 该实现的一个很棒的功能是 doCommonMath 方法 这个库中的所有函数都重用了它 我没有花费力气去实现的其它测试(正态测试和卡方测试)也都使用 doCommonMath 方法
这次移植的另一个方面也值得注意 通过使用 JavaScript 用户可以将动态确定的值赋给实例变量 譬如
var PiD = pi() /
在 PHP 中不能这样做 只能把简单的常量值赋给实例变量 希望在 PHP 中会解决这个缺陷
请注意 清单 中的代码并未定义实例变量 — 这是因为在 JavaScript 版本中 它们是动态赋予的值
清单 实现概率函数
?php // Distribution php // Copyright John Pezullo // Released under same terms as PHP // PHP Port and OO fying by Paul Meagher class Distribution { function doCommonMath($q $i $j $b) { $zz = ; $z = $zz; $k = $i; while($k = $j) { $zz = $zz * $q * $k / ($k $b); $z = $z + $zz; $k = $k + ; } return $z; } function getStudentT($t $df) { $t = abs($t); $w = $t / sqrt($df); $th = atan($w); if ($df == ) { return $th / (pi() / ); } $sth = sin($th); $cth = cos($th); if( ($df % ) == ) { return ($th + $sth * $cth * $this doCommonMath($cth * $cth $df )) / (pi()/ ); } else { return $sth * $this doCommonMath($cth * $cth $df ); } } function getInverseStudentT($p $df) { $v = ; $dv = ; $t = ; while($dv e ) { $t = ( / $v) ; $dv = $dv / ; if ( $this getStudentT($t $df) $p) { $v = $v $dv; } else { $v = $v + $dv; } } return $t; } function getFisherF($f $n $n ) { // implemented but not shown } function getInverseFisherF($p $n $n ) { // implemented but not shown } } ?
回页首
图形输出
迄今为止 您已经实现的输出方法都以 HTML 格式显示汇总值 它也适合于用 GIF JPEG 或 PNG 格式显示这些数据的分布图(scatter plot)或线图(line plot)
与其亲自编写生成线图和分布图的代码 我认为最好使用名为 JpGraph的基于 PHP 的图形库 JpGraph 正由 Johan Persson 积极开发 其 项目网站这样描述它
无论是对于只有最少代码的“以快捷但不恰当方式获得的”图形 还是对于需要非常细粒度控制的复杂专业图形 JpGraph 都可以使它们的绘制变得简单 JpGraph 同样适用于科学和商业类型的图形
JpGraph 分发版中包含大量可以根据特定需求进行定制的示例脚本 将 JpGraph 用于数据研究工具非常简单 只需找到功能与我的需求类似的示例脚本 然后对该脚本进行改写以满足我的特定需求即可
清单 中的脚本是从样本数据研究工具( explore php)中抽取的 它演示了如何调用该库以及如何将来自于 SimpleLinearRegression 分析的数据填入 Line 和 Scatter 类 这段代码中的注释是 Johan Persson 编写的(JPGraph 代码库的文档化工作做得很好)
清单 来自于样本数据研究工具 explore php 的函数的详细内容
?php // Snippet extracted from explore php script include ("jpgraph/jpgraph php"); include ("jpgraph/jpgraph_scatter php"); include ("jpgraph/jpgraph_line php"); // Create the graph $graph = new Graph( auto ); $graph SetScale("linlin"); // Setup title $graph title Set("$title"); $graph img SetMargin( ); $graph xaxis SetTitle("$x_name" "center"); $graph yaxis SetTitleMargin( ); $graph yaxis title Set("$y_name"); $graph title SetFont(FF_FONT FS_BOLD); // make sure that the X axis is always at the // bottom at the plot and not just at Y= which is // the default position $graph xaxis SetPos( min ); // Create the scatter plot with some nice colors $sp = new ScatterPlot($slr Y $slr X); $sp mark SetType(MARK_FILLEDCIRCLE); $sp mark SetFillColor("red"); $sp SetColor("blue"); $sp SetWeight( ); $sp mark SetWidth( ); // Create the regression line $lplot = new LinePlot($slr PredictedY $slr X); $lplot SetWeight( ); $lplot SetColor( navy ); // Add the pltos to the line $graph Add($sp ); $graph Add($lplot); // and stroke $graph_name = "temp/test png"; $graph Stroke($graph_name); ? img src= ?php echo $graph_name ? vspace= ?
回页首
数据研究脚本
该数据研究工具由单个脚本( explore php)构成 该脚本调用 SimpleLinearRegressionHTML 类和 JpGraph 库的方法
该脚本使用了简单的处理逻辑 该脚本的第一部分对所提交的表单数据执行基本验证 如果这些表单数据通过验证 则执行该脚本的第二部分
该脚本的第二部分所包含的代码用于分析数据 并以 HTML 和图形格式显示汇总结果 清单 中显示了 explore php脚本的基本结构
清单 explore php 的结构
lishixinzhi/Article/program/PHP/201311/21213
Q2: 怎么利用php mysql 在网页上制作直方图
可以配合css样式实现,如果读取的数据为59%。则css样式高度为59%
php数据分布图的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于php 数据分析 图、php数据分布图的信息别忘了在本站进行查找喔。





