关于秒杀系统的疑问和个人简单想法?

funnyone 2016-03-03 10:32:34
昨天去面试,问到这个问题。(如何实现秒杀系统)
我是说用直接用AtomicLong,但是对方说不对,我的实现如下:


//单机秒杀实现
AtomicBoolean hadDone = new AtomicBoolean(false);
AtomicLong total = new AtomicLong(100L);
public boolean miaoSha(){
if (!hadDone.get()) {
//是否已经减 到0
if(total.decrementAndGet() > 0){
//秒杀成功
return true;
}else {
hadDone.set(true);
}
}
//秒杀失败
return false;
}

按照这种想法,集群也可以用redis替换AtomicLong 。

现在网上找找,什么队列排队,问题是看不出来有什么必要排队?和这样有什么问题吗?
...全文
1301 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
无情波仔 2016-04-25
  • 打赏
  • 举报
回复
根据我做了几年秒杀系统的经验,简单的说下我的思路,秒杀系统要解决的是两个问题,一个是库存,一个是客户端访问量。 在高并发的情况下,我们不能超库存,并且系统可用性不能受到影响,解决思路如下: 后端:后台引入kafka(或者rabbitMa)系统,相关抢购数据系统启动时入redis缓存,根据抢购的请求数设置集群的机器数,一台tomcat大概2000个并发请求。如果预估10万并发,则设置50个tomcat集群。 前端:抢购页面静态化,采用nginx或者apache。 具体思路:前台抢购请求入kafka队列,服务端返回唯一序列号给客户端。注意这里是异步的。返回序列号给客户端和请求入队同时发生。然后客户端根据唯一序列号轮询抢购结果,同时server端消费者开始根据请求参数生成订单,并把生成订单的结果放入到redis中。 这里只是简单的说说,真正实现还有很。。。。。
乔不思 2016-04-20
  • 打赏
  • 举报
回复
感觉做秒杀系统有几方面得考虑: 但是几方面都可以归结于:五楼说的 库存一致性问题,保证商品不会错买给别人,不会多买,不会少买 当然redis能解决,但是它只解决了冰山一脚的问题。 秒杀大致可以分为: 请求---匹配商品---商品绑定请求 1.请求考虑放在队列中,“放”是一个操作,“取”是一个操作,放考虑线程安全,“取”也得考虑线程安全。(暂不考虑队列大小) 2.假定商品量一定可以考虑放在缓存中(暂不考虑商品多少),当然商品也可以考虑队列(具体情况定),在第一步的“取”的基础上做商品匹配,当然也是多机多线程,考虑线程安全。 3.在第二部的基础上,做商品增减操作,绑定请求。多级多线程,考虑线程安全 单凭楼主几行代码,感觉貌似没回答到重点。 当然请求可以不用队列...视具体情况定 片面理解,望大牛指点
乔不思 2016-04-20
  • 打赏
  • 举报
回复
引用 6 楼 qq467339640 的回复:
[quote=引用 2 楼 funnyone 的回复:] [quote=引用 1 楼 sinat_27650399 的回复:] 你这是单机的实现,而事实情况是,秒杀系统大都是分布式的,total大都是存在缓存中 不可能放在进程中
这个不是问题的重点,这个很容易转化为分布式的。例如用redis:
//SET miaoSha 100
AtomicBoolean hadDone = new AtomicBoolean(false);
Jedis jedis = new Jedis("127.0.0.1"); 
public boolean miaoSha(){
	if (!hadDone.get()) {
		if(jedis.decr("miaoSha") > 0){
			//秒杀成功
			return true;
		}else {
			hadDone.set(true);
		}
	}
	//秒杀失败
	return false;
}
[/quote] 这样也不行,redis有单点问题,redis挂掉咋办,秒杀里面很多组件都是用的集群[/quote] redis可以搞成集群。
大雨将至 2016-03-31
  • 打赏
  • 举报
回复
这题问的很没水平,涉及的方方面面太多,比如有人会考虑页面静态缓存方面,有人会像你一样考虑处理高并发下库存量的判断,有人考虑订单存储问题。还有复杂的情况,比如手机有16g,32g,黑色白色等,你用一个long型如何处理 你应该询问细节,看考官想了解哪方面的东西 我猜他只是想让你说出使用redis
浪里花 2016-03-24
  • 打赏
  • 举报
回复
引用 2 楼 funnyone 的回复:
[quote=引用 1 楼 sinat_27650399 的回复:] 你这是单机的实现,而事实情况是,秒杀系统大都是分布式的,total大都是存在缓存中 不可能放在进程中
这个不是问题的重点,这个很容易转化为分布式的。例如用redis:
//SET miaoSha 100
AtomicBoolean hadDone = new AtomicBoolean(false);
Jedis jedis = new Jedis("127.0.0.1"); 
public boolean miaoSha(){
	if (!hadDone.get()) {
		if(jedis.decr("miaoSha") > 0){
			//秒杀成功
			return true;
		}else {
			hadDone.set(true);
		}
	}
	//秒杀失败
	return false;
}
[/quote] 这样也不行,redis有单点问题,redis挂掉咋办,秒杀里面很多组件都是用的集群
  • 打赏
  • 举报
回复
hadDone的get 然后set 这两个操作是非线程安全的
引用 2 楼 funnyone 的回复:
[quote=引用 1 楼 sinat_27650399 的回复:] 你这是单机的实现,而事实情况是,秒杀系统大都是分布式的,total大都是存在缓存中 不可能放在进程中
这个不是问题的重点,这个很容易转化为分布式的。例如用redis:
//SET miaoSha 100
AtomicBoolean hadDone = new AtomicBoolean(false);
Jedis jedis = new Jedis("127.0.0.1"); 
public boolean miaoSha(){
	if (!hadDone.get()) {
		if(jedis.decr("miaoSha") > 0){
			//秒杀成功
			return true;
		}else {
			hadDone.set(true);
		}
	}
	//秒杀失败
	return false;
}
[/quote]
funnyone 2016-03-07
  • 打赏
  • 举报
回复
引用 1 楼 sinat_27650399 的回复:
你这是单机的实现,而事实情况是,秒杀系统大都是分布式的,total大都是存在缓存中 不可能放在进程中
这个不是问题的重点,这个很容易转化为分布式的。例如用redis:
//SET miaoSha 100
AtomicBoolean hadDone = new AtomicBoolean(false);
Jedis jedis = new Jedis("127.0.0.1"); 
public boolean miaoSha(){
	if (!hadDone.get()) {
		if(jedis.decr("miaoSha") > 0){
			//秒杀成功
			return true;
		}else {
			hadDone.set(true);
		}
	}
	//秒杀失败
	return false;
}
  • 打赏
  • 举报
回复
秒杀系统涉及面比较广,单就你这几行代码并不能说明问题,而且库存这种一致性要求极高的数据也不会放在缓存中去校验
引用 4 楼 funnyone 的回复:
[quote=引用 3 楼 sinat_27650399 的回复:] hadDone的get 然后set 这两个操作是非线程安全的 [quote=引用 2 楼 funnyone 的回复:] [quote=引用 1 楼 sinat_27650399 的回复:] 你这是单机的实现,而事实情况是,秒杀系统大都是分布式的,total大都是存在缓存中 不可能放在进程中
这个不是问题的重点,这个很容易转化为分布式的。例如用redis:
//SET miaoSha 100
AtomicBoolean hadDone = new AtomicBoolean(false);
Jedis jedis = new Jedis("127.0.0.1"); 
public boolean miaoSha(){
	if (!hadDone.get()) {
		if(jedis.decr("miaoSha") > 0){
			//秒杀成功
			return true;
		}else {
			hadDone.set(true);
		}
	}
	//秒杀失败
	return false;
}
[/quote][/quote] 那里不需要线程安全,只是一个简单的缓存位,这一步是jedis.decr("miaoSha")线程安全的就可以了。[/quote]
funnyone 2016-03-07
  • 打赏
  • 举报
回复
引用 3 楼 sinat_27650399 的回复:
hadDone的get 然后set 这两个操作是非线程安全的 [quote=引用 2 楼 funnyone 的回复:] [quote=引用 1 楼 sinat_27650399 的回复:] 你这是单机的实现,而事实情况是,秒杀系统大都是分布式的,total大都是存在缓存中 不可能放在进程中
这个不是问题的重点,这个很容易转化为分布式的。例如用redis:
//SET miaoSha 100
AtomicBoolean hadDone = new AtomicBoolean(false);
Jedis jedis = new Jedis("127.0.0.1"); 
public boolean miaoSha(){
	if (!hadDone.get()) {
		if(jedis.decr("miaoSha") > 0){
			//秒杀成功
			return true;
		}else {
			hadDone.set(true);
		}
	}
	//秒杀失败
	return false;
}
[/quote][/quote] 那里不需要线程安全,只是一个简单的缓存位,这一步是jedis.decr("miaoSha")线程安全的就可以了。
  • 打赏
  • 举报
回复
你这是单机的实现,而事实情况是,秒杀系统大都是分布式的,total大都是存在缓存中 不可能放在进程中

25,984

社区成员

发帖
与我相关
我的任务
社区描述
高性能WEB开发
社区管理员
  • 高性能WEB开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧