2015年8月26日星期三

使用消息系统MQ规避分布式事务

随着业务的不断扩展,数据库数据爆炸性增长,将原有系统和数据库进行拆分不可避免。随之带来了分布式事务的问题,分布式事务是一种常见的,并且让开发者头疼的事情。常用的解决方案有XA协议和2PC协议。但是,这两种协议的性能差强人意,响应速度很慢,很难达到很多互联网场景的需求。因此,ebay的大神们提出了使用消息系统规避分布式事务的解决方案。这是一种基于BASE的最终一致性方案。

参考:
http://queue.acm.org/detail.cfm?id=1394128
http://www.cnblogs.com/LBSer/p/4715395.html

2015年8月23日星期日

Spring AOP

教程:http://www.tutorialspoint.com/spring/aop_with_spring.htm
http://examples.javacodegeeks.com/enterprise-java/spring/aop/spring-aop-example/
http://hyhai7.iteye.com/blog/837497
http://www.journaldev.com/2583/spring-aop-example-tutorial-aspect-advice-pointcut-joinpoint-annotations-xml-configuration

自定义注解:
http://www.cnblogs.com/shipengzhi/articles/2716004.html

Spring cache

官方doc:
http://spring.io/guides/gs/caching/
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html

Blog介绍:https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/

spring schedule

http://spring.io/guides/gs/scheduling-tasks/
官方doc:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

http://gong1208.iteye.com/blog/1773177

Spring整合JMS

JMS原理:http://docs.oracle.com/cd/E19148-01/820-0533/aeras/index.html
JMS和MQ原理:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt127


基于spring Boot和annotion的实例:http://spring.io/guides/gs/messaging-jms/

基于配置文件的JMS实例:
http://haohaoxuexi.iteye.com/blog/1893038
http://haohaoxuexi.iteye.com/blog/1893676-介绍了各种listener
http://haohaoxuexi.iteye.com/blog/1900937-介绍了messageConverter
http://haohaoxuexi.iteye.com/blog/1983532-介绍了事务支持

官方doc:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html

2015年8月18日星期二

Spring Batch


  Spring Batch是一个轻量级的,完全面向Spring的批处理框架,可以应用于企业级大量的数据处理系统。Spring Batch以POJO和大家熟知的Spring框架为基础,使开发者更容易的访问和利用企业级服务。Spring Batch可以提供大量的,可重复的数据处理功能,包括日志记录/跟踪,事务管理,作业处理统计工作重新启动、跳过,和资源管理等重要功能。

适用的业务方案:
1、批处理定期提交。
2、并行批处理:并行处理工作。
3、企业消息驱动处理
4、大规模的并行处理
5、手动或是有计划的重启
6、局部处理:跳过记录(如:回滚)
Spring Batch流程


每个Batch都会包含一个Job。Job就像一个容器,这个容器里装了若干Step,Batch中实际干活的也就是这些Step,至于Step干什么活,无外乎读取数据,处理数据,然后将这些数据存储起来(ItemReader用来读取数据,ItemProcessor用来处理数据,ItemWriter用来写数据) 。JobLauncher用来启动Job,JobRepository是上述处理提供的一种持久化机制,它为JobLauncher,Job,和Step实例提供CRUD操作。

外部控制器调用JobLauncher启动一个Job,Job调用自己的Step去实现对数据的操作,Step处理完成后,再将处理结果一步步返回给上一层,这就是Batch处理实现的一个简单流程。


参考:
http://www.ibm.com/developerworks/cn/java/j-lo-springbatch1/
http://www.ibm.com/developerworks/cn/java/j-lo-springbatch2/

2015年8月9日星期日

Spring Data Redis资料整理

Redis介绍
http://www.ibm.com/developerworks/cn/java/os-springredis/

Spring 整合 Redis:spring data redis基础使用
http://blog.csdn.net/java2000_wl/article/details/8543203/

使用Spring Data + Redis实现缓存:基于@cache实现
http://www.jdon.com/repository/redis.html
http://blog.joshuawhite.com/java/caching-with-spring-data-redis/

Spring Cache注解+Redis
http://hanqunfeng.iteye.com/blog/2176172

Spring Data Redis实现一个订阅/发布系统
http://www.open-open.com/lib/view/open1351324403395.html


使用Spring Data Redis操作Redis
涉及进行master切换,事务相关内容
http://aiilive.blog.51cto.com/1925756/1627455
两种方式实现pub/sub消息系统:注册bean和使用Redis命名空间的方式配置
http://aiilive.blog.51cto.com/1925756/1627478

Spring-data-redis:特性与实例
http://shift-alt-ctrl.iteye.com/blog/1886831

Redis连接池简单介绍
http://shift-alt-ctrl.iteye.com/blog/1885910


Spring-data-redis: 事务与pipeline
http://shift-alt-ctrl.iteye.com/blog/1887473
Spring-data-redis: pub/sub消息订阅-->redis的消息订阅不是持久化的
http://shift-alt-ctrl.iteye.com/blog/1887700
改进为持久化的消息队列:http://shift-alt-ctrl.iteye.com/blog/1867454


征服redis系列
http://snowolf.iteye.com/blog/1630697 安装和简单的使用
http://snowolf.iteye.com/blog/1633196 客户端进行shard
http://snowolf.iteye.com/blog/1666908

监控

用Kibana和logstash快速搭建实时日志查询、收集与分析系统http://storysky.blog.51cto.com/628458/1158707/

数据治理资料

http://housheng33.iteye.com/blog/1853966
http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0904loulj/
http://v.youku.com/v_show/id_XOTI1NDc4MjUy.html?from=y1.7-1.2

2015年8月8日星期六

MySQL-Proxy

MySQL-Proxy是处在你的MySQL数据库客户和服务端之间的程序,它可以监测、分析或改变它们的通信,它还支持嵌入性脚本语言Lua。这个代理可以用来分析、监控和变换(transform)通信数据,它支持非常广泛的使用场景:
  • 负载平衡和故障转移处理
  • 查询分析和日志
  • SQL宏(SQL macros)
  • 查询重写(query rewriting)
  • 执行shell命令
简单的说,MySQL Proxy就是一个连接池,负责将前台应用的连接请求转发给后台的数据库,并且通过使用lua脚本,可以实现复杂的连接控制和过滤,从而实现读写分离和负载平衡。对于应用来说,MySQL Proxy是完全透明的,应用则只需要连接到MySQL Proxy的监听端口即可。当然,这样proxy机器可能成为单点失效,但完全可以使用多个proxy机器做为冗余,在应用服务器的连接池配置中配置到多个proxy的连接参数即可。
MySQL Proxy更强大的一项功能是实现“读写分离(Read/Write Splitting)”。基本的原理是让主数据库处理事务性查询,而从数据库处理SELECT查询。数据库复制被用来把事务性查询导致的变更同步到集群中的从数据库。


读写分离:
http://imysql.cn/2008_04_23_quick_startup_with_mysql_proxy
http://blog.csdn.net/yueliangdao0608/article/details/2398655

Gossip协议

1.背景

Gossip算法又被称为反熵(Anti-Entropy),熵是物理学上的一个概念,代表杂乱无章,而反熵就是在杂乱无章中寻求一致,这充分说明了Gossip的特点:在一个有界网络中,每个节点都随机地与其他节点通信,经过一番杂乱无章的通信,最终所有节点的状态都会达成一致。每个节点可能知道所有其他节点,也可能仅知道几个邻居节点,只要这些节可以通过网络连通,最终他们的状态都是一致的,当然这也是疫情传播的特点。

要注意到的一点是,即使有的节点因宕机而重启,有新节点加入,但经过一段时间后,这些节点的状态也会与其他节点达成一致,也就是说,Gossip天然具有分布式容错的优点。

Gossip是一个带冗余的容错算法,更进一步,Gossip是一个最终一致性算法。虽然无法保证在某个时刻所有节点状态一致,但可以保证在”最终“所有节点一致,”最终“是一个现实中存在,但理论上无法证明的时间点。

因为Gossip不要求节点知道所有其他节点,因此又具有去中心化的特点,节点之间完全对等,不需要任何的中心节点。实际上Gossip可以用于众多能接受“最终一致性”的领域:失败检测、路由同步、Pub/Sub、动态负载均衡。例如,Cassandra集群没有中心节点,各个节点的地位完全相同,它们通过gossip协议维护集群的状态。通过gossip,每个节点都能知道集群中包含哪些节点,以及这些节点的状态,这使得Cassandra集群中的任何一个节点都可以完成任意key的路由,任意一个节点不可用都不会造成灾难性的后果。

但Gossip的缺点也很明显,冗余通信会对网路带宽、CPU资源造成很大的负载,而这些负载又受限于通信频率,该频率又影响着算法收敛的速度,后面我们会讲在各种场合下的优化方法。

2.基本概念
gossip分为两种. 本文只讨论anti-entropy
■anti-entropy 只要数据不同步,就开始同步数据
■rumor mongering 每隔固定的时间同步数据

Gossip中的每个节点维护一组状态,状态可以用一个key/value对表示,还附带一个版本号,版本号大的为更新的状态。信息达到同步的时间大概是log(N),这里N表示节点的数量。

为了保证一致性,规定数据的value及version只有宿主节点才能修改,其他节点只能间接通过Gossip协议来请求数据对应的宿主节点修改,即m (p)只能由有节点p来修改。

anti-entropy协议通过版本号大小来对数据进行更新。

两个节点(A、B)之间存在三种通信方式:
■push-gossip: A节点将数据推送给B节点,B节点更新A中比自己新的数据

■pull-gossip:A仅将摘要数据 (node,key,value,version)推送给B,B根据摘要数据来选择那些版本号比A高的数据推送给A,A更新本地。

■push-pull gossip:与pull类似,只是多了一步,A再将本地比B新的数据推送给B,B更新本地。

如果把两个节点数据同步一次定义为一个周期,则在一个周期内,push需通信1次,pull需2次,push/pull则需3次。从效果上来讲,push/pull最好,理论上一个周期内可以使两个节点完全一致。直观上也感觉,push/pull的收敛速度是最快的。

3.算法样例
Cassandra内部有一个Gossiper,每隔一秒运行一次(在Gossiper.java的start方法中),按照以下规则向其他节点发送同步消息:

1、随机取一个当前活着的节点,并向它发送同步请求

2、向随机一台不可达的机器发送同步请求

3、如果第一步中所选择的节点不是seed,或者当前活着的节点数少于seed数,则向随意一台seed发送同步请求

如果没有这个判断,考虑这样一种场景,有4台机器,{A, B, C, D},并且配置了它们都是seed,如果它们同时启动,可能会出现这样的情形:
1、A节点起来,发现没有活着的节点,走到第三步,和任意一个种子同步,假设选择了B
2、B节点和A完成同步,则认为A活着,它将和A同步,由于A是种子,B将不再和其他种子同步
3、C节点起来,发现没有活着的节点,同样走到第三步,和任意一个种子同步,假设这次选择了D
4、C节点和D完成同步,认为D活着,则它将和D同步,由于D也是种子,所以C也不再和其他种子同步

这时就形成了两个孤岛,A和B互相同步,C和D之间互相同步,但是{A,B}和{C,D}之间将不再互相同步,它们也就不知道对方的存在了。
加入第二个判断后,A和B同步完,发现只有一个节点活着,但是seed有4个,这时会再和任意一个seed通信,从而打破这个孤岛。

参考:
http://f.dataguru.cn/thread-163038-1-1.html
http://blog.163.com/liaoxiangui@126/blog/static/795696402012121112831272/

2015年8月5日星期三

Spring Data初见

Spring Data 作为SpringSource的其中一个父项目, 旨在统一和简化对各类型持久化存储, 而不拘泥于是关系型数据库还是NoSQL 数据存储。无论是哪种持久化存储, 数据访问对象(或称作为DAO,即Data Access Objects)通常都会提供对单一域对象的CRUD (创建、读取、更新、删除)操作、查询方法、排序和分页方法等。Spring Data则提供了基于这些层面的统一接口(CrudRepository,PagingAndSortingRepository)以及对持久化存储的实现。
Spring Data包括许多子项目: Spring Data 项目旨在为大家提供一种通用的编码模式。数据访问对象实现了对物理数据层的抽象, 为编写查询方法提供了方便。通过对象映射, 实现域对象和持续化存储之间的转换, 而模板提供的是对底层存储实体的访问实现。

Spring Data JPA:

Spring Data JPA 的发布包包含Spring Data Commons 和 Spring Data JPA 两个发布包,Commons 是 Spring Data 的公共基础包。
使用 Spring Data JPA 进行持久层开发大致需要的三个步骤:

1.声明持久层的接口,该接口继承 Repository,Repository 是一个标记型接口,它不包含任何方法,当然如果有需要,Spring Data 也提供了若干 Repository 子接口,其中定义了一些常用的增删改查,以及分页相关的方法。

2.在接口中声明需要的业务方法。Spring Data 将根据给定的策略来为其生成实现代码。

3.在 Spring 配置文件中增加一行声明,让 Spring 为声明的接口创建代理对象。配置了 <jpa:repositories> 后,Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录,为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring 自动封装的特性来直接使用该对象。

此外,<jpa:repository> 还提供了一些属性和子标签,便于做更细粒度的控制。可以在 <jpa:repository> 内部使用 <context:include-filter>、<context:exclude-filter> 来过滤掉一些不希望被扫描到的接口。

接口继承
持久层接口继承 Repository 并不是唯一选择。Repository 接口是 Spring Data 的一个核心接口,它不提供任何方法,开发者需要在自己定义的接口中声明需要的方法。与继承 Repository 等价的一种方式,就是在持久层接口上使用 @RepositoryDefinition 注解,并为其指定 domainClass 和 idClass 属性。

1.如果持久层接口较多,且每一个接口都需要声明相似的增删改查方法,直接继承 Repository 就显得有些啰嗦,这时可以继承 CrudRepository,它会自动为域对象创建增删改查方法,供业务层直接使用。开发者只是多写了 "Crud" 四个字母,即刻便为域对象提供了开箱即用的十个增删改查方法。

2.使用 CrudRepository 也有副作用,它可能暴露了你不希望暴露给业务层的方法。比如某些接口你只希望提供增加的操作而不希望提供删除的方法。针对这种情况,开发者只能退回到 Repository 接口,然后到 CrudRepository 中把希望保留的方法声明复制到自定义的接口中即可.

3.分页查询和排序是持久层常用的功能,Spring Data 为此提供了 PagingAndSortingRepository 接口,它继承自 CrudRepository 接口,在 CrudRepository 基础上新增了两个与分页有关的方法。但是,我们很少会将自定义的持久层接口直接继承自 PagingAndSortingRepository,而是在继承 Repository 或 CrudRepository 的基础上,在自己声明的方法参数列表最后增加一个 Pageable 或 Sort 类型的参数,用于指定分页或排序信息即可,这比直接使用 PagingAndSortingRepository 提供了更大的灵活性。

4.JpaRepository 是继承自 PagingAndSortingRepository 的针对 JPA 技术提供的接口,它在父接口的基础上,提供了其他一些方法,比如 flush(),saveAndFlush(),deleteInBatch() 等。如果有这样的需求,则可以继承该接口。

查询方式

1.通过解析方法名创建查询
框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。并且如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。

2.使用 @Query 创建查询
@Query 注解的使用非常简单,只需在声明的方法上面标注该注解,同时提供一个 JP QL 查询语句即可,如下所示:

3.通过调用 JPA 命名查询语句创建查询
命名查询是 JPA 提供的一种将查询语句从方法体中独立出来,以供多个方法共用的功能。Spring Data JPA 对命名查询也提供了很好的支持。用户只需要按照 JPA 规范在 orm.xml 文件或者在代码中使用 @NamedQuery(或 @NamedNativeQuery)定义好查询语句,唯一要做的就是为该语句命名时,需要满足”DomainClass.methodName()”的命名规则。假设定义了如下接口
Spring Data JPA 对事务的支持
默认情况下,Spring Data JPA 实现的方法都是使用事务的。针对查询类型的方法,其等价于 @Transactional(readOnly=true);增删改类型的方法,等价于 @Transactional。可以看出,除了将查询的方法设为只读事务外,其他事务属性均采用默认值。
如果用户觉得有必要,可以在接口方法上使用 @Transactional 显式指定事务属性,该值覆盖 Spring Data JPA 提供的默认值。同时,开发者也可以在业务层方法上使用 @Transactional 指定事务属性,这主要针对一个业务层方法多次调用持久层方法的情况。持久层的事务会根据设置的事务传播行为来决定是挂起业务层事务还是加入业务层的事务。具体 @Transactional 的使用可以参考Spring的参考文档。

2015年8月2日星期日

Java序列化框架FST

FST(fast-serialization)是一种快速高效的Java序列化框架,文档:https://github.com/RuedigerMoeller/fast-serialization/wiki.

概述:
  进行Java序列化,最重要的是序列化的格式,常用的有bson ,msgpack,protobuffer等。然而这些格式需要额外的配置文件或者注解等,需要对使用者的代码产生侵入,或者产生额外的工作。好的序列化框架应该只通过class定义信息一种渠道获取信息。FST使用Kson格式存储数据,KSON通过反射获取类定义的元数据信息,无需其他配置文件。
  具体而言,KSON是一种json的扩展格式,将object进行序列化存储。

In C++, one needs to sacrifice performance in order to get convenience, in Java one needs to sacrifice convenience in order to get performance

  FST通过反射获取类信息,反射的效率并不高,因此可以在启动的时候,对类信息进行注册,并缓存类的metaData信息,提高效率。
  另外,为了节约内存,减少GC停顿,FST提出了FST Structs的概念,允许将结构化的数据存储在连续的内存块中,减少内存碎片。连续的内存可以通过byte[] array或者使用native的方式在java的堆外进行申请(使用unsafe类型即可)。
  FST Structs的原因:

  • 内存更便宜了,但是随着堆内内存的加大,GC的停顿时间更长了;
  • Java中的结构化数据存储在堆内性能消耗很大,例如,A String member of a class with value "A" requires 60 to 80 bytes on the heap (depends on VM version and 32/64 bit), which means >90% memory overhead.Frequently your 60 GB on-heap data structures boil down to some 5GB stored in packed structs.
  • 利于进行跨进程调用。


FST将meta信息保存在序列化后的数据中的优点是decode时,不需要访问类信息。这一点在跨语言时,特别有用。然后存在的问题就是所有序列化后的类型中均包含元数据信息,及其冗余。 因此,根据不同的使用场景,FST并非完全cover。

FST的限制:
  • stick with pojos,个人认为只有对pojo进行序列化才是比较合理的。 
  • supported collections: Map's, List's 
  • Use strong typing in class definition
自己实现序列化工具时,需要注意的点:
  • 序列化基础类型时,注意大小端,否则linux和windows将会出现不兼容现象; 
  • 注意读取注解,避免序列化不需要的Field; 
  • 注意扩展使用off-Heap Map/Memory Map Files; 
  • 注意循环引用的处理。