冰冷的梦境


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

Failed to read artifact descriptor for XX,Could not find artifact XX

发表于 2018-04-09 | 分类于 项目问题

  maven聚合项目通过deploy打包自己的项目到远程库时,出现了” Failed to read artifact descriptor for XX,Could not find artifact XX “ 这样的信息,导致编译失败。

  但是在本地install的时候却是成功的。也就是说,项目在本地跑什么事没有,一旦发布自己的jar包就不行。

  根据错误信息提示,最后,将问题定位在一个依赖的外部jar包,发现只要把这个jar包的依赖注解掉,项目发布就没问题,但是加上就报错。


  解决办法:问题的原因是因为依赖的jar,其deploy方式有问题。

如果是一个单独的maven项目,其发布方式:

1
2
mvn -U clean install -Dmaven.test.skip=true
mvn -U clean deploy -Dmaven.test.skip=true

但如果是一个maven的聚合项目,只想发布部分module:

1
2
3
mvn -U clean install -Dmaven.test.skip=true
mvn -U clean deploy -Dmaven.test.skip=true -pl :xxx1 -am
mvn -U clean deploy -Dmaven.test.skip=true -pl :xxx2 -am

其中,xxx1、xxx2是module的名字,注意一定不要忽略-am这个参数,否则就会出现,我上面描述的问题。


  -am参数表示构建指定模块,同时构建指定模块依赖的其他模块。(全称also make)

电商-促销系统

发表于 2017-12-24 | 分类于 项目

系统结构

  促销系统是商城活动的核心模块,主要由:OA、服务、第三方服务和JOB组成。

  • OA:促销活动数据的源头,同时也对所有的促销活动进行管理。
  • 服务:商城内部的使用的rpc接口,提供各种促销信息查询、作用等功能。
  • 第三方服务:为我们商城之外的系统提供的第三方http接口。
  • JOB:促销系统为了提高响应速度,所有在线的促销活动,都以一种倒排的形式存到了内存中,job就是定时更新这些数据用的。

系统架构图

image
  该图画的比较简单,不过整体的架构与我们现在使用的系统,没什么差别。

对bio、nio、aio的理解

发表于 2017-12-14 | 分类于 笔记

阻塞/非阻塞 同步/异步

  同步与异步关注的是消息的通知机制。

  同步指的是在发出一个消息调用的时候,如果没有获得结果,该消息调用就不会返回,会一直等待,也就是处于一种阻塞状态。一旦该消息调用返回,就能立刻得到返回值。

  也就是说,调用者需要主动等待被调用者返回的结果。

  异步指的是,在消息调用发出后,这个调用就直接返回了,没有返回结果。也就是说,异步调用发出后,调用者不会立刻得到结果。被调用者通过状态、通知或者回调函数来通知调用者。

  阻塞与非阻塞关注的是程序在等待调用结果(消息、返回值)时的状态。

  阻塞调用是指在调用结果返回之前,当前的线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用正好相反,调用线程在没有得到结果之前,该调用也不会阻塞当前线程。

IO模型

阻塞式IO模型

image

非阻塞式IO模型

image

IO多路复用模型

image

异步IO模型

image

java中的NIO

BIO同步阻塞

  客户端在读取数据的时候会产生阻塞,直到有数据返回或者超时;服务器端也会一直阻塞到有客户端连接才会返回,每个客户端连接过来,服务器端后会启动一个线程去处理客户端的请求。

  BIO的优点就是简单。缺点是当客户端过多的时候,会创建大量的线程去处理客户端的请求,线程资源都很宝贵,线程数量快速膨胀后,会导致系统的性能急剧下降,最终会导致系统宕掉。使用线程池可以限制线程的数量,但如果有大量的并发请求,超过最大数量的线程就只能等待,知道线程池中有空闲的线程可以被复用。

NIO同步非阻塞

NIO提供了Buffer、Selector、Channel进行数据处理。selector是一个选择器,可以选择某一个channel去做某些事。一个线程可以对应一个selector,而一个selector可以轮询多个channel,每一个channel对应一个socket。与BIO相比,只用一个线程就可以轮询多个socket。NIO虽然是非阻塞的,但是在调用select()时,如果数据没有准备好,还是会产生阻塞。BIO是在读取数据的时候会产生阻塞,而NIO会在select的时候会产生阻塞。

AIO异步非阻塞

AIO的使用回调函数来完成异步操作,数据读取完成后,在被通知。

一张它们的对比图片

image


参考文献

  • https://www.zhihu.com/question/19732473
  • http://blog.51cto.com/yaocoder/1308899
  • http://blog.csdn.net/anxpp/article/details/51512200

优惠券被刷

发表于 2017-12-13 | 分类于 项目问题

背景

  双十二活动期间,为了活跃气氛、提高销量,我们在商城首页弄了一个老虎机,通过该老虎机可以进行抽奖,奖品就是优惠券。满1500减100、满2000减200,不过这些都是比较普通的优惠券,优惠力度并不大。让我们没想到的是,运营还放出了20张满0减1000的优惠券。在用老虎机进行抽奖的时候,会提示有什么样的优惠券。

  这一下让黄牛看到了商机,不知道他们从哪里找到了大量用户的账号和密码,对我们的抽奖接口疯狂的刷。活动刚上线的时候,系统运行良好。但是过了几个小时,客服那边接到了投诉电话,用户说抽到了优惠券,但是在自己的个人中心并没有找到。我们也尝试了下,发现这个问题是确实存在。

  我第一个反应就是优惠券系统出了问题,马上查线上日志,发现日志打印正常,但是用grep命令,搜我自己的账号时,发现在这一段时间内的日志没有任何记录。“请求没过来”,发奖系统出问题了。跳到发奖系统的线上服务器上,继续看日志,但也没有发现异常日志。但是却能grep到我刚才的抽奖信息,并且还是处理成功的。

  最后,查了下发奖系统的redis队列,发现里面堆积了上万条请求。“接口被刷了,完!!”。我们job的处理速度是每秒30个请求,分析了下黄牛刷接口的频率是每秒40个。这样的话,队列中会堆积越来越多的请求,所有才会出现用户投诉的问题。

解决办法

  既然你刷,那我就封你IP。找运维帮忙查看了下请求最频繁的IP,发现请求大部分来自阿里云。哎,肯定是写好了代码,放在阿里云上跑,也是够下本的。运维把IP封了后,队列中的请求请求数量慢慢降了下来。系统又正常运行了。

  以为问题解决了,谁知道第二天,队列中的请求又开始堆积了。黄牛换了不同的IP,又开始继续刷券。这次我们分析了下我们job的处理速度和他们刷券的频率,让运营的人限制用户每天能抽中奖的次数。问题解决。

  又过了一天,我们分析了这几次刷券用户的id,发现这些用户id刷券的顺序和时间段几乎一致。那这就好办了,我们把凌晨1点到6点的请求进行分析,然后清空这个队列,让黄牛白刷。

问题的原因

  出现的问题的原因,我们商场早期用户注册是不需要手机号验证的,这也就导致了那时候,有黄牛批量注册用户,导致了今天这样的问题的出现。

通过fastjson将Long类型转换成String类型

发表于 2017-11-28 | 分类于 项目问题

  后端把Long类型的数据传给前端,前端可能会出现精度丢失的情况。例如:201511200001725439这样一个Long类型的整数,传给前端后会变成201511200001725440。

解决方法:

  • 在后台将这个Long类型的字段转换成String类型的,风险比较大。
  • 使用fastjson的提供的注解,@JSONField(serializeUsing= ToStringSerializer.class)。

备注:
  

  • fastjson在com.alibaba.fastjson.serializer包下面提供了多种数据类型转换的注解。
  • 自己也可以拓展这些注解,通过实现ObjectSerializer接口来完成。

ToStringSerializer的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ToStringSerializer implements ObjectSerializer {

public static final ToStringSerializer instance = new ToStringSerializer();

@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
int features) throws IOException {
SerializeWriter out = serializer.out;

if (object == null) {
out.writeNull();
return;
}

String strVal = object.toString();
out.writeString(strVal);
}

}

RocketMQ

发表于 2017-10-21 | 分类于 RocketMQ

RocketMQ

Producer

  消息生产者,负责产生消息,一般由业务系统负责产生消息。

Producer Group

  生产者组,一类Producer的集合名称,这类Producer通常发送一类消息,且发送逻辑一致。

Consumer

  消息消费者,消费MQ上的消息的应用程序就是消费者,根据业务的需要对消息进行不同的处理,一般是后台系统负责异步消费。

Push Consumer

  Consumer的一种,应用通常向consumer对象注册一个listener接口,一旦收到消息,consumer对象立刻回调listener接口方法。

Pull Consumber

  Consumer的一种,应用通常主动调用consumer的拉消息方法从broker拉消息,主动权由应用控制。

Consumer Group

  消费者组,和生产者组类似,消费同一类消息的多个consumer示例组成的一个消费者组,消费逻辑一致。

Topic

  Topic是一种消息的逻辑分类,比如在电商中订单、商品、活动等产生的消息,都需要进行分类。订单的消息放到订单的topic,活动的消息放到活动的topic。

Message

  Message是消息的载体。一个message必须指定topic,相当于寄信的地址。Message还可以设置一个可选的tag设置,以便消费端可以基于tag进行消息过滤。

Tag

  Tag可以被认为是topic的进一步细化。一般在相同的业务模块中通过引入标签来标记不同用途的消息。

Broker

  Broker是RocketMQ系统的主要角色,broker接收来自生产者的消息,储存以及为消费者拉取消息的请求做好准备。一般也称为server,在JMS规范中称为Provider。

Name Server

  Name Server为producer和consumer提供路由信息。作用和zookeeper一样,轻量级的。

广播消费

  一条消息被多个consumer消费,即使这些consumer属于同一个consumer group,消息也会被consumer group中的每个consumer都消费一次,广播消费中的consumer group概念可以认为在消息划分方面无意义。
  在CORBA Notification规范中,消费方式都属于广播消费。在JMS规范中,相当于JMS publish/subscribe model。

集群消费

  一个consumer group中的consumer实例平均分摊消费信息。例如某个topic有9条消息,其中一个consumer group有3个实例(可能是三个进程,也可能是三台机器),那么每个实例消费其中的3条消息。

顺序消息

  消费消息的顺序要同发送消息的顺序一致,在rocketmq中,主要指的是局部顺序,即一类消息为满足顺序性,必须producer单线程顺序发送,且发送到同一个队列,这样consumer就可以按照producer发送的顺序去消费消息。

普通顺序消息

  顺序消息的一种,正常情况下可以保证完全的顺序消息,但是一旦发生通信异常,broker重启,由于队列总数发生变化,哈希取模后定位的队列会发生变化,产生短暂的消息顺序不一致。如果业务能容忍在集群异常情况下(如某个broker宕机或者重启)下,消息短暂的乱序,使用普通顺序方式比较合适。

严格顺序消息

  顺序消息的一种,无论正常异常情况下都能保证顺序,但是牺牲了分布式failover特性,即broker集群中只要有一台机器不可用,则整个集群都不可用,服务可用性大大降低。如果服务器部署为同步双写模式,此缺陷可通过备机自主切换为主避免,不过仍然会存在几分钟的服务不可用。

  目前已知的应用只有数据库binlog同步强依赖严格顺序消息,其他应用大部分都可以容忍短暂乱序,推荐使用普通的顺序消息。

message queue

  在rocketmq中,所有消息队列都是持久化,长度无限的数据结构,所谓长度无限是指队列中的每个存储单元都是定长,访问其中的存储单元使用offset来访问,offset为java long类型,64位,理论上在100年内不会溢出,所以认为是长度无限的,另外队列中只保存最近几天的数据,之前的数据会按照过期时间来删除。

  也可以认为message queue是一个长度无限的数组,offset就是下标。

RocketMQ特点

  • 是一个队列模型的消息中间件,具有高性能、高可靠性、高实时、分布式特点。
  • Producer、Consumer、队列都可以是分布式。
  • Producer向一些队列轮流发送消息,队列集合称为Topic。Consumer如果做广播消费,则一个consumer示例消费这个Topic对应的所有队列;如果做集群消费,则多个Consumer实例平均消费这个topic对应的队列集合。
  • 能够保证严格的消息顺序。
  • 提供丰富的消息拉取模式。
  • 高效的订阅者水平拓展能力。
  • 实时的消息订阅机制。
  • 亿级消息堆积能力。
  • 较少的依赖。

RocketMQ物理部署结构

image

  • Name Server是一个几乎无状态节点,可集群部署,节点间无任何信息同步。
  • Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与Name Server集群中的所有节点建立长连接,定时注册Topic信息到所有的Name Server。
  • Producer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name Server取Topic路由信息,并向提供Topic服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。
  • Consumer与Name Server集群中的一个节点(随机选择)建立长连接,定期从Name Server取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅规则由Broker配置决定。

RocketMQ逻辑部署结构

image

Producer Group

  用来表示一个发送消息的应用,一个Producer Group下包含多个Producer实例,可以使多台机器,也可以是一台机器的多个进程,或者一个进程的多个Producer对象。一个Producer Group可以发送多个Topic消息,Producer Group的作用如下:

  • 标识一类Producer。
  • 可以通过运维工具查询这个发送消息应用下有多个Producer实例。
  • 发送分布式事务消息时,如果Producer中途意外宕机,Broker会主动回调Producer Group内任意一台机器来确认事务状态。

Consumer Group

  用来表示一个消费消息应用,一个Consumer Group下包含多个consumer实例,可以是多台机器,也可以是多个进程,或者是一个进程下的多个consumer对象。一个Consumer Group下的多个consumer以均摊方式消费消息,如果设置为广播方式,那么这个Consumer Group下的每个实例都消费全量数据。

RocketMQ数据存储结构

image

  RocketMQ采取一种数据与索引分离的存储方法。有效降低文件资源、IO资源,内存资源的损耗。对于海量数据、高并发场景也能有效降低端到端延迟,并具备较强的横向拓展能力。

RocketMQ分布式消息系统

消息顺序

  例如订单创建、订单付款、订单完成,需要保证消费的顺序才有意义。所以可以将这几条消息发送到同一个topic队列中,并让同一个消费者来消费,这样就能保证消息的顺序消费。

producer:

1
2
3
4
5
6
7
8
9
SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
Integer id = (Integer) arg;
int index = id % mqs.size();
return mqs.get(index);
}
}, orderId
);

consumer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
consumer.registerMessageListener(new MessageListenerOrderly() {

AtomicLong consumeTimes = new AtomicLong(0);
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeOrderlyContext context) {
context.setAutoCommit(false);
System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
this.consumeTimes.incrementAndGet();
if ((this.consumeTimes.get() % 2) == 0) {
return ConsumeOrderlyStatus.SUCCESS;
} else if ((this.consumeTimes.get() % 3) == 0) {
return ConsumeOrderlyStatus.ROLLBACK;
} else if ((this.consumeTimes.get() % 4) == 0) {
return ConsumeOrderlyStatus.COMMIT;
} else if ((this.consumeTimes.get() % 5) == 0) {
context.setSuspendCurrentQueueTimeMillis(3000);
return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
}
return ConsumeOrderlyStatus.SUCCESS;

}
});

消息重复

  • 消费端处理消息的业务逻辑保持幂等性
  • 保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现

  RocketMQ不保证消息不重复,如果业务需要保证严格的不重复消息,需要自己在业务端去重。


参考

  • http://jm.taobao.org/2017/01/12/rocketmq-quick-start-in-10-minutes/
  • https://www.jianshu.com/p/824066d70da8
  • https://www.jianshu.com/p/453c6e7ff81c
  • http://rocketmq.apache.org/docs/order-example/

电商-购物车

发表于 2017-10-18 | 分类于 项目

系统结构

  购物车是电商中的核心,最近由于缺人,参与了点购物车系统的开发,架构图是一个技术经理画的,通过这个图快速熟悉购物车系统。

  • CartDataSync:购物车数据同步模块,购物车需要能支持高并发,并且快速响应用户请求(商品数量变化,商品增减等)。所以,我们使用cordis集群来存储用户的购物车数据,这个模块主要是为了定时将缓存的数据同步到DB,为以后分析用户的喜好做准备。
  • shoppingcart:购物车系统的核心,查看购物车以及对购物车的各种操作,都在该模块中。支持PC、M站、移动端等。
  • shoppingcart_api:回退库存的接口,该模块没有在架构图中画出来,是针对抢购秒杀而开发的接口。

系统架构图

image

电商-发奖系统

发表于 2017-09-02 | 分类于 项目

系统结构

  同事离职,接手了发奖系统,根据同事给的架构图(PS掉了一些模块),对发奖系统进行了梳理。

  • lottery:服务接口,商城页面的那些抽奖、发奖活动,都是对该接口的二次封装。lottery_n与lottery作用一样,只不过lottery_n多了签名验证。
  • lottery_task:发奖系统的job,在页面的领奖信息会被保存到一个redis队列中,然后通过该job进行定时处理。
  • lottery_service:发奖系统的OA

系统架构图

image
  该系统与优惠券系统息息相关,因为这里的奖,大部分指的都是各种各样的优惠券。
  发奖系统算是一个前台程序,而优惠券算是一个中台程序。

电商-优惠券系统

发表于 2017-07-08 | 分类于 项目

系统结构

  最近接手了优惠券系统,对该系统进行下简要的描述,整个系统可以分成三部分:OA,服务和JOB。

  • OA:优惠券制作、查询、统计等,所有的优惠券数据都来自这里。
  • 服务:提供rpc或者http接口给第三方的系统服务。
  • job:整个优惠券系统为了便于解耦,使用了大量的队列,job就是一个定时任务,定时从队列里面取数据,然后处理。

系统架构图

image
  由于是公司的项目,所以没有将系统的详细架构完整的画出来,但主要的模块都已经描绘了出来。

设计模式-解释器模式

发表于 2017-06-25 | 分类于 设计模式

解释器模式

  解释器模式实现了一个表达式接口,该接口解释一个特定的上下文。该模式可以被用在SQL解析、符号处理引擎等。属于行为模式。

优点

  • 可扩展性比较好、灵活。
  • 增加了新的解释器表达式的方式。
  • 易于实现简单文法。

缺点

  • 可利用的场景比较少。
  • 对于复杂的文法比较难维护。
  • 解释器模式会引起类膨胀。
  • 解释器模式采用递归调用方法。

适用场景

  • 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  • 一些重复出现的问题可以用一种简单的语言来进行表达。
  • 一个简单语法需要解释的场景。

类图

image


参考

  • http://www.runoob.com/design-pattern/interpreter-pattern.html
123
dreamlate

dreamlate

for the dream

23 日志
6 分类
39 标签
© 2018 dreamlate
由 Hexo 强力驱动
主题 - NexT.Pisces