这是我参与8月更文挑战的第 11 天,活动详情查看:8月更文挑战
作者简介:悟空,8年一线互联网开发和架构经验,用故事讲解分布式、架构设计、Java 核心技术。《JVM性能优化实战》专栏作者,开源了《Spring Cloud 实战 PassJava》项目,公众号:
悟空聊架构。本文已收录至 www.passjava.cn
今天遇到一个平均分配的问题,分享下解决思路。
例子:5个苹果:编号 a1, b1,c1, d1, e1,分配给3个勇士:ABC,编号为 ABC,实现随机平均分配。 期望结果:A=[a1,d1],B=[b1,e1],C=[c1]。
思路:用的 hash 算法的思路,给勇士和苹果编号,遍历苹果,然后用苹果的编号 % 3,得到的余数就是勇士的编号,然后把这个苹果分配给这个勇士。数据库的分库就是这个思路。目前代码中已实现。
for (i = 0; i < 苹果总数; i++) {
映射关系表 = [
"苹果" => 苹果数组[i],
"勇士" => 勇士数组[i % 勇士总数],
];
// 将映射关系存到数组里面
array_push(映射关系数表,映射关系);
}
return 映射关系表;
结果:
映射关系表 = [
[
"苹果" => a1,
"勇士" => A,
],
[
"苹果" => b1,
"勇士" => B,
],
[
"苹果" => c1,
"勇士" => C,
],
[
"苹果" => d1,
"勇士" => A,
],
[
"苹果" => e1,
"勇士" => B,
],
]
然后遍历这个映射表,就可以给勇士发苹果了。虽然和期望的数组有出入,但是已经能够满足工作中的需求了。
不足之处:
- 细节1:如果再来2个编号为 f1, g1 的苹果,苹果数组为 [f1, g1],结果:A=[a1,d1,f1],B=[b1,e1,g1],C=[c1],结果就不均匀了。
- 细节2:如果 ABC 都是最多分配 4 个,A 已经分到 4 个了,再分配给他就超过限制了。
- 细节3:如果5个苹果有好坏之分,好苹果优先分配,则需要先对苹果进行排序。
- 细节4:并没有实现随机,按照的是 苹果的排列顺序来分的。
以下解答还只是处于方案程度,还未 coding,仅供参考:
- 细节 1 解答:可以通过将 ABC 的顺序倒置后,再分配。
- 细节 2 解答:就是加一层判断,满了后,就把这个勇士排除,被除数 -1,重新取余,苹果的编号 % 2。
- 细节 3 解答:就是将苹果按照好坏程度进行排序。
- 细节 4 解答:将苹果数组打乱排序。
另外又看了下 Redis 的有序集合 zset,发现也可以实现,不过不是取余的思路,用有序集合的评分来进行对勇士进行排序,分配一个苹果后,分数加一,然后再分配给评分最低的勇士。 因工作中的用到的 redis 镜像是 2.8 的,而 zset 的取最高分和最低分需要 5.0 以上,后面试着在本地用 Redis 抽象出解决这个问题的算法。