分类 Java 下的文章

什么是分布式系统中的幂等性

现如今我们的系统大多拆分为分布式SOA,或者微服务,一套系统中包含了多个子系统服务,而一个子系统服务往往会去调用另一个服务,而服务调用服务无非就是使用RPC通信或者restful,既然是通信,那么就有可能再服务器处理完毕后返回结果的时候挂掉,这个时候用户端发现很久没有反应,那么就会多次点击按钮,这样请求有多次,那么处理数据的结果是否要统一呢?那是肯定的!尤其再支付场景。
幂等性:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品使用约支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...
在以前的单应用系统中,我们只需要把数据操作放入事务中即可,发生错误立即回滚,但是再响应客户端的时候也有可能出现网络中断或者异常等等。
在增删改查4个操作中,尤为注意就是增加或者修改,
查询对于结果是不会有改变的,
删除只会进行一次,用户多次点击产生的结果一样
修改在大多场景下结果一样
增加在重复提交的场景下会出现
那么如何设计接口才能做到幂等呢?
方法一、单次支付请求,也就是直接支付了,不需要额外的数据库操作了,这个时候发起异步请求创建一个唯一的ticketId,就是门票,这张门票只能使用一次就作废,具体步骤如下:
异步请求获取门票
调用支付,传入门票
根据门票ID查询此次操作是否存在,如果存在则表示该操作已经执行过,直接返回结果;如果不存在,支付扣款,保存结果
返回结果到客户端
如果步骤4通信失败,用户再次发起请求,那么最终结果还是一样的
方法二、分布式环境下各个服务相互调用
这边就要举例我们的系统了,我们支付的时候先要扣款,然后更新订单,这个地方就涉及到了订单服务以及支付服务了。
用户调用支付,扣款成功后,更新对应订单状态,然后再保存流水。
而在这个地方就没必要使用门票ticketId了,因为会比较闲的麻烦
(支付状态:未支付,已支付)
步骤:
1、查询订单支付状态
2、如果已经支付,直接返回结果
3、如果未支付,则支付扣款并且保存流水
4、返回支付结果
如果步骤4通信失败,用户再次发起请求,那么最终结果还是一样的
对于做过支付的朋友,幂等,也可以称之为冲正,保证客户端与服务端的交易一致性,避免多次扣款。

TCC和两阶段分布式事务处理的区别

经常在网络上看见有人介绍TCC时,都提一句,”TCC是两阶段提交的一种”。其理由是TCC将业务逻辑分成try、confirm/cancel在两个不同的阶段中执行。其实这个说法,是不正确的。可能是因为既不太了解两阶段提交机制、也不太了解TCC机制的缘故,于是将两阶段提交机制的prepare、commit两个事务提交阶段和TCC机制的try、confirm/cancel两个业务执行阶段互相混淆,才有了这种说法。
两阶段提交(Two Phase Commit,下文简称2PC),简单的说,是将事务的提交操作分成了prepare、commit两个阶段。其事务处理方式为:
1、 在全局事务决定提交时,a)逐个向RM发送prepare请求;b)若所有RM都返回OK,则逐个发送commit请求最终提交事务;否则,逐个发送rollback请求来回滚事务;
2、 在全局事务决定回滚时,直接逐个发送rollback请求即可,不必分阶段。
* 需要注意的是:2PC机制需要RM提供底层支持(一般是兼容XA),而TCC机制则不需要。
TCC(Try-Confirm-Cancel),则是将业务逻辑分成try、confirm/cancel两个阶段执行,具体介绍见TCC事务机制简介。其事务处理方式为:
1、 在全局事务决定提交时,调用与try业务逻辑相对应的confirm业务逻辑;
2、 在全局事务决定回滚时,调用与try业务逻辑相对应的cancel业务逻辑。
可见,TCC在事务处理方式上,是很简单的:要么调用confirm业务逻辑,要么调用cancel逻辑。这里为什么没有提到try业务逻辑呢?因为try逻辑与全局事务处理无关。
当讨论2PC时,我们只专注于事务处理阶段,因而只讨论prepare和commit,所以,可能很多人都忘了,使用2PC事务管理机制时也是有业务逻辑阶段的。正是因为业务逻辑的执行,发起了全局事务,这才有其后的事务处理阶段。实际上,使用2PC机制时————以提交为例————一个完整的事务生命周期是:begin -> 业务逻辑 -> prepare -> commit。
再看TCC,也不外乎如此。我们要发起全局事务,同样也必须通过执行一段业务逻辑来实现。该业务逻辑一来通过执行触发TCC全局事务的创建;二来也需要执行部分数据写操作;此外,还要通过执行来向TCC全局事务注册自己,以便后续TCC全局事务commit/rollback时回调其相应的confirm/cancel业务逻辑。所以,使用TCC机制时————以提交为例————一个完整的事务生命周期是:begin -> 业务逻辑(try业务) -> commit(comfirm业务)。
综上,我们可以从执行的阶段上将二者一一对应起来:
1、 2PC机制的业务阶段 等价于 TCC机制的try业务阶段;
2、 2PC机制的提交阶段(prepare & commit) 等价于 TCC机制的提交阶段(confirm);
3、 2PC机制的回滚阶段(rollback) 等价于 TCC机制的回滚阶段(cancel)。

acid

ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库,必须要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。
原子性
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性
一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。
隔离性
隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。
持久性
在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

数据空洞

数据空洞的产生原理都是相通的,类似的。
文件空洞的概念:
在UNIX文件操作中,文件位移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被设为 0。
如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大(extend)”。这就是所谓的在文件里创造“空洞(hole)”。没有被实际写入文件的所有字节由重复的 0 表示。空洞是否占用硬盘空间是由文件系统(file system)决定的。
文件空洞的特点:
用ls查看的文件大小是将空洞算在内的。
cp命令拷贝的文件,空洞部分不拷贝,所以生成的同样文件占用磁盘空间小。
用read读取空洞部分读出的数据是0,所以如果用read和write拷贝一个有空洞的文件,那么最终得到的文件没有了空洞,空洞部分都被0给填充了,文件占用的磁盘空间就大了。不过文件大小不变。
空洞文件作用很大,例如迅雷下载文件,在未下载完成时就已经占据了全部文件大小的空间,这时候就是空洞文件。下载时如果没有空洞文件,多线程下载时文件就都只能从一个地方写入,这就不是多线程了。如果有了空洞文件,可以从不同的地址写入,就完成了多线程的优势任务。
hbase空洞:
在我们的大规模的应用测试中,发现了个别异常的Region。
首先,介绍发现这个问题的来由。在线上读写请求出现个别操作失败,并且失败的请求指向同一个Region A,因此,检查该Region A的位置,指向了host1,然而进入host1的onlineRegion列表中,却没有发现该Region,因此,此时出现Region不匹配的问题。更名为Region空洞。
在互联网应用中,有一个共性是,找问题比解决问题要难。只要定位到了问题,根据上面对于AM、RS、HMaster之间Region迁移的理解,很容易发现是Region迁移过程中出现了一次事故,造成了空洞现象。
我的解决方法就是增加一个定时触发的监控程序,去检查.META.表中记录的Region位置(RS)是否与RS对应上,如果RS上onlineRegion,不存在该Region,则就报警,并尝试进行unassign操作。
将该程序放入crontab中,定时检查监控,并有Region重新部署功能。
http://blog.sina.com.cn/s/blog_4a1f59bf0101b1hv.html
MongoDB空洞:
很多时候,我们项目上线时间比较久了,我们积累了一些无用的数据,而由于MongoDB顺序写的原因,在我们删除部分无用数据后,它的storageSize和fileSize并不会变小,这就造成了大量的数据空洞。
这些数据空洞除了占用磁盘之外,也会加载到内存中,这会降低内存效率。
所以这个时候,我们一般要对这些数据空洞进行处理,一般有下面几种处理方式。 一种是使用MongoDB自带的compact命令:
db.collectionName.runCommand(“compact”)
这种方式是collection级别的压缩,只能去除collection内的碎片,但是MongoDB的数据分配是DB级别的,效果并不一定多好,其次呢,这个压缩是线上压缩,肯定会影响服务的,磁盘IO会比较高,这么干容易出事。
还有一种方式,也就是我们下面要详细说明的方式,过程大概类似于下面:
先预热从库
提升从库为主库,原主库降为从库
移除原主库的DB数据,直接remove掉
重新同步
完成后,预热,然后将此库提升为主库,原从库依然降为从库
这样做的好处是:
DB级别,不会有碎片,毕竟是新写的,收缩效率高
基本不会影响线上服务(当然,你不能只有一个从,你也不能挑服务高负荷的时候来干这个事情)
Mysql空洞:
现发现对一个几亿条记录的表进行删除记录及进行optimize操作时,会极其的耗时间和空间。
删除记录时,MyISAM表会留下空洞碎片,碎片多了会持续降低MySQL性能。如果使用optimize操作的话,MySQL会先生成一个TMD文件;完成操作后才会把这个文件删除。这个过程相当漫长……
所以再设计表和存储记录时,就应当想好这个表的记录会不会有大量记录;如果是的话应该要先设计好应对方案,水平切分或垂直切分。

bootstrap table 导出数据格式,前端日期排序

先看插件说明,再看options的设置即可.
排序主要看:

sorter:numberSort

导出文件格式化主要看:

showExport:true,
            exportOptions:{
            	fileName:"例子后端常规监控",
            	worksheetName:"例子后端常规监控",
            	onCellData:function(cell, row, col, data){
            		if(row == 0){
            			return data;
            		}else{
            			return data.replace(/\([^\)]*\)/g,"");
            		}
                }
            },

https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/export
https://github.com/hhurz/tableExport.jquery.plugin#options

//数据排序算法
function numberSort(a,b){
    	a = a.replace(/\([^\)]*\)/g,"");//正则 去掉小括号及里边的内容
    	b = b.replace(/\([^\)]*\)/g,"");
    	var numa = parseFloat(a);
    	var numb = parseFloat(b);
    	return a - b;
}
//日期排序算法
sorter:function(a, b){
              var d1 = new Date(a.replace(/\-/g, "\/"));
              var d2 = new Date(b.replace(/\-/g, "\/"));
              if(a != "" && b != ""){
              	    return d1 - d2;
               }
}
//bootstrap table初始化函数
        $('#table').bootstrapTable({
            showToggle:false,
            showPaginationSwitch:true,  //
            showColumns:true,        //可选列按钮
            iconsPrefix:"glyphicon",   //图标样式
            iconSize:"sm",           //图标大小
            striped:true,
            classes:"table table-striped table-bordered table-hover",
            pagination:true,        //底部分页
            sidePagination:"client",
            showExport:true,
            exportOptions:{
            	fileName:"例子后端常规监控",
            	worksheetName:"例子后端常规监控",
            	onCellData:function(cell, row, col, data){
            		if(row == 0){
            			return data;
            		}else{
            			return data.replace(/\([^\)]*\)/g,"");
            		}
                }
            },
            search:true,
            undefinedText:"无",
            pageSize: 20, //每页的记录行数(*)
            pageList: [20, 50, 100, 150], //可供选择的每页的行数(*)
            //sortable: true, //是否启用排序
            //sortName:"stat_dt",
            //sortOrder:"desc",
            columns:[
                 {
                    field:"stat_dt",
                    title:"统计日期",
                    sortable:true,
                    sorter:function(a, b){
                    	var d1 = new Date(a.replace(/\-/g, "\/"));
                    	var d2 = new Date(b.replace(/\-/g, "\/"));
                    	if(a != "" && b != ""){
                    	    return d1 - d2;
                    	}
                    }
                 },
                {
                 field:"platform",
                 title:"平台",
                 sortable:true
                },
                {
                    field:"app_name",
                    sortable:true,
                    title:"APP名称",
                    formatter:function(value,row,index){
                        if(value == "other"){
                            return "无";
                        }
                        return value;
                    }
                    },
                 {
                  field:"order_num",
                  sortable:true,
                  title:"例子订单量",
                  sorter:numberSort
                  },
                  ......

superset能否连接ElasticSearch

找到一个组件,还没来得及看呢
https://pypi.python.org/pypi/sqlalchemy-elasticquery/

修改bootstrap table 单元格背景色

         cellStyle:function(value,row,index){
                       var allTableData = $('#table').bootstrapTable('getData');
               		 var tmp = allTableData[index];
               		 //console.log(tmp[3]);
                        console.log(tmp[6]+","+tmp[3]);
                       // console.log(value+","+row+","+index);
                        if (value==1){
                   		 return {css:{"background-color":"red"}}
                        }else{
                            return {css:{"background-color":"green"}}
                        }
               	}

maven项目出现数组越界异常

解决方案:3.5的会出现这个问题,更换maven版本位3.3.9就ok了

[ERROR] 44410
java.lang.ArrayIndexOutOfBoundsException: 44410
	at org.codehaus.plexus.util.xml.pull.MXParser.parsePI(MXParser.java:2502)
	at org.codehaus.plexus.util.xml.pull.MXParser.parseEpilog(MXParser.java:1604)
	at org.codehaus.plexus.util.xml.pull.MXParser.nextImpl(MXParser.java:1434)
	at org.codehaus.plexus.util.xml.pull.MXParser.next(MXParser.java:1131)
	at org.apache.maven.model.io.xpp3.MavenXpp3Reader.read(MavenXpp3Reader.java:3856)
	at org.apache.maven.model.io.xpp3.MavenXpp3Reader.read(MavenXpp3Reader.java:595)
	at org.apache.maven.model.io.DefaultModelReader.read(DefaultModelReader.java:109)
	at org.apache.maven.model.io.DefaultModelReader.read(DefaultModelReader.java:82)
	at org.apache.maven.model.building.DefaultModelProcessor.read(DefaultModelProcessor.java:81)
	at org.apache.maven.model.building.DefaultModelBuilder.readModel(DefaultModelBuilder.java:535)
	at org.apache.maven.model.building.DefaultModelBuilder.readParentExternally(DefaultModelBuilder.java:1097)
	at org.apache.maven.model.building.DefaultModelBuilder.readParent(DefaultModelBuilder.java:829)
	at org.apache.maven.model.building.DefaultModelBuilder.build(DefaultModelBuilder.java:331)
	at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.loadPom(DefaultArtifactDescriptorReader.java:321)
	at org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.readArtifactDescriptor(DefaultArtifactDescriptorReader.java:199)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.resolveCachedArtifactDescriptor(DefaultDependencyCollector.java:544)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.getArtifactDescriptorResult(DefaultDependencyCollector.java:528)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.processDependency(DefaultDependencyCollector.java:418)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.processDependency(DefaultDependencyCollector.java:372)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.process(DefaultDependencyCollector.java:360)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.doRecurse(DefaultDependencyCollector.java:513)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.processDependency(DefaultDependencyCollector.java:467)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.processDependency(DefaultDependencyCollector.java:372)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.process(DefaultDependencyCollector.java:360)
	at org.eclipse.aether.internal.impl.DefaultDependencyCollector.collectDependencies(DefaultDependencyCollector.java:263)
	at org.eclipse.aether.internal.impl.DefaultRepositorySystem.collectDependencies(DefaultRepositorySystem.java:325)
	at org.apache.maven.project.DefaultProjectDependenciesResolver.resolve(DefaultProjectDependenciesResolver.java:169)
	at org.apache.maven.lifecycle.internal.LifecycleDependencyResolver.getDependencies(LifecycleDependencyResolver.java:195)
	at org.apache.maven.lifecycle.internal.LifecycleDependencyResolver.resolveProjectDependencies(LifecycleDependencyResolver.java:127)
	at org.apache.maven.lifecycle.internal.MojoExecutor.ensureDependenciesAreResolved(MojoExecutor.java:246)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:200)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:154)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:146)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:309)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:194)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:107)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:993)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:345)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:191)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
[ERROR]

感觉是maven自己的plexus-utils包有问题
我也有如上问题,我是再pom中添加了activiti的jar就会报数组越界,去掉activiti的jar就正常。 但是我必须用activiti,也不知道究竟是什么原因。

[WARNING] The POM for org.slf4j:slf4j-api:jar:1.7.6 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for org.slf4j:slf4j-api:[unknown-version]
[FATAL] Non-parseable POM D:\maven\repository\org\slf4j\slf4j-parent\1.7.6\slf4j-parent-1.7.6.pom: end tag not allowed in epilog but got / (position: END_TAG seen ...\r\n\r\n\r\n </... @398:16) @ D:\maven\repository\org\slf4j\slf4j-parent\1.7.6\slf4j-parent-1.7.6.pom, line 398, column 16
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.709 s
[INFO] Finished at: 2017-07-04T15:23:48+08:00
[INFO] Final Memory: 12M/219M
[INFO] ------------------------------------------------------------------------
[ERROR] 17166
java.lang.ArrayIndexOutOfBoundsException: 17166
at org.codehaus.plexus.util.xml.pull.MXParser.parsePI(MXParser.java:2502)
at org.codehaus.plexus.util.xml.pull.MXParser.parseEpilog(MXParser.java:1604)
at org.codehaus.plexus.util.xml.pull.MXParser.nextImpl(MXParser.java:1434)
at org.codehaus.plexus.util.xml.pull.MXParser.next(MXParser.java:1131)
at org.apache.maven.model.io.xpp3.MavenXpp3Reader.read(MavenXpp3Reader.java:3856)
at org.apache.maven.model.io.xpp3.MavenXpp3Reader.read(MavenXpp3Reader.java:595)
at org.apache.maven.model.io.DefaultModelReader.read(DefaultModelReader.java:109)
at org.apache.maven.model.io.DefaultModelReader.read(DefaultModelReader.java:82)

linux导出sql导入windows,out of memory

导入sql文件,这个可以用于大文件3.9G的文件,用navcat客户端导入有问题 out of memory。
例如:我的用户名是root 密码是123 sql脚本存在C盘 名字为test.sql 数据库为test
有两种方法可以执行脚本
1:打开CMD输入以下命令(不需要转换目录)

>mysql -u root -p123

进入MYSQL后

mysql>use test;
mysql> source c:/test.sql

ok执行完了,你可以用show tables;查看有哪写表(记得语句后有个分号)
还可以用desc tableName;查看你的表结构
 
2:打开CMD输入以下命令(进入mysql的bin目录)

d:\mysql\bin>mysql -u root -p123 test < c:/test.sql 

在window的服务里找到mysql服务就可以看到mysql完成安装路径 今天想把远程MySQL服务器上的一张表导入到本地数据库,于是先使用mysqldump导出这张表,这是很容易的,轻松搞定。但是导入的时候就不行了,总是提示Unknown command ‘\\’。一开始还以为这是mysql的bug,自己导出的东西自己不能导入,后来想想MySQL不应该这么弱的,就上网搜了一下,结果发现是默认字符集的问题。远程的数据库服务器操作系统是Linux,OS的默认字符集也是UTF-8,但是我本机用的是Windows 7,默认的字符集是GBK,在导入的时候加上–default-character-set=utf8就好了。最后附上完整的导入导出语句

 mysqldump -udbuser -p database table > exp.sql;
mysql -udbuser -p --default-character-set=utf8 database < exp.sql  

linux导出的sql文件导入到window系统里的mysql一定要指定编码 导入命令:

 mysql> source d:/rew.sql