关于某彩票活动的总结
具体需求,每个用户进活动页面,领取一个号码,1000中的一个;
活动要求
1,随机性,一定要有随机性;
2,最少中奖概率,如果注数为3200注,则最多中4注
3,效率问题,(不能每个人来都产生一个随机数,这样效率不高);
4,支持断电(仍然从下一个开始),重启服务;(存数据库有点大材小用,因此不能存放在数据库)
解决方案
1,事先产生随机数1000个,并打乱数据(initHaoPool)
2,算法采用,计数,从1开始,领到1000个,又重新从1开始
3,不能存放数据库,
第一想法,那就存放在action里;action在struts2中不是安全的,有多个实例,否定
第二想法,放在service里,由于service是单例,可以保证线程安全;
(因此我以service的领号顺序为主,memcahe中的当备份使用,当主站重启时,memcahe还可以获取)
后来第二个方法也出问题了,3G站的领号不按顺序,为什么呢
原来我们的服务器采用双IP,2套代码服务,通过切换IP达到临时换包的效果;
假设线上服务器为A,由于3G站的HOST指到了B上,因此2套代码中的service都是独立的;
第三想法,放在memcache中,以memcache为主,service的为备份,这样就保证了代码的正确性;
但是后来又出问题了,早上10点13分,领号的数据又重复了,原因是当时同事切换了服务器,2台服务器代码都是不一致的,又导致了错误。
总结一下;在分布式环境下,要保持数据的一致性,放代码实在不可靠,
第一选择 是数据库
第二选择 是cache
最后才是 action,但这个保存不住,实在有问题;
下面是代码
/**
* 初始化号码池
*
* @return
*/
public void initHaoPool() {
//如果action中的结果集和缓存中的结果集都为空,则初始化;
if(hl==null&&CacheDataService.getCacheObject("<webactivityList>hl")==null){
hl = new ArrayList<String>();
//生成1000个号码
for (int i = 0; i < 1000; i++)
{
String randomNo="";
if (i < 10) {
randomNo= "00" + i;
}
else if (i < 100 && i >= 10) {
randomNo= "0" + i;
}else{
randomNo=Integer.valueOf(i).toString();
}
hl.add(randomNo);
}
//打乱顺序
Collections.shuffle(hl);
//初始lhkey为0;
lhkey=0;
CacheDataService.setCacheObject("<webactivityList>hl", hl, 60*60*24);
CacheDataService.setCacheObject("<webactivityInteger>lhkey", lhkey, 60*60*24);
}
}
/**
* 清除号码池和缓存
*
* @return
*/
public void clearPoolCache() {
hl=null;
lhkey=0;
//清除缓存;
CacheDataService.deleteCacheObject("<webactivityList>hl");
CacheDataService.deleteCacheObject("<webactivityInteger>lhkey");
}
/**
* 随机领取号码
*
* @return
*/
public synchronized String getMyNumber(){
String myno="";
// 如果丢失,从cache中取;
// if(hl==null){
// hl= (List)CacheDataService.getCacheObject("<webactivityList>hl");
// lhkey= (Integer)CacheDataService.getCacheObject("<webactivityInteger>lhkey");
// }
//如果丢失,从memcache中取;
if((List)CacheDataService.getCacheObject("<webactivityList>hl")!=null){
hl= (List)CacheDataService.getCacheObject("<webactivityList>hl");
lhkey= (Integer)CacheDataService.getCacheObject("<webactivityInteger>lhkey");
}
if(lhkey<1000){
myno=(String)hl.get(lhkey);
lhkey=lhkey+1;
}else{
//System.out.println("从0开始循环--------------");
myno=(String)hl.get(0);
lhkey=1;
}
//更新缓存信息
CacheDataService.setCacheObject("<webactivityList>hl", hl, 60*60*24);
CacheDataService.setCacheObject("<webactivityInteger>lhkey", lhkey, 60*60*24);
return myno;
}