• 关于 事务-特性 的搜索结果

回答

struts2所必须的jar包五个:struts2-core-2.1.6.jar ------struts2的核心包freemarker-2.3.13.jar-------FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具commons-logging.jar ------Jakarta的通用日志记录包ognl-2.6.11.jar --------支持ognl表达式xwork-2.1.2.jar ------xwork的包 由于Struts2是由xwork的延伸 有些类依然关联着xwork的类Hibernate所用15个jar包:Hbernate3.jar-----核心包antlr.jar-------语言转换工具,hibernate用他将hql语句转换为sql语句dom4j.jar--------解析xml文档的工具ehcahe.jar----------缓存工具,如没提供其它缓存,默认使用他jta.jar----------标准的JTAAPI(JTA即java事物API,JTA事务比JDBC事务更强大。一个JTA事务可以有多个参与者,而一个JDBC事务则被限定在一个单一的数据库连接),有朋友说这个包可以不要,不过没测试,反正加这个没错,所以就没删除了。cglib.jar---------高效的代码生成工具,Hibernate用它在运行时扩展 Java类和实现 Java 接口asm.jar-------ASM字节码库 ,使用“cglib”则必要 asm-attrs.jar-------ASM字节码库,使用“cglib”则必要 commons-collections-2.1.1.jar-----Apache的工具集,集合类 ,用来增强Java对集合的处理能力。jaxen-1.1-beta-7.jar------------------用dom的方式解析工程中xml文件,如果想提高启动性能则去使用(可选)commons-logging.jar---------------日志工具log4j1.2.11.jar--------------------------log4j库,Apache 的日志工具commons-pool.jar,commons-dbcp.jar--------DBCP数据库连接池,Apache的Jakarta组织开发的,Tomcat4的连接池也是DBCP。(可选)xml-apis.jar------------------------------解析xml。spring所用的5个jar:spring.jar----------------------------是包含有完整发布的单个jar包spring-aop.jar----------------------这个jar文件包含在应用中使用Spring的AOP特性时所需的类aspectjrt.jar---------------------------------是SpringAop所要用到的包commons-digester.jar--------------------Digester基于规则的XML文档解析,主要用于XML到Java对象的映射.aspectjweaver.jar-------------------------用于在Spring2.0中集成AspectJ AspectJ LTW织入器其他4个jar包:msbase.jar,mssqlserver.jar,msutil.jar----连接数据库sqlserver 20003个jar struts2-spring-plugin-2.0.11.1.jar-------struts2与spring整合所需的插件。

蛮大人123 2019-12-02 01:49:31 0 浏览量 回答数 0

问题

魔乐MLDN李兴华主讲Oracle视频教程

webssss 2019-12-01 20:58:21 13867 浏览量 回答数 5

问题

spring事物不回滚的问题。 400 请求出错 

kun坤 2020-05-25 20:35:55 11 浏览量 回答数 1

新用户福利专场,云服务器ECS低至96.9元/年

新用户福利专场,云服务器ECS低至96.9元/年

回答

TokuDB的优点: -高压缩比,默认使用zlib进行压缩,尤其是对字符串(varchar,text等)类型有非常高的压缩比,比较适合存储日志、原始数据等。 - 在线添加索引,不影响读写操作 - HCADER 特性,支持在线字段增加、删除、扩展、重命名操作,(瞬间或秒级完成) - 支持完整的ACID特性和事务机制 - 非常快的写入性能, Fractal-tree在事务实现上有优势,无undo log。 - 支持show processlist 进度查看 - 数据量可以扩展到几个TB; - 不会产生索引碎片; - 支持hot column addition,hot indexing,mvcc TokuDB缺点: 不支持外键(foreign key)功能,如果您的表有外键,切换到 TokuDB引擎后,此约束将被忽略。TokuDB 不适大量读取的场景,因为压缩解压缩的原因。CPU占用会高2-3倍,但由于压缩后空间小,IO开销低,平均响应时间大概是2倍左右。online ddl 对text,blob等类型的字段不适用没有完善的热备工具,只能通过mysqldump进行逻辑备份 适用场景: 访问频率不高的数据或历史数据归档数据表非常大并且时不时还需要进行DDL操作

小霉子 2020-05-08 14:34:10 0 浏览量 回答数 0

问题

spring + jpa 配置问题,No transactional EntityManager available

a123456678 2019-12-01 20:26:35 2349 浏览量 回答数 1

回答

共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE 锁的类别有两种分法: 1. 从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁 MS-SQL Server 使用以下资源锁模式。 锁模式 描述 共享 (S) 用于不更改或不更新数据的操作(只读操作),如 SELECT 语句。 更新 (U) 用于可更新的资源中。防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。 排它 (X) 用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。 意向锁 用于建立锁的层次结构。意向锁的类型为:意向共享 (IS)、意向排它 (IX) 以及与意向排它共享 (SIX)。 架构锁 在执行依赖于表架构的操作时使用。架构锁的类型为:架构修改 (Sch-M) 和架构稳定性 (Sch-S)。 大容量更新 (BU) 向表中大容量复制数据并指定了 TABLOCK 提示时使用。 共享锁 共享 (S) 锁允许并发事务读取 (SELECT) 一个资源。资源上存在共享 (S) 锁时,任何其它事务都不能修改数据。一旦已经读取数据,便立即释放资源上的共享 (S) 锁,除非将事务隔离级别设置为可重复读或更高级别,或者在事务生存周期内用锁定提示保留共享 (S) 锁。 更新锁 更新 (U) 锁可以防止通常形式的死锁。一般更新模式由一个事务组成,此事务读取记录,获取资源(页或行)的共享 (S) 锁,然后修改行,此操作要求锁转换为排它 (X) 锁。如果两个事务获得了资源上的共享模式锁,然后试图同时更新数据,则一个事务尝试将锁转换为排它 (X) 锁。共享模式到排它锁的转换必须等待一段时间,因为一个事务的排它锁与其它事务的共享模式锁不兼容;发生锁等待。第二个事务试图获取排它 (X) 锁以进行更新。由于两个事务都要转换为排它 (X) 锁,并且每个事务都等待另一个事务释放共享模式锁,因此发生死锁。 若要避免这种潜在的死锁问题,请使用更新 (U) 锁。一次只有一个事务可以获得资源的更新 (U) 锁。如果事务修改资源,则更新 (U) 锁转换为排它 (X) 锁。否则,锁转换为共享锁。 排它锁 排它 (X) 锁可以防止并发事务对资源进行访问。其它事务不能读取或修改排它 (X) 锁锁定的数据。 意向锁 意向锁表示 SQL Server 需要在层次结构中的某些底层资源上获取共享 (S) 锁或排它 (X) 锁。例如,放置在表级的共享意向锁表示事务打算在表中的页或行上放置共享 (S) 锁。在表级设置意向锁可防止另一个事务随后在包含那一页的表上获取排它 (X) 锁。意向锁可以提高性能,因为 SQL Server 仅在表级检查意向锁来确定事务是否可以安全地获取该表上的锁。而无须检查表中的每行或每页上的锁以确定事务是否可以锁定整个表。 意向锁包括意向共享 (IS)、意向排它 (IX) 以及与意向排它共享 (SIX)。 锁模式 描述 意向共享 (IS) 通过在各资源上放置 S 锁,表明事务的意向是读取层次结构中的部分(而不是全部)底层资源。 意向排它 (IX) 通过在各资源上放置 X 锁,表明事务的意向是修改层次结构中的部分(而不是全部)底层资源。IX 是 IS 的超集。 与意向排它共享 (SIX) 通过在各资源上放置 IX 锁,表明事务的意向是读取层次结构中的全部底层资源并修改部分(而不是全部)底层资源。允许顶层资源上的并发 IS 锁。例如,表的 SIX 锁在表上放置一个 SIX 锁(允许并发 IS 锁),在当前所修改页上放置 IX 锁(在已修改行上放置 X 锁)。虽然每个资源在一段时间内只能有一个 SIX 锁,以防止其它事务对资源进行更新,但是其它事务可以通过获取表级的 IS 锁来读取层次结构中的底层资源。 独占锁:只允许进行锁定操作的程序使用,其他任何对他的操作均不会被接受。执行数据更新命令时,SQL Server会自动使用独占锁。当对象上有其他锁存在时,无法对其加独占锁。 共享锁:共享锁锁定的资源可以被其他用户读取,但其他用户无法修改它,在执行Select时,SQL Server会对对象加共享锁。 更新锁:当SQL Server准备更新数据时,它首先对数据对象作更新锁锁定,这样数据将不能被修改,但可以读取。等到SQL Server确定要进行更新数据操作时,他会自动将更新锁换为独占锁,当对象上有其他锁存在时,无法对其加更新锁。 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能例外。MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎所针对的应用场景特点都不太一样,为了满足各自特定应用场景的需求,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计,所以各存储引擎的锁定机制也有较大区别。MySQL各存储引擎使用了三种类型(级别)的锁定机制:表级锁定,行级锁定和页级锁定。 1.表级锁定(table-level) 表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。 当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。 使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。 2.行级锁定(row-level) 行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。 虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。 使用行级锁定的主要是InnoDB存储引擎。 3.页级锁定(page-level) 页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。 在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。 使用页级锁定的主要是BerkeleyDB存储引擎。 总的来说,MySQL这3种锁的特性可大致归纳如下: 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低; 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高; 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。 适用:从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。 -------------MYSQL处理------------------ 表级锁定 由于MyISAM存储引擎使用的锁定机制完全是由MySQL提供的表级锁定实现,所以下面我们将以MyISAM存储引擎作为示例存储引擎。 1.MySQL表级锁的锁模式 MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。锁模式的兼容性: 对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求; 对MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作; MyISAM表的读操作与写操作之间,以及写操作之间是串行的。当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。 2.如何加表锁 MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。 3.MyISAM表锁优化建议 对于MyISAM存储引擎,虽然使用表级锁定在锁定实现的过程中比实现行级锁定或者页级锁所带来的附加成本都要小,锁定本身所消耗的资源也是最少。但是由于锁定的颗粒度比较到,所以造成锁定资源的争用情况也会比其他的锁定级别都要多,从而在较大程度上会降低并发处理能力。所以,在优化MyISAM存储引擎锁定问题的时候,最关键的就是如何让其提高并发度。由于锁定级别是不可能改变的了,所以我们首先需要尽可能让锁定的时间变短,然后就是让可能并发进行的操作尽可能的并发。 (1)查询表级锁争用情况 MySQL内部有两组专门的状态变量记录系统内部锁资源争用情况: mysql> show status like 'table%'; +----------------------------+---------+ | Variable_name | Value | +----------------------------+---------+ | Table_locks_immediate | 100 | | Table_locks_waited | 10 | +----------------------------+---------+ 这里有两个状态变量记录MySQL内部表级锁定的情况,两个变量说明如下: Table_locks_immediate:产生表级锁定的次数; Table_locks_waited:出现表级锁定争用而发生等待的次数; 两个状态值都是从系统启动后开始记录,出现一次对应的事件则数量加1。如果这里的Table_locks_waited状态值比较高,那么说明系统中表级锁定争用现象比较严重,就需要进一步分析为什么会有较多的锁定资源争用了。 (2)缩短锁定时间 如何让锁定时间尽可能的短呢?唯一的办法就是让我们的Query执行时间尽可能的短。 a)尽两减少大的复杂Query,将复杂Query分拆成几个小的Query分布进行; b)尽可能的建立足够高效的索引,让数据检索更迅速; c)尽量让MyISAM存储引擎的表只存放必要的信息,控制字段类型; d)利用合适的机会优化MyISAM表数据文件。 (3)分离能并行的操作 说到MyISAM的表锁,而且是读写互相阻塞的表锁,可能有些人会认为在MyISAM存储引擎的表上就只能是完全的串行化,没办法再并行了。大家不要忘记了,MyISAM的存储引擎还有一个非常有用的特性,那就是ConcurrentInsert(并发插入)的特性。 MyISAM存储引擎有一个控制是否打开Concurrent Insert功能的参数选项:concurrent_insert,可以设置为0,1或者2。三个值的具体说明如下: concurrent_insert=2,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录; concurrent_insert=1,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置; concurrent_insert=0,不允许并发插入。 可以利用MyISAM存储引擎的并发插入特性,来解决应用中对同一表查询和插入的锁争用。例如,将concurrent_insert系统变量设为2,总是允许并发插入;同时,通过定期在系统空闲时段执行OPTIMIZE TABLE语句来整理空间碎片,收回因删除记录而产生的中间空洞。 (4)合理利用读写优先级 MyISAM存储引擎的是读写互相阻塞的,那么,一个进程请求某个MyISAM表的读锁,同时另一个进程也请求同一表的写锁,MySQL如何处理呢? 答案是写进程先获得锁。不仅如此,即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁请求之前。 这是因为MySQL的表级锁定对于读和写是有不同优先级设定的,默认情况下是写优先级要大于读优先级。 所以,如果我们可以根据各自系统环境的差异决定读与写的优先级: 通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接读比写的优先级高。如果我们的系统是一个以读为主,可以设置此参数,如果以写为主,则不用设置; 通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。 虽然上面方法都是要么更新优先,要么查询优先的方法,但还是可以用其来解决查询相对重要的应用(如用户登录系统)中,读锁等待严重的问题。 另外,MySQL也提供了一种折中的办法来调节读写冲突,即给系统参数max_write_lock_count设置一个合适的值,当一个表的读锁达到这个值后,MySQL就暂时将写请求的优先级降低,给读进程一定获得锁的机会。 这里还要强调一点:一些需要长时间运行的查询操作,也会使写进程“饿死”,因此,应用中应尽量避免出现长时间运行的查询操作,不要总想用一条SELECT语句来解决问题,因为这种看似巧妙的SQL语句,往往比较复杂,执行时间较长,在可能的情况下可以通过使用中间表等措施对SQL语句做一定的“分解”,使每一步查询都能在较短时间完成,从而减少锁冲突。如果复杂查询不可避免,应尽量安排在数据库空闲时段执行,比如一些定期统计可以安排在夜间执行 三、行级锁定 行级锁定不是MySQL自己实现的锁定方式,而是由其他存储引擎自己所实现的,如广为大家所知的InnoDB存储引擎,以及MySQL的分布式存储引擎NDBCluster等都是实现了行级锁定。考虑到行级锁定君由各个存储引擎自行实现,而且具体实现也各有差别,而InnoDB是目前事务型存储引擎中使用最为广泛的存储引擎,所以这里我们就主要分析一下InnoDB的锁定特性。 1.InnoDB锁定模式及实现机制 考虑到行级锁定君由各个存储引擎自行实现,而且具体实现也各有差别,而InnoDB是目前事务型存储引擎中使用最为广泛的存储引擎,所以这里我们就主要分析一下InnoDB的锁定特性。 总的来说,InnoDB的锁定机制和Oracle数据库有不少相似之处。InnoDB的行级锁定同样分为两种类型,共享锁和排他锁,而在锁定机制的实现过程中为了让行级锁定和表级锁定共存,InnoDB也同样使用了意向锁(表级锁定)的概念,也就有了意向共享锁和意向排他锁这两种。 当一个事务需要给自己需要的某个资源加锁的时候,如果遇到一个共享锁正锁定着自己需要的资源的时候,自己可以再加一个共享锁,不过不能加排他锁。但是,如果遇到自己需要锁定的资源已经被一个排他锁占有之后,则只能等待该锁定释放资源之后自己才能获取锁定资源并添加自己的锁定。而意向锁的作用就是当一个事务在需要获取资源锁定的时候,如果遇到自己需要的资源已经被排他锁占用的时候,该事务可以需要锁定行的表上面添加一个合适的意向锁。如果自己需要一个共享锁,那么就在表上面添加一个意向共享锁。而如果自己需要的是某行(或者某些行)上面添加一个排他锁的话,则先在表上面添加一个意向排他锁。意向共享锁可以同时并存多个,但是意向排他锁同时只能有一个存在。所以,可以说InnoDB的锁定模式实际上可以分为四种:共享锁(S),排他锁(X),意向共享锁(IS)和意向排他锁(IX),我们可以通过以下表格来总结上面这四种所的共存逻辑关系 如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。 意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁。 共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE 用SELECT ... IN SHARE MODE获得共享锁,主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。 但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT... FOR UPDATE方式获得排他锁。 2.InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁 在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。下面通过一些实际例子来加以说明。 (1)在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁。 (2)由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。 (3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。 (4)即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。 3.间隙锁(Next-Key锁) 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁; 对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。 例: 假如emp表中只有101条记录,其empid的值分别是 1,2,...,100,101,下面的SQL: mysql> select * from emp where empid > 100 for update; 是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。 InnoDB使用间隙锁的目的: (1)防止幻读,以满足相关隔离级别的要求。对于上面的例子,要是不使用间隙锁,如果其他事务插入了empid大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读; (2)为了满足其恢复和复制的需要。 很显然,在使用范围条件检索并锁定记录时,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。 除了间隙锁给InnoDB带来性能的负面影响之外,通过索引实现锁定的方式还存在其他几个较大的性能隐患: (1)当Query无法利用索引的时候,InnoDB会放弃使用行级别锁定而改用表级别的锁定,造成并发性能的降低; (2)当Query使用的索引并不包含所有过滤条件的时候,数据检索使用到的索引键所只想的数据可能有部分并不属于该Query的结果集的行列,但是也会被锁定,因为间隙锁锁定的是一个范围,而不是具体的索引键; (3)当Query在使用索引定位数据的时候,如果使用的索引键一样但访问的数据行不同的时候(索引只是过滤条件的一部分),一样会被锁定。 因此,在实际应用开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。 还要特别说明的是,InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁。 4.死锁 MyISAM表锁是deadlock free的,这是因为MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。但在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,当两个事务都需要获得对方持有的排他锁才能继续完成事务,这种循环锁等待就是典型的死锁。 在InnoDB的事务管理和锁定机制中,有专门检测死锁的机制,会在系统中产生死锁之后的很短时间内就检测到该死锁的存在。当InnoDB检测到系统中产生了死锁之后,InnoDB会通过相应的判断来选这产生死锁的两个事务中较小的事务来回滚,而让另外一个较大的事务成功完成。 那InnoDB是以什么来为标准判定事务的大小的呢?MySQL官方手册中也提到了这个问题,实际上在InnoDB发现死锁之后,会计算出两个事务各自插入、更新或者删除的数据量来判定两个事务的大小。也就是说哪个事务所改变的记录条数越多,在死锁中就越不会被回滚掉。 但是有一点需要注意的就是,当产生死锁的场景中涉及到不止InnoDB存储引擎的时候,InnoDB是没办法检测到该死锁的,这时候就只能通过锁定超时限制参数InnoDB_lock_wait_timeout来解决。 需要说明的是,这个参数并不是只用来解决死锁问题,在并发访问比较高的情况下,如果大量事务因无法立即获得所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖跨数据库。我们通过设置合适的锁等待超时阈值,可以避免这种情况发生。 通常来说,死锁都是应用设计的问题,通过调整业务流程、数据库对象设计、事务大小,以及访问数据库的SQL语句,绝大部分死锁都可以避免。下面就通过实例来介绍几种避免死锁的常用方法: (1)在应用中,如果不同的程序会并发存取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会。 (2)在程序以批量方式处理数据的时候,如果事先对数据排序,保证每个线程按固定的顺序来处理记录,也可以大大降低出现死锁的可能。 (3)在事务中,如果要更新记录,应该直接申请足够级别的锁,即排他锁,而不应先申请共享锁,更新时再申请排他锁,因为当用户申请排他锁时,其他事务可能又已经获得了相同记录的共享锁,从而造成锁冲突,甚至死锁。 (4)在REPEATABLE-READ隔离级别下,如果两个线程同时对相同条件记录用SELECT...FOR UPDATE加排他锁,在没有符合该条件记录情况下,两个线程都会加锁成功。程序发现记录尚不存在,就试图插入一条新记录,如果两个线程都这么做,就会出现死锁。这种情况下,将隔离级别改成READ COMMITTED,就可避免问题。 (5)当隔离级别为READ COMMITTED时,如果两个线程都先执行SELECT...FOR UPDATE,判断是否存在符合条件的记录,如果没有,就插入记录。此时,只有一个线程能插入成功,另一个线程会出现锁等待,当第1个线程提交后,第2个线程会因主键重出错,但虽然这个线程出错了,却会获得一个排他锁。这时如果有第3个线程又来申请排他锁,也会出现死锁。对于这种情况,可以直接做插入操作,然后再捕获主键重异常,或者在遇到主键重错误时,总是执行ROLLBACK释放获得的排他锁。 5.什么时候使用表锁 对于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁: (1)事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。 (2)事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。 应用中这两种事务不能太多,否则,就应该考虑使用MyISAM表了。 在InnoDB下,使用表锁要注意以下两点。 (1)使用LOCK TABLES虽然可以给InnoDB加表级锁,但必须说明的是,表锁不是由InnoDB存储引擎层管理的,而是由其上一层──MySQL Server负责的,仅当autocommit=0、InnoDB_table_locks=1(默认设置)时,InnoDB层才能知道MySQL加的表锁,MySQL Server也才能感知InnoDB加的行锁,这种情况下,InnoDB才能自动识别涉及表级锁的死锁,否则,InnoDB将无法自动检测并处理这种死锁。 (2)在用 LOCK TABLES对InnoDB表加锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCK TABLES释放表锁,因为UNLOCK TABLES会隐含地提交事务;COMMIT或ROLLBACK并不能释放用LOCK TABLES加的表级锁,必须用UNLOCK TABLES释放表锁。

1006541099824509 2019-12-02 03:14:39 0 浏览量 回答数 0

回答

以下是配置文件:web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <error-page> <error-code>401</error-code> <location>/error.jsp</location> </error-page> <error-page> <error-code>403</error-code> <location>/error.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/error.jsp</location> </error-page> <context-param> <param-name> contextConfigLocation </param-name> <param-value> /WEB-INF/classes/spring-servlet.xml </param-value> </context-param> <!-- 将EntityManager的范围扩大到view层 --> <filter> <filter-name>openSessionInView</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> <init-param> <param-name>singleSession</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>openSessionInView</filter-name> <url-pattern>*.do</url-pattern> <url-pattern>*.json</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>*.do</url-pattern> <url-pattern>*.json</url-pattern> </servlet-mapping> </web-app><span></span> ? spring配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <context:annotation-config /> <context:component-scan base-package="com.gswtek.mawjaw.controller" /> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**/listAll*.do" /> <bean class="com.gswtek.mawjaw.filter.DispatcherInterceptor" /> </mvc:interceptor> </mvc:interceptors> <!-- JSP视图 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/jsp/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> <!-- JSON试图 --> <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="mediaTypes"> <map> <entry key="json" value="application/json" /> </map> </property> <property name="defaultViews"> <list> <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" /> </list> </property> </bean> <!-- 上传文件 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="1000000" /> <property name="defaultEncoding" value="utf-8" /> </bean> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driverClassName}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="minPoolSize" value="${jdbc.minPoolSize}" /> <property name="maxPoolSize" value="${jdbc.maxPoolSize}" /> <property name="initialPoolSize" value="${jdbc.initialPoolSize}" /> <property name="maxIdleTime" value="${jdbc.maxIdleTime}" /> <property name="acquireIncrement" value="${jdbc.acquireIncrement}" /> <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}" /> <property name="acquireRetryDelay" value="${jdbc.acquireRetryDelay}" /> <property name="testConnectionOnCheckin" value="${jdbc.testConnectionOnCheckin}" /> <property name="automaticTestTable" value="${jdbc.automaticTestTable}" /> <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}" /> <property name="checkoutTimeout" value="${jdbc.checkoutTimeout}" /> </bean> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource" /> </property> <property name="hibernateProperties"> <props> <!-- SQL方言 --> <prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop> <!-- 输出SQL语句 --> <prop key="hibernate.show_sql">true</prop> <!-- 格式化SQL语句 --> <prop key="hibernate.format_sql">false</prop> <!-- 更新表结构 --> <prop key="hibernate.hbm2ddl.auto">update</prop> <!-- 缓存实现类 --> <prop key="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </prop> <!-- 使用查询缓存 --> <prop key="hibernate.cache.use_query_cache">true</prop> </props> </property> <property name="mappingResources"> <list> <value>com/gswtek/mawjaw/bean/User.hbm.xml</value> <value>com/gswtek/mawjaw/bean/Writer.hbm.xml</value> <value>com/gswtek/mawjaw/bean/Illustrator.hbm.xml</value> <value>com/gswtek/mawjaw/bean/IlluImage.hbm.xml</value> <value>com/gswtek/mawjaw/bean/Tvfilm.hbm.xml</value></list> </property> </bean> <!-- Hibernate事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="sessionFactory"/> </property> </bean> <!-- 事务传播特性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- 配置事务 --> <aop:config> <aop:pointcut expression="execution(* com.gswtek.mawjaw.service.*.*(..))" id="allServiceMethod"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="allServiceMethod"/> </aop:config> <bean id="UserDAO" class="com.gswtek.mawjaw.dao.UserDAO"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <bean id="WriterDAO" class="com.gswtek.mawjaw.dao.WriterDAO"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <bean id="IllustratorDAO" class="com.gswtek.mawjaw.dao.IllustratorDAO"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <bean id="IlluImageDAO" class="com.gswtek.mawjaw.dao.IlluImageDAO"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <bean id="TvfilmDAO" class="com.gswtek.mawjaw.dao.TvfilmDAO"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <bean id="UserService" class="com.gswtek.mawjaw.service.UserServiceImpl"> <property name="userDAO" ref="UserDAO" /> </bean> <bean id="WriterService" class="com.gswtek.mawjaw.service.WriterServiceImpl"> <property name="writerDAO" ref="WriterDAO" /> <property name="userDAO" ref="UserDAO" /> </bean> <bean id="IllustratorService" class="com.gswtek.mawjaw.service.IllustratorServiceImpl"> <property name="illuImageDAO" ref="IlluImageDAO" /> <property name="illustratorDAO" ref="IllustratorDAO" /> </bean> <bean id="TvfilmService" class="com.gswtek.mawjaw.service.TvfilmServiceImpl"> <property name="tvfilmDAO" ref="TvfilmDAO" /> </bean> </beans>

a123456678 2019-12-02 02:10:19 0 浏览量 回答数 0

问题

DRDS 错误代码如何解决?

猫饭先生 2019-12-01 21:21:21 7993 浏览量 回答数 0

问题

关于Spring整合Hibernate的问题

蛮大人123 2019-12-01 19:59:26 1178 浏览量 回答数 1

回答

本文介绍了如何使用 Serverless 工作流提供长流程分布式事务保证,帮助用户聚焦于自身业务逻辑。 简介 复杂的业务场景例如电商网站、酒店、航班预定这类涉及订单管理的应用通常要访问多个远程服务,并且对操作事务性语义(即所有步骤全部成功或全部失败,不存在中间状态)有较高要求。在流量较小、数据存储集中的应用中,事务性可以通过关系型数据库提供的 ACID 特性满足。然而在大流量场景下,为了高可用和可扩展性,业务通常选择向微服务的分布式架构方向演进。在这样的架构中提供多步骤事务性的保证通常需要引入队列和数据库来持久化消息以及展现流程状态,这类系统的开发和运维会给业务方带来额外的成本和负担。而使用 Serverless 工作流提供长流程分布式事务保证会帮您解决这些问题。 场景描述 假设某应用为其用户提供预定火车票、航班和酒店的功能,要求三个步骤保证事务性。该功能需要三个远程调用实现(例如预定火车票需要调用 12306 接口),如果三个调用都成功则该订单成功。然而实际上任何一个远程调用都有可能会失败,因此该应用需要对不同的失败场景做出相应的补偿逻辑,回退已完成操作。如下图所示: 如果预定火车票(BuyTrainTicket)成功,而预定航班(ReserveFlight)失败,则需要取消已经购买的火车票 (CancelTrainTicket),并告知用户订单失败。 如果预定火车票(BuyTrainTicket)和预定航班(ReserveFlight)均成功,但是预订酒店(ReserveHotel) 失败,则需要取消已经预定的航班(CancelFlight)和火车票(CancelTrainTicket),并告知用户订单失败。 longtxn-saga_train_flight_hotel Serverless 工作流实现 下文的示例将 FC 函数编排成一个 Serverless 工作流流程从而实现了一个可靠的多步骤长流程,该示例分为 3 步: 创建 FC 函数 创建流程 执行并查看结果 步骤 1:创建 FC 函数(模拟上面提到的3个操作:预定火车票、预定航班、预定酒店) 创建下面的 Python2.7 的函数,关于创建的详细步骤,可以参见 FC 文档,建议命名: Service: fnf-demo Function: Operation Operation 函数模拟各操作(例如预定航班、预定酒店)的实现,根据输入决定该操作执行结果(成功或失败)。 import json import logging import uuid def handler(event, context): evt = json.loads(event) logger = logging.getLogger() id = uuid.uuid4() op = "operation" if 'operation' in evt: op = evt['operation'] if op in evt: result = evt[op] if result == False: logger.info("%s failed" % op) exit() logger.info("%s succeeded, id %s" % (op, id)) return '{"%s":"success", "%s_txnID": "%s"}' % (op, op, id) 步骤 2:创建流程 使用 Serverless 工作流控制台创建下面的流程。 配置流程 RAM 角色 { "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "Service": [ "fnf.aliyuncs.com" ] } } ], "Version": "1" } 流程定义 version: v1 type: flow steps: - type: task resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/Operation name: BuyTrainTicket inputMappings: - target: operation source: buy_train_ticket - target: buy_train_ticket source: $input.buy_train_ticket_result catch: - errors: - FC.Unknown goto: OrderFailed - type: task resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/Operation name: ReserveFlight inputMappings: - target: operation source: reserve_flight - target: reserve_flight source: $input.reserve_flight_result catch: # 捕获 ReserveFlight task 抛出的 FC.Unknown 错误,跳转到 CancelTrainTicket。 - errors: - FC.Unknown goto: CancelTrainTicket - type: task resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/Operation name: ReserveHotel inputMappings: - target: operation source: reserve_hotel - target: reserve_hotel source: $input.reserve_hotel_result retry: # 对 FC.Unknown 类型的错误最多指数退避重试 3 次,初始间隔 1s,后续间隔 = 上次间隔 * 2。 - errors: - FC.Unknown intervalSeconds: 1 maxAttempts: 3 multiplier: 2 catch: # 捕获 ReserveHotel task 抛出的 FC.Unknown 错误,跳转到 CancelFlight。 - errors: - FC.Unknown goto: CancelFlight - type: succeed name: OrderSucceeded - type: task resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/Operation name: CancelFlight inputMappings: - target: operation source: cancel_flight - target: reserve_flight_txnID source: $local.reserve_flight_txnID - type: task resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/Operation name: CancelTrainTicket inputMappings: - target: operation source: cancel_train_ticket - target: reserve_flight_txnID source: $local.reserve_flight_txnID - type: fail name: OrderFailed 步骤 3:执行并查看结果 在控制台上对创建好的流程(Flow)开始一个新的执行(Execution)。StartExecution API 要求传入 JSON 格式的输入。下面的 JSON 对象可以模拟每个步骤的成功或失败(例如 "reserve_hotel_result":"fail" 代表模拟预定酒店这步失败)。StartExecution 是一个异步 API,调用结束后,Serverless 工作流会返回一个执行名字用来查询流程执行状态。 { "buy_train_ticket_result":"success", "reserve_flight_result":"success", "reserve_hotel_result":"fail" } 流程执行开始后,在 Serverless 工作流控制台单击进入该执行并查看执行过程和结果。可以看到,由于 "reserve_hotel_result":"fail" 和 ReserveHotel 函数调用失败,Serverless 工作流按照流程定义,依次取消航班(CancelFlight)、取消火车票(CancelTrainTicket)。Serverless 工作流每个步骤转换有持久化的保证,因此网络中断或进程崩溃等失败场景不会影响流程事务性的保证。 Screen Shot 2019-06-26 at 12.14.50 PM 流程执行会产生执行历史事件(event),这些事件可以通过控制台或者 SDK/CLI 调用 GetExecutionHistory API 查询。 Screen Shot 2019-06-26 at 12.17.26 PM 错误处理和重试 上面示例中的预定航班、预定酒店等远程调用都有可能受到网络或服务错误等原因导致调用失败,而增加对瞬时错误的重试可以提高订单流程成功率。Serverless 工作流在任务(Task)类型的步骤(Step)自带重试功能,如预定酒店这个步骤用下面的写法可以实现对 FC.Unknown 类型的错误指数退避。假设重试到达最大次数后 ReserveHotel 都无法成功,按照该步骤中 catch 的定义,ReserveHotel 函数抛出的 FC.Unknown 错误会被捕获并将跳转到 CancelFlight 执行定义好的补偿逻辑。 - type: task resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/Operation name: ReserveHotel inputMappings: - target: operation source: reserve_hotel retry: # 对 FC.Unknown 类型的错误最多指数退避重试3次,初始间隔1s,后续间隔 = 上次间隔 * 2。 - errors: - FC.Unknown intervalSeconds: 1 maxAttempts: 3 multiplier: 2 catch: # 捕获 ReserveHotel task 抛出的 FC.Unknown 错误,跳转到 CancelFlight。 - errors: - FC.Unknown goto: CancelFlight 下图可以看到加入重试之后预订酒店(ReserveHotel)任务执行了多次直到最大重试数。Screen Shot 2019-06-26 at 12.19.55 PM 步骤间的数据传递 预定酒店失败后需要取消航班和火车票,这两部分别需要用到预定航班和预定火车票返回的交易 ID (txnID),下面的 inputMapping 对象描述了如何将之前步骤产生的输出传入 CancelFlight 这个步骤中。 - type: task resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/Operation name: CancelFlight inputMappings: - target: operation source: cancel_flight - target: reserve_flight_txnID source: $local.reserve_flight_txnID 流程执行各步骤结束的输出都会被放在 StepExited 事件详情(EventDetail)的 local 对象中。 { "input":{ "operation":"reserve_hotel", "reserve_hotel_result":"fail" }, "local":{ "buy_train_ticket":"success", "buy_train_ticket_txnID":"d37412b3-bb68-4d04-9d90-c8c15643d45e", "reserve_flight_result":"success", "reserve_flight_txnID":"024caecf-cfa3-43a6-b561-9b6fe0571b55" }, "resourceArn":"acs:fc:{region}:{accountID}:services/fnf-demo/functions/Operation", "cause":"{"errorMessage":"Process exited unexpectedly before completing request (duration: 12ms, maxMemoryUsage: 9.18MB)"}", "error":"FC.Unknown", "retryCount":3, "goto":"CancelFlight" } 结合上面的 EventDetail 和 inputMappings 的映射之后,传入到 CancelFlight 步骤的输入变成如下 JSON 对象,这样 CancelFlight 函数的输入会包含 reserve_flight_txnID 字段。 "input":{ "operation":"cancel_flight", "reserve_flight_txnID":"024caecf-cfa3-43a6-b561-9b6fe0571b55" }

1934890530796658 2020-03-27 10:47:41 0 浏览量 回答数 0

回答

您可以使用 Pandora Boot 开发 HSF 应用,实现服务注册发现、异步调用,并完成单元测试。相比使用 ali-tomcat 部署 HSF 的 WAR 包,Pandora Boot部署的是 JAR 包。直接将 HSF 应用打包成 FatJar,这更加符合微服务的风格,不需要依赖外置的 ali-tomcat 也使得应用的部署更加灵活。Pandora Boot 可以认为是 Spring Boot 的增强。 前提条件 在开发应用前,您已经完成以下工作: 配置 SAE 的私服地址和轻量级配置及注册中心 启动轻量级配置及注册中心 服务注册与发现 介绍如何使用 Pandora Boot 开发应用(包括服务提供者和服务消费者)并实现服务注册与发现。 注意 严禁在应用启动时调用 HSF 远程服务,否则会导致启动失败。 Demo 源码下载:https://github.com/aliyun/alibabacloud-microservice-demo/tree/master/microservice-doc-demo/hsf-pandora-boot 使用 Git 克隆整个项目,并在 microservice-doc-demo/hsf-pandora-boot 文件夹内可以找到本文使用的示例工程。 创建服务提供者。 创建命名为 hsf-pandora-boot-provider的 Maven 工程。 在 pom.xml 中引入需要的依赖。 <java.version>1.8</java.version> <spring-boot.version>2.1.6.RELEASE</spring-boot.version> <pandora-boot.version>2019-06-stable</pandora-boot.version> com.alibaba.boot pandora-hsf-spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import com.taobao.pandora pandora-boot-starter-bom ${pandora-boot.version} pom import org.apache.maven.plugins maven-compiler-plugin 3.7.0 1.8 1.8 com.taobao.pandora pandora-boot-maven-plugin 2.1.11.8 package repackage 虽然 HSF 服务框架并不依赖于 Web 环境,但是在应用的生命周期过程中需要使用到 Web 相关的特性,所以需要添加 spring-boot-starter-web 的依赖。 pandora-hsf-spring-boot-starter 实现了 HSF 配置的自动装配。pandora-boot-maven-plugin 是 Pandora Boot 提供的 maven 打包插件,可以将 Pandora Boot HSF 工程编译为可执行的 FatJar,并在 EDAS Container 中部署运行。 dependencyManagement 中包含了 spring-boot-dependencies 和 pandora-boot-starter-bom 两个依赖,分别负责 Spring Boot 和 Pandora Boot 相关依赖的版本管理,设置之后,您的工程无需将 parent 设置为 spring-boot-starter-parent。 定义服务接口,创建一个接口类 com.alibaba.edas.HelloService。 HSF 服务框架基于接口进行服务通信,当接口定义好之后,生产者将通过该接口实现具体的服务并发布,消费者也是基于此接口去订阅和消费服务。 public interface HelloService { String echo(String string); } 接口 com.alibaba.edas.HelloService 提供了 echo 方法。 添加服务提供者的具体实现类 EchoServiceImpl ,并通过注解方式发布服务。 @HSFProvider(serviceInterface = HelloService.class, serviceVersion = "1.0.0") public class HelloServiceImpl implements HelloService { @Override public String echo(String string) { return string; } } 在 HSF 应用中,接口名和服务版本才能唯一确定一个服务,所以在注解 HSFProvider 中的需要添加接口名 com.alibaba.edas.HelloService 和服务版本1.0.0。 说明 注解中的配置拥有高优先级。 如果在注解中没有配置,服务发布时会优先在 resources/application.properties 文件中查找这些属性的全局配置。 如果注解和 resources/application.properties 文件中都没有配置,则会使用注解中的默认值。 在 resources 目录下的 application.properties 文件中配置应用名和监听端口号。 spring.application.name=hsf-pandora-boot-provider server.port=8081 spring.hsf.version=1.0.0 spring.hsf.timeout=3000 说明 建议将服务版本(spring.hsf.version)和服务超时(spring.hsf.timeout)都统一配置在 application.properties 中。 添加服务启动的 main 函数入口。 @SpringBootApplication public class HSFProviderApplication { public static void main(String[] args) { // 启动 Pandora Boot 用于加载 Pandora 容器 PandoraBootstrap.run(args); SpringApplication.run(HSFProviderApplication.class, args); // 标记服务启动完成,并设置线程 wait。防止业务代码运行完毕退出后,导致容器退出。 PandoraBootstrap.markStartupAndWait(); } } 表 1. 服务提供者属性列表 属性 是否必配 描述 类型 默认值 serviceInterface 是 服务对外提供的接口 Class java.lang.Object serviceVersion 否 服务的版本号 String 1.0.0.DAILY serviceGroup 否 服务的组名 String HSF clientTimeout 否 该配置对接口中的所有方法生效,但是如果客户端通过 methodSpecials 属性对某方法配置了超时时间,则该方法的超时时间以客户端配置为准。其他方法不受影响,还是以服务端配置为准(单位 ms) int -1 corePoolSize 否 单独针对这个服务设置最小活跃线程数,从公用线程池中划分出来 int 0 maxPoolSize 否 单独针对这个服务设置最大活跃线程数,从公用线程池中划分出来 int 0 delayedPublish 否 是否延迟发布 boolean false includeFilters 否 用户可选的自定义过滤器 String[] 空 enableTXC 否 是否开启分布式事务 GTS boolean false serializeType 否 服务接口序列化类型,hessian 或者 java String hessian supportAsynCall 否 是否支持异步调用 String false 表 2. 服务创建及发布限制 名称 示例 限制大小 是否可调整 {服务名}:{版本号} com.alibaba.edas.testcase.api.TestCase:1.0.0 最大192字节 否 组名 aliware 最大32字节 否 一个Pandora应用实例发布的服务数 N/A 最大800个 是,可在应用基本信息页面单击应用设置右侧的设置,并在下拉列表中选择 JVM,然后在弹出的应用设置对话框中选择自定义 > 自定义参数,在输入框中添加 -DCC.pubCountMax=1200属性参数(该参数值可根据应用实际发布的服务数调整) 创建服务消费者。 本示例中,将创建一个服务消费者,通过 HSFConsumer 所提供的 API 接口去调用服务提供者。 创建一个 Maven 工程,命名为 hsf-pandora-boot-consumer。 在 pom.xml 中引入需要的依赖内容。 说明 消费者和提供者的 Maven 依赖是相同。 <java.version>1.8</java.version> <spring-boot.version>2.1.6.RELEASE</spring-boot.version> <pandora-boot.version>2019-06-stable</pandora-boot.version> com.alibaba.boot pandora-hsf-spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import com.taobao.pandora pandora-boot-starter-bom ${pandora-boot.version} pom import org.apache.maven.plugins maven-compiler-plugin 3.7.0 1.8 1.8 com.taobao.pandora pandora-boot-maven-plugin 2.1.11.8 package repackage 将服务提供者所发布的 API 服务接口(包括包名)拷贝到本地,如 com.alibaba.edas.HelloService。 public interface HelloService { String echo(String string); } 通过注解的方式将服务消费者的实例注入到 Spring 的 Context 中。 @Configuration public class HsfConfig { @HSFConsumer(clientTimeout = 3000, serviceVersion = "1.0.0") private EchoService echoService; } 说明 在 HsfConfig 类里配置一次 @HSFConsumer,然后在多处通过 @Autowired 注入使用。通常一个 HSF Consumer 需要在多个地方使用,但并不需要在每次使用的地方都用 @HSFConsumer 来标记。只需要写一个统一的 HsfConfig 类,然后在其它需要使用的地方,直接通过 @Autowired 注入即可。 为了便于测试,使用 SimpleController 来暴露一个 /hsf-echo/* 的 HTTP 接口,/hsf-echo/* 接口内部实现调用了 HSF 服务提供者。 @RestController public class SimpleController { @Autowired private HelloService helloService; @RequestMapping(value = "/hsf-echo/{str}", method = RequestMethod.GET) public String echo(@PathVariable String str) { return helloService.echo(str); } } 在 resources 目录下的 application.properties 文件中配置应用名与监听端口号。 spring.application.name=hsf-pandora-boot-consumer server.port=8080 spring.hsf.version=1.0.0 spring.hsf.timeout=1000 说明 建议将服务版本和服务超时都统一配置在 application.properties 中。 添加服务启动的 main 函数入口。 @SpringBootApplication public class HSFConsumerApplication { public static void main(String[] args) { PandoraBootstrap.run(args); SpringApplication.run(HSFConsumerApplication.class, args); PandoraBootstrap.markStartupAndWait(); } } 表 3. 服务消费者属性列表 属性 是否必配 描述 类型 默认值 serviceGroup 否 服务的组名 String HSF serviceVersion 否 服务的版本号 String 1.0.0.DAILY clientTimeout 否 客户端统一设置接口中所有方法的超时时间(单位 ms) int -1 generic 否 是否支持泛化调用 boolean false addressWaitTime 否 同步等待服务注册中心( ConfigServer )推送服务提供者地址的时间(单位 ms) int 3000 proxyStyle 否 代理方式(JDK 或 Javassist) String jdk futureMethods 否 设置调用此服务时需要采用异步调用的方法名列表以及异步调用的方式,默认为空,即所有方法都采用同步调用 String[] 空 consistent 否 负载均衡是否使用一致性哈希 String 空 methodSpecials 否 配置方法级的超时时间、重试次数、方法名称 com.alibaba.boot.hsf.annotation.HSFConsumer.ConsumerMethodSpecial[] 空 表 4. 服务提供者和消费者全局配置参数列表 属性 是否必配 描述 类型 默认值 spring.hsf.version 否 服务的全局版本号,还可以使用 spring.hsf.versions.<完整的服务接口名>=<单独为该服务接口设置的版本号,String类型>,例如spring.hsf.versions.com.aliware.edas.EchoService="1.0.0"为具体某个服务设置版本号。 String 1.0.0.DAILY spring.hsf.group 否 服务的全局组名,还可以使用spring.hsf.groups.<完整的服务接口名>=<单独为该服务接口设置的组名,String类型>为具体某个服务设置组名。 String HSF spring.hsf.timeout 否 服务的全局超时时间,还可以使用spring.hsf.timeouts.<完整的服务接口名>=<超时时间,String类型>为具体某个服务设置超时时间。 Integer 无 spring.hsf.max-wait-address-time 否 同步等待服务注册中心( ConfigServer )推送服务提供者地址的全局时间(单位 ms ),还可以使用spring.hsf.max-wait-address-times.<完整的服务接口名>=<等待时间,String类型>为具体某个服务设置的等待服务注册中心(ConfigServer)推送服务提供者地址的时间。 Integer 3000 spring.hsf.delay-publish 否 服务延迟发布的全局开关,”true” or “false”,还可以使用spring.hsf.delay-publishes.<完整的服务接口名>=<是否延迟发布,String类型>为具体某个服务设置是否延迟。 String 无 spring.hsf.core-pool-size 否 服务的全局最小活跃线程数,还可以使用spring.hsf.core-pool-sizes.<完整的服务接口名>=<最小活跃线程数,String类型>单独为某服务设置最小活跃线程数。 int 无 spring.hsf.max-pool-size 否 服务的全局最大活跃线程数,还可以使用spring.hsf.max-pool-sizes.<完整的服务接口名>=<最大活跃线程数,String类型>单独为某服务设置最大活跃线程数。 int 无 spring.hsf.serialize-type 否 服务的全局序列化类型,Hessian 或者 Java,还可以使用spring.hsf.serialize-types.<完整的服务接口名>=<序列化类型>单独为某服务设置序列化类型。 String 无 说明 全局配置参数可在 Pandora Boot 应用的 application.properties 文件中设置。 本地开发调试。 配置轻量级配置及注册中心。 本地开发调试时,需要使用轻量级配置及注册中心,轻量级配置及注册中心包含了服务注册发现服务端的轻量版,详情请参见启动轻量级配置及注册中心。 启动应用。 在 IDE 中启动 通过 VM options 配置启动参数 -Djmenv.tbsite.net={$IP},通过 main 方法直接启动。其中 {$IP} 为轻量配置中心的 IP 地址。列如本机启动轻量配置中心,则 {$IP} 为 127.0.0.1。 您也可以不配置 JVM 的参数,而是直接通过修改 hosts 文件将 jmenv.tbsite.net 绑定为轻量配置中心的 IP。详情请参见启动轻量级配置及注册中心。 通过 FatJar 启动 增加 taobao-hsf.sar 依赖,这样会下载到我们需要的依赖:/.m2/com/taobao/pandora/taobao-hsf.sar/2019-06-stable/taobao-hsf.sar-2019-06-stable.jar,在后面的启动参数中依赖它。 com.taobao.pandora taobao-hsf.sar 2019-06-stable 使用 Maven 将 Pandora Boot 工程打包成 FatJar, 需要在 pom.xml 中添加如下插件。为避免与其他打包插件发生冲突,请勿在 build 的 plugin 中添加其他 FatJar 插件。 com.taobao.pandora pandora-boot-maven-plugin 2.1.11.8 package repackage 添加完插件后,在工程的主目录下,执行 maven 命令 mvn clean package 进行打包,即可在 Target 目录下找到打包好的 FatJar 文件。 通过 Java 命令启动应用。 java -Djmenv.tbsite.net=127.0.0.1 -Dpandora.location=${M2_HOME}/.m2/repository/com/taobao/pandora/taobao-hsf.sar/2019-06-stable/taobao-hsf.sar-2019-06-stable.jar -jar hsf-pandora-boot-provider-1.0.jar 说明 -Dpandora.location 指定的路径必须是全路径,使用命令行启动时,必须显示指定 taobao-hsf.sar 的位置。 访问 consumer 所在机器的地址,可以触发 consumer 远程调用 provider。 curl localhost:8080/hsf-echo/helloworld helloworld 单元测试。 Pandora Boot 的单元测试可以通过 PandoraBootRunner 启动,并与 SpringJUnit4ClassRunner 无缝集成。 我们将演示一下如何在服务提供者中进行单元测试,供大家参考。 在 Maven 中添加 Pandora Boot 和 Spring Boot 测试必要的依赖。 com.taobao.pandora pandora-boot-test test org.springframework.boot spring-boot-starter-test test 编写测试类的代码。 @RunWith(PandoraBootRunner.class) @DelegateTo(SpringJUnit4ClassRunner.class) // 加载测试需要的类,一定要加入 Spring Boot 的启动类,其次需要加入本类。 @SpringBootTest(classes = {HSFProviderApplication.class, HelloServiceTest.class }) @Component public class HelloServiceTest { /** * 当使用 @HSFConsumer 时,一定要在 @SpringBootTest 类加载中,加载本类,通过本类来注入对象,否则当做泛化时,会出现类转换异常。 */ @HSFConsumer(generic = true) HelloService helloService; //普通的调用 @Test public void testInvoke() { TestCase.assertEquals("hello world", helloService.echo("hello world")); } //泛化调用 @Test public void testGenericInvoke() { GenericService service = (GenericService) helloService; Object result = service.$invoke("echo", new String[] {"java.lang.String"}, new Object[] {"hello world"}); TestCase.assertEquals("hello world", result); } //返回值 Mock @Test public void testMock() { HelloService mock = Mockito.mock(HelloService.class, AdditionalAnswers.delegatesTo(helloService)); Mockito.when(mock.echo("")).thenReturn("beta"); TestCase.assertEquals("beta", mock.echo("")); } }

1934890530796658 2020-03-27 18:22:24 0 浏览量 回答数 0

问题

配置了却报错说找不到action?报错

爱吃鱼的程序员 2020-06-09 15:06:05 0 浏览量 回答数 1

问题

Percona Server 5.7 安装教程

妙正灰 2019-12-01 21:43:29 1204 浏览量 回答数 1

回答

为了达到事务的四大特性,数据库定义了4种不同的事务隔离级别,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。 SQL 标准定义了四个隔离级别: READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。 READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。 REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。 这里需要注意的是:Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别 事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。 因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容):,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。 InnoDB 存储引擎在 分布式事务 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。

剑曼红尘 2020-03-31 10:59:54 0 浏览量 回答数 0

问题

技术运维问题 - MYSQL使用 -RDS MySQL 5.6 版本GTID特性对临时表限制的处理

李沃晟 2019-12-01 21:42:27 1234 浏览量 回答数 0

问题

null?报错

爱吃鱼的程序员 2020-06-07 17:45:13 0 浏览量 回答数 1

回答

分布式文件系统,无论是 Lustre、GlusterFS、OrangeFS、BeeGFS、XtreemFS 还是之前的 Ceph,都有几个关键需求: 高效的事务 快速的元数据操作 (可能不是通用的)对未来的不向后兼容的存储硬件的支持 因为大部分文件系统按 POSIX 标准实现,因此缺乏事务概念,因此分布式文件系统往往通过 WAL 或者基于文件系统的内部事务机制实现(Lustre)。 无法高效的列举目录内容或者 hanle 海量小文件也是分布式存储使用本地文件系统的一个痛点,为此分布式文件系统就需要通过元数据缓存、哈希、数据库或对本地文件系统打 patch 来解决。 根据硬件供应商的预测,2023 年半数的数据中心将使用 SMR HDD。此外 ZNS SSD 能够通过不提供 FTL 来避免 gc 带来的不可控的延迟。像这种新硬件也是 Ceph 希望支持的。 上图是 Ceph 的大致架构,考虑到 Ceph 架构的介绍文章很多,这里就赘述了,读者可以搜索任一篇 Ceph 架构的介绍文章。 Ceph 的 ObjectStore 第一个实现是一个叫 EBOFS(Extent and B-Tree-based Object File System ) 的用户态文件系统。2018 年 Btrfs 出现,有事务、去重、校验码、透明压缩都特性,因此 EBOFS 被基于 Btrfs 实现的 FileStore 取代。 FileStore 里,一个对象集合会被映射到目录,数据会被存储到文件。一开始对象的属性是被 POSIX 的 xattrs 保存的,但后来被移到了 LevelDB(xattrs 容量有限)。 Btrfs 被用作生产环境后端很多年,这个过程中 Btrfs 一直有不稳定和数据/元数据的 fragmentation 问题,但因为对象接口的不断演进导致已经不太可能退回到 EBOFS 了,因此 FileStore 被移植到过 XFS、ext4、ZFS,最终因为在 XFS 上良好的 scale 和元数据性能而成为 FileStore 的事实标准。 虽然基于 XFS 的 FileStore 已经比较稳定了,但是一直受元数据 fragmentation 和无法充分发挥硬件性能的问题困扰。因为缺乏原生的事务,所以用户态的 WAL 实现使用了完整数据的 journal,并受读取-修改-写入这一过程(read-modify-write workloads )的速度限制——这个正是 Ceph WAL 的典型操作过程。此外,XFS 不是一个 COW 文件系统,快照因为需要克隆操作受此影响就会很慢。 NewStore 是 Ceph 尝试通过基于文件系统解决元数据问题的第一次尝试。NewStore 不再使用目录来代表对象集合,而是用 RocksDB 保存元数据。此外 RocksDB 还用来实现 WAL,使得读取-修改-写入过程可以通过合并数据和元数据日志来加速。 这个方案整体来说就是通过文件保存数据、通过在日志文件系统上运行 RocksDB 来保存元数据。但这个方案带来沉重的一致性负担,最终促使了 BlueStore 的开发。

kun坤 2020-04-23 19:46:29 0 浏览量 回答数 0

回答

X-Engine是阿里云数据库产品事业部自研的联机事务处理OLTP(On-Line Transaction Processing)数据库存储引擎。作为自研数据库POLARDB的存储引擎之一,已经广泛应用在阿里集团内部诸多业务系统中,包括交易历史库、钉钉历史库等核心应用,大幅缩减了业务成本,同时也作为双十一大促的关键数据库技术,挺过了数百倍平时流量的冲击。 为什么设计一个新的存储引擎 X-Engine的诞生是为了应对阿里内部业务的挑战,早在2010年,阿里内部就大规模部署了MySQL数据库,但是业务量的逐年爆炸式增长,数据库面临着极大的挑战: 极高的并发事务处理能力(尤其是双十一的流量突发式暴增)。 超大规模的数据存储。 这两个问题虽然可以通过扩展数据库节点的分布式方案解决,但是堆机器不是一个高效的手段,我们更想用技术的手段将数据库性价比提升到极致,实现以少量资源换取性能大幅提高的目的。 传统数据库架构的性能已经被仔细的研究过,数据库领域的泰斗,图灵奖得主Michael Stonebreaker就此写过一篇论文 《OLTP Through the Looking Glass, and What We Found There》 ,指出传统关系型数据库,仅有不到10%的时间是在做真正有效的数据处理工作,剩下的时间都浪费在其它工作上,例如加锁等待、缓冲管理、日志同步等。 造成这种现象的原因是因为近年来我们所依赖的硬件体系发生了巨大的变化,例如多核(众核)CPU、新的处理器架构(Cache/NUMA)、各种异构计算设备(GPU/FPGA)等,而架构在这些硬件之上的数据库软件却没有太大的改变,例如使用B-Tree索引的固定大小的数据页(Page)、使用ARIES算法的事务处理与数据恢复机制、基于独立锁管理器的并发控制等,这些都是为了慢速磁盘而设计,很难发挥出现有硬件体系应有的性能。 基于以上原因,阿里开发了适合当前硬件体系的存储引擎,即X-Engine。 X-Engine架构 全新架构的X-Engine存储引擎不仅可以无缝对接兼容MySQL(得益于MySQL Pluginable Storage Engine特性),同时X-Engine使用分层存储架构。 因为目标是面向大规模的海量数据存储,提供高并发事务处理能力和降低存储成本,在大部分大数据量场景下,数据被访问的机会是不均等的,访问频繁的热数据实际上占比很少,X-Engine根据数据访问频度的不同将数据划分为多个层次,针对每个层次数据的访问特点,设计对应的存储结构,写入合适的存储设备。 X-Engine使用了LSM-Tree作为分层存储的架构基础,并进行了重新设计: 热数据层和数据更新使用内存存储,通过内存数据库技术(Lock-Free index structure/append only)提高事务处理的性能。 流水线事务处理机制,把事务处理的几个阶段并行起来,极大提升了吞吐。 访问频度低的数据逐渐淘汰或是合并到持久化的存储层次中,并结合多层次的存储设备(NVM/SSD/HDD)进行存储。 对性能影响比较大的Compaction过程做了大量优化: 拆分数据存储粒度,利用数据更新热点较为集中的特征,尽可能的在合并过程中复用数据。 精细化控制LSM的形状,减少I/O和计算代价,有效缓解了合并过程中的空间增大。 同时使用更细粒度的访问控制和缓存机制,优化读的性能。 技术特点 利用FPGA硬件加速Compaction过程,使得系统上限进一步提升。这个技术属首次将硬件加速技术应用到在线事务处理数据库存储引擎中,相关论文 《FPGA-Accelerated Compactions for LSM-based Key Value Store》 已经被2020年的顶级会议FAST'20接收。 通过数据复用技术减少数据合并代价,同时减少缓存淘汰带来的性能抖动。 使用多事务处理队列和流水线处理技术,减少线程上下文切换代价,并计算每个阶段任务量配比,使整个流水线充分流转,极大提升事务处理性能。相对于其他类似架构的存储引擎(例如RocksDB),X-Engine的事务处理性能有10倍以上提升。 X-Engine使用的Copy-on-write技术,避免原地更新数据页,从而对只读数据页面进行编码压缩,相对于传统存储引擎(例如InnoDB),使用X-Engine可以将存储空间降低至10%~50%。 Bloom Filter快速判定数据是否存在,Surf Filter判断范围数据是否存在,Row Cache缓存热点行,加速读取性能。 LSM基本逻辑 LSM的本质是所有写入操作直接以追加的方式写入内存。每次写到一定程度,即冻结为一层(Level),并写入持久化存储。所有写入的行,都以主键(Key)排序好后存放,无论是在内存中,还是持久化存储中。在内存中即为一个排序的内存数据结构(Skiplist、B-Tree、etc),在持久化存储也作为一个只读的全排序持久化存储结构。 普通的存储系统若要支持事务处理,需要加入一个时间维度,为每个事务构造出一个不受并发干扰的独立视域。例如存储引擎会对每个事务定序并赋予一个全局单调递增的事务版本号(SN),每个事务中的记录会存储这个SN以判断独立事务之间的可见性,从而实现事务的隔离机制。 如果LSM存储结构持续写入,不做其他的动作,那么最终会成为如下结构。 这种结构对于写入是非常友好的,只要追加到最新的内存表中即完成,为实现故障恢复,只需记录Redo Log,因为新数据不会覆盖旧版本,追加记录会形成天然的多版本结构。 但是如此累积,冻结的持久化层次越来越多,会对查询会产生不利的影响。例如对同一个key,不同事务提交产生的多版本记录会散落在各个层次中;不同的key也会散落在不同层次中。读操作需要查找各个层并合并才能得到最终结果。 因此LSM引入了Compaction操作解决这个问题,Compaction操作有2种作用: 控制LSM层次形状 一般的LSM形状都是层次越低,数据量越大(倍数关系),目的是为了提升读性能。 通常存储系统的数据访问都有局部性,大量的访问都集中在少部分数据上,这也是缓存系统能有效工作的基本前提。在LSM存储结构中,如果把访问频率高的数据尽可能放在较高的层次上,存放在快速存储设备中(例如NVM、DRAM),而把访问频率低的数据放在较低层次中,存放在廉价慢速存储设备中。这就是X-Engine的冷热分层概念。 合并数据 Compaction操作不断的把相邻层次的数据合并,并写入更低层次。合并的过程实际上是把要合并的相邻两层或多层的数据读出来,按key排序,相同的key如果有多个版本,只保留新的版本(比当前正在执行的活跃事务中最小版本号新),丢掉旧版本数据,然后写入新的层,这个操作非常耗费资源。 合并数据除了考虑冷热分层以外,还需要考虑其他维度,例如数据的更新频率,大量的多版本数据在查询的时候会浪费更多的I/O和CPU,因此需要优先进行合并以减少记录的版本数量。X-Engine综合考虑了各种策略形成自己的Compaction调度机制。 高度优化的LSM X-Engine的memory tables使用了无锁跳表(Locked-free SkipList),并发读写的性能较高。在持久化层如何实现高效,就需要讨论每层的细微结构。 数据组织 X-Engine的每层都划分成固定大小的Extent,存放每个层次中的数据的一个连续片段(Key Range)。为了快速定位Extent,为每层Extents建立了一套索引(Meta Index),所有这些索引,加上所有的memory tables(active/immutable)一起组成了一个元数据树(Metadata Tree),root节点为Metadata Snapshot,这个树结构类似于B-Tree。 X-Engine中除了当前的正在写入的active memory tables以外,其他结构都是只读的,不会被修改。给定某个时间点,例如LSN=1000,上图中的Metadata Snapshot 1引用到的结构即包含了LSN=1000时的所有的数据的快照,因此这个结构被称为Snapshot。 即便是Metadata结构本身,也是一旦生成就不会被修改。所有的读请求都是以Snapshot为入口,这是X-Engine实现Snapshot级别隔离的基础。前文说过随着数据写入,累积数据越多,会执行Compaction操作、冻结memory tables等,这些操作都是用Copy-on-write实现,即每次都将修改产生的结果写入新的Extent,然后生成新的Meta Index结构,最终生成新的Metadata Snapshot。 例如执行一次Compaction操作会生成新的Metadata Snapshot,如下图所示。 可以看到Metadata Snapshot 2相对于Metadata Snapshot 1并没有太多的变化,仅仅修改了发生变更的一些叶子节点和索引节点。 事务处理 得益于LSM的轻量化写机制,写入操作固然是其明显的优势,但是事务处理不只是把更新的数据写入系统那么简单,还要保证ACID(原子性、一致性、隔离性、持久性),涉及到一整套复杂的流程。X-Engine将整个事务处理过程分为两个阶段: 读写阶段 校验事务的冲突(写写冲突、读写冲突),判断事务是否可以执行、回滚重试或者等锁。如果事务冲突校验通过,则把修改的所有数据写入Transaction Buffer。 提交阶段 写WAL、写内存表,以及提交并返回用户结果,这里面既有I/O操作(写日志、返回消息),也有CPU操作(拷贝日志、写内存表)。 为了提高事务处理吞吐,系统内会有大量事务并发执行,单个I/O操作比较昂贵,大部分存储引擎会倾向于聚集一批事务一起提交,称为Group Commit,能够合并I/O操作。但是一组事务提交的过程中,还是有大量等待过程的,例如写入日志到磁盘过程中,除了等待落盘无所事事。 X-Engine为了进一步提升事务处理的吞吐,使用流水线技术,把提交阶段分为4个独立的更精细的阶段: 拷贝日志到缓冲区(Log Buffer) 日志落盘(Log Flush) 写内存表(Write memory table) 提交返回(Commit) 事务到了提交阶段,可以自由选择执行流水线中任意一个阶段,只要流水线任务的大小划分得当,就能充分并行起来,流水线处于接近满载状态。另外这里利用的是事务处理的线程,而非后台线程,每个线程在执行的时候,选择流水线中的一个阶段执行任务,或者空闲后处理其他请求,没有等待,也无需切换,充分利用了每个线程的能力。 读操作 LSM处理多版本数据的方式是新版本数据记录会追加在老版本数据后面,从物理上看,一条记录不同的版本可能存放在不同的层,在查询的时候需要找到合适的版本(根据事务隔离级别定义的可见性规则),一般查询都是查找最新的数据,总是由最高的层次往低层次找。 对于单条记录的查找而言,一旦找到便可以终止,如果记录在比较高的层次,例如memory tables,很快便可以返回;如果记录已经落入了很低的层次,那就得逐层查找,也许Bloom Filter可以跳过某些层次加快这个旅程,但毕竟还是有很多的I/O操作。X-Engine针对单记录查询引入了Row Cache,在所有持久化的层次的数据之上做了一个缓存,在memory tables中没有命中的单行查询,在Row Cache之中也会被捕获。Row Cache需要保证缓存了所有持久化层次中最新版本的记录,而这个记录是可能发生变化的,例如每次flush将只读的memory tables写入持久化层次时,就需要恰当的更新Row Cache中的缓存记录,这个操作比较微妙,需要精心的设计。 对于范围扫描而言,因为没法确定一个范围的key在哪个层次中有数据,只能扫描所有的层次做合并之后才能返回最终的结果。X-Engine采用了一系列的手段,例如SuRF(SIGMOD'18 best paper)提供range scan filter减少扫描层数、异步I/O与预取。 读操作中最核心的是缓存设计,Row Cache负责单行查询,Block Cache负责Row Cache的漏网之鱼,也用来进行范围扫描。由于LSM的Compaction操作会一次更新大量的Data Block,导致Block Cache中大量数据短时间内失效,导致性能的急剧抖动,因此X-Engine做了很多的优化: 减少Compaction的粒度。 减少Compaction过程中改动的数据。 Compaction过程中针对已有的缓存数据做定点更新。 Compaction Compaction操作是比较重要的,需要把相邻层次交叉的Key Range数据读取合并,然后写到新的位置。这是为前面简单的写入操作付出的代价。X-Engine为优化这个操作重新设计了存储结构。 如前文所述,X-Engine将每一层的数据划分为固定大小的Extent,一个Extent相当于一个小而完整的排序字符串表(SSTable),存储了一个层次中的一个连续片段,连续片段又进一步划分为一个个连续的更小的片段Data Block,相当于传统数据库中的Page,只不过Data Block是只读而且不定长的。 回看并对比Metadata Snapshot 1和Metadata Snapshot 2,可以发现Extent的设计意图。每次修改只需要修改少部分有交叠的数据,以及涉及到的Meta Index节点。两个Metadata Snapshot结构实际上共用了大量的数据结构,这被称为数据复用技术(Data Reuse),而Extent大小正是影响数据复用率的关键,Extent作为一个完整的被复用的物理结构,需要尽可能的小,这样与其他Extent数据交叉点会变少,但又不能非常小,否则需要索引过多,管理成本太大。 X-Engine中Compaction的数据复用是非常彻底的,假设选取两个相邻层次(Level1, Level2)中的交叉的Key Range所涵盖的Extents进行合并,合并算法会逐行进行扫描,只要发现任意的物理结构(包括Data Block和Extent)与其他层中的数据没有交叠,则可以进行复用。只不过Extent的复用可以修改Meta Index,而Data Block的复用只能拷贝,即便如此也可以节省大量的CPU。 一个典型的数据复用在Compaction中的过程可以参考下图。 可以看出数据复用的过程是在逐行迭代的过程中完成的,不过这种精细的数据复用带来另一个副作用,即数据的碎片化,所以在实际操作的过程中也需要根据实际情况进行分析。 数据复用不仅给Compaction操作本身带来好处,降低操作过程中的I/O与CPU消耗,更对系统的综合性能产生一系列的影响。例如c、Compaction过程中数据不用完全重写,大大降低了写入时空间的增大;大部分数据保持原样,数据缓存不会因为数据更新而失效,减少合并过程中因缓存失效带来的读性能抖动。 实际上,优化Compaction的过程只是X-Engine工作的一部分,更重要的是优化Compaction调度的策略,选什么样的Extent、定义compaction任务的粒度、执行的优先级等,都会对整个系统性能产生影响,可惜并不存在什么完美的策略,X-Engine积累了一些经验,定义了很多规则,而探索更合理的调度策略是未来一个重要方向。 适用场景 请参见X-Engine最佳实践。 如何使用X-Engine 请参见使用X-Engine引擎。 后续发展 作为MySQL的存储引擎,持续地提升MySQL系统的兼容能力是一个重要目标,后续会根据需求的迫切程度逐步加强原本取消的一些功能,例如外键,以及对一些数据结构、索引类型的支持。 X-Engine作为存储引擎,核心的价值还在于性价比,持续提升性能降低成本,是一个长期的根本目标,X-Engine还在Compaction调度、缓存管理与优化、数据压缩、事务处理等方向上进行深层次的探索。 X-Engine不仅仅局限为一个单机的数据库存储引擎,未来还将作为自研分布式数据库POLARDB分布式版本的核心,提供企业级数据库服务。

游客yl2rjx5yxwcam 2020-03-08 13:24:40 0 浏览量 回答数 0

问题

spring配置自动代理后启动报错 - java报错

montos 2020-05-31 09:08:59 1 浏览量 回答数 1

问题

spring配置自动代理后启动报错403.10 禁止访问:配置无效 

kun坤 2020-05-27 20:05:27 5 浏览量 回答数 1

问题

spring配置自动代理后启动报错:报错

kun坤 2020-06-06 22:32:41 0 浏览量 回答数 1

回答

PostgreSQL是目前最先进的开源数据库,可以支持:多核并行计算FDW 下推join, sort, where clause.snapshot too old检查点平滑fsyncvacuum freeze加速sharding base on fdw分词增强,支持相邻phrases搜索,据说比ES用起来还爽。scale-up 多核增强, 72HT的机器tpc-b select only达到了180万的tps.推出等待事件统计信息支持多副本同步复制,满足金融级可靠性要求聚合复用SFUNC,多个聚合如果INIT和SFUNC一致的话,可以节约非常多的运算开销。事务idle超时机制还有很多,可以在 release notes页面查找https://www.postgresql.org/docs/9.6/static/release-9-6.html除此之外,社区开发的一些特性也很吸引人,例如:rum插件,支持文本相似度查询,效率嘛10亿级别TOKEN,毫秒级响应,比搜索引擎还好用,具体见云栖社区的测试文章。LLVM版本的PostgreSQL,对大数据量的表达式处理性能提升非常明显。也是大数据处理惯用的手法,例如Impala。虽然PostgreSQL的定位是OLTP,但不代表它不能处理OLAP的请求,而且Gartner去年就提出了HTAP的数据库概念,指即能处理TP有能处理AP的数据库产品,PostgreSQL的特性可见一斑。10.0版本已经加入的聚合算子下推,你是不是开始浮想联翩了呢?更多的插件可以到github , pgxn.org , pgfoundry , 以及PostgreSQL生态体系的很多公司的官网等网站查找。

卓刀 2019-12-02 03:09:58 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档实时数据订阅功能旨在帮助用户获取RDS/DRDS的实时增量数据,用户能够根据自身业务需求自由消费增量数据,例如实现缓存更新策略、业务异步解耦、异构数据源数据实时同步及含复杂ETL的数据实时同 步等多种业务场景。 功能列表(1) 支持公共云、金融云RDS For MySQL实例的数据订阅。(2) 支持经典网络、VPC网络下RDS For MySQL实例的数据订阅。 数据源类型实时数据订阅支持的数据源类型包括: RDS For MySQLDRDS 其中,DRDS 不记录事务日志,所以如果需要订阅DRDS的实时增量数据,那么需要通过订阅DRDS底层挂载的RDS实例的增量日志来实现。 订阅对象数据订阅的订阅对象可以为:库、表。用户可以根据需要订阅某几个表的增量数据。 数据订阅将增量数据细分为数据变更(Data Manipulation Language 简称DML)和结构变更(Data Definition Language,简称DDL),配置数据订阅时,可以选择需要订阅的具体数据变更类型。 订阅通道订阅通道是进行增量数据订阅与消费的基本单元。如果要订阅RDS的增量数据,必须在数据传输控制台创建一个针对这个RDS实例的订阅通道。订阅通道会实时拉取RDS的增量数据,并将最新一段时间的增量数据保存在订阅通道中,用户可以使用数据传输提供SDK从这个订阅通道中订阅增量数据,并进行相应的消费。同时,用户可以在数据传输控制台进行订阅通道的创建、管理及删除等操作。一个订阅通道同时只能被一个下游SDK订阅消费,如果用户有多个下游需要订阅同一个RDS实例时,需要创建多个订阅通道。这些订阅通道订阅的RDS实例均为同一个实例ID。 订阅通道在创建及运行过程中,不同阶段会处于不同的状态,具体如下表所示: 通道状态 状态说明 可进行操作 预检中 订阅通道已经完成任务配置,正在进行启动之前的简单预检查 删除订阅 未启动 迁移任务已经通过迁移之前的预检查,但是还没有启动订阅 - 开始订阅- 删除订阅 初始化 订阅通道正在进行启动初始化,一般需要1分钟左右 删除订阅 正常 订阅通道正在正常拉取RDS实例的增量数据 - 查看示例代码- 查看订阅数据- 删除订阅 异常 订阅通道拉取RDS实例增量数据异常 - 查看示例代码- 删除订阅 高级特性数据订阅支持多种特性,有效降低用户使用门槛,主要包括: (1) 动态增减订阅对象, 在数据订阅过程中,用户可以随时增加或减少需要订阅的对象。 (2) 在线查看订阅数据, 数据传输DTS控制台支持在线查看订阅通道中的增量数据。 (3) 修改消费时间点,数据订阅支持用户随时修改需要消费数据对应的时间点。 (4) 完善监控体系, 数据订阅提供订阅通道状态、下游消费延迟的报警监控功能。用户可以根据业务敏感度,自定义消费延迟报警阈值。

2019-12-01 23:09:36 0 浏览量 回答数 0

问题

Redis 4.0、codis 、云数据库 Redis 版集群对比分析

云栖大讲堂 2019-12-01 21:20:41 1050 浏览量 回答数 0

问题

数据传输服务DTS的功能特性(什么是数据订阅?)

云栖大讲堂 2019-12-01 21:23:49 1106 浏览量 回答数 0

回答

没玩过这些,我直接说一下我们公司内部架构的用法把,主要给你讲一下事务 什么叫做事务,不知道你用的是啥数据库,事务就是当前链接下的数据要保持一致性,也就是你上面的所谓的session,我只用Oracle数据库,如果你用过pl/sql的话你每打开一个COMMANDWINDOW他就是一个事务,当前的COMMANDWINDOW做一个数据的增,删,改,如果不提交的话,那么另外一个COMMANDWINDOW里是看不出数据的变化了的,如果需要在另外一个里面看得到数据变化,那么你需要提交事务,使用commit语句,关闭COMMANDWINDOW也就是释放事务 上面的一段配合的只是这么几句代码,我以最简单的JDBC为例 conn=DriverManager.getConnection("jdbc:mysql:///day11","root","root");//获取链接conn.setAutoCommit(false);//开启事务conn.commit();//事务提交conn.rollback();//事务回滚conn.close();//这里是关闭连接 你这里的疑问,我没玩过hibernet,但是大同小异,我以我 公司的内部框架的代码逻辑为例: 如果我是新开启一个事务,也就是你说的 opensession,那么就是新开启一个事务,如果我选择的是获取当前的事务,就是你这边的 getcurrentsession,那么我会做一下判断,当前的线程是否存在事务,如果不存在,我就会新建一个事务,而从你的这个报错看的很清楚,hibernate的获取当前事务的时候,如果不存在当前事务,那么他就直接报错了! ------菜鸟见解,欢迎拍砖,PS:JDBC的事务控制,回答这个问题的时候我才去百度,以前就一直是记JDBC五步操作,到公司直接用内部框架了,就没去认真研究! 不要狭义的理解session就是你想的那个session哈 getcurrentsession当前线程的session为了让pojo从数据库到页面到结束使用出于同一session便于hibernate代理,并添加各种操作,事务等保证状态一致, opensession开启一个新session,没有上述特点 spring其实在后面代理了你的hibernate动作,模板保证每个写操作[你配置的情况下]都有事务控制,保证数据一致性[出现异常,事务回滚] 首先明确一点,关系数据库中的事务,核心配置在DB中的由DBA设置,我们在JAVA层的操作准确的说是事务传播属性 首先说一下关系数据库中的事务特性 事务的 特性(ACID特性) A:原子性(Atomicity)    事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。B:一致性(Consistency)    事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。C:隔离性(Isolation)   一个事务的执行不能被其他事务干扰。D:持续性/永久性(Durability)   一个事务一旦提交,它对数据库中数据的改变就应该是永久性的 然后在事务中存在的问题准确的说是有一些根据不同的隔离级别或业务要求是允许的 1、幻想读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想。2、不可重复读取:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同,这称为不可重复读。3、脏读:事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据,然后T1执行回滚操作,取消刚才的修改,所以T2所读取的行就无效,也就是脏数据。 引用来自“卧枝会中田”的评论 首先明确一点,关系数据库中的事务,核心配置在DB中的由DBA设置,我们在JAVA层的操作准确的说是事务传播属性 首先说一下关系数据库中的事务特性 事务的 特性(ACID特性) A:原子性(Atomicity)    事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。B:一致性(Consistency)    事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。C:隔离性(Isolation)   一个事务的执行不能被其他事务干扰。D:持续性/永久性(Durability)   一个事务一旦提交,它对数据库中数据的改变就应该是永久性的 然后在事务中存在的问题准确的说是有一些根据不同的隔离级别或业务要求是允许的 1、幻想读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想。2、不可重复读取:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同,这称为不可重复读。3、脏读:事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据,然后T1执行回滚操作,取消刚才的修改,所以T2所读取的行就无效,也就是脏数据。

爱吃鱼的程序员 2020-06-12 15:51:30 0 浏览量 回答数 0

问题

(update_non_index/flush_log=0) 响应时间, 95 percentil

kun坤 2020-06-14 13:59:23 0 浏览量 回答数 0

回答

• 有 orm 框架的,就是都不开源,17年底我有参与过一个,本来打算去年自己也撸一个开源版的,想想还是算了,自己辛辛苦苦一年,可能也没什么人用,还不如推广知识了。 • 其实 rxjava 不是特别适合后端开发的,以前没有接触 spring reactor 倒还没觉得有什么,在接触之后,顿时觉得 reactor 太良心,提供了大量新特性。代码设计也更加简洁,细节处理上更加完善,而不是和 rxjava 一样,提的问题更多在注释上提醒大家注意。使用rx(此处指反应式,并非指rxjava)进行编程,就意味着我们要抛弃ThreadLocal的玩法,Rxjava并没有提供一个很好的解决方案,但Spring Reactor给出了,并基于此方案演化出了现在的Spring 的响应式事务处理。 • rx(此处指反应式,并非指rxjava)国外用的很成熟的就数netflix了,一套完整的解决方案。当下reactor-netty真的是做了极大的努力,对架构设计做了极大的调整,新版本下的 reactor-netty 已经做到了性能的大幅优化,rx在使用上的落地请参考我6.6的分享「Java编程方法论 Reactor解读补充」(2019-06-06 我的一些项目开发感悟以及如何将响应式与函数式落地到我们的开发中) 来源:云原生后端社区

Atom 2020-04-25 15:13:18 0 浏览量 回答数 0

回答

原版英文链接:点击这里 作者 | Md Kamaruzzaman 译者 | 无明 策划 | 小智 基础设施:条条道路通云端 对于云厂商来说,2019 年是硕果累累的一年。不仅初创公司在使用云计算,那些很注重安全的“保守派”公司(如政府机构、医疗保健机构、银行、保险公司,甚至是美国五角大楼)也在迁移到云端。这种趋势在 2020 年将会继续,大大小小的公司都将(或者至少有计划)迁移到云端。Gartner 公司最近发布了一个数字: 如果你是一个还在考虑要不要迁移到云端的决策者,不妨重新审视一下你的策略。如果你是一个独立开发者,并且还没使用过云基础设施,那么完全可以在 2020 年尝试一下。很多大型的云厂商(如亚马逊、微软、谷歌)都提供了免费的体验机会。谷歌在这方面做得特别大方,它提供了价值 300 美元的一年免费服务。 策划注:阿里、腾讯、华为等国内云厂商同样有免费云服务试用产品。 云平台:亚马逊领头,其他跟上 作为第一大云厂商,亚马逊在 2019 年可谓风生水起。凭借其丰富的产品组合,亚马逊将把它的优势延续到 2020 年。Canalys 发布的 2019 年第三季度报告指出,大型云厂商(AWS、Azure、GCP)占据 56% 的市场份额,其中 AWS 独享 32.6%。 其他云厂商也在努力缩短与 AWS 之间的差距。微软把主要目标转向了大型企业。最近,微软打败了亚马逊,从美国五角大楼拿到了一个 100 亿美元的大单子。这个单子将提升 Azure 的声誉,同时削弱 AWS 的士气。 谷歌一直在推动 CNCF,实现云计算运维的标准化。谷歌的长期目标是让云迁移变得更容易,方便企业从 AWS 迁移到 GCP。IBM 之前斥资 360 亿美元收购了 RedHat,也想要在云计算市场占有一席之地。 在亚太地区,阿里云市场规模超过了 AWS、Azure 的总和,全球排名第三。中国国内腾讯云等企业的增长势头也十分迅猛。 2020 年将出现更多的并购。当然,很多初创公司将会带来新的想法和创新,例如多云服务。因为竞争激烈,这些公司只能从降价和推出更多的创新产品来获取利润。 容器化:Kubernetes 将会更酷 在容器编排领域,虽然一度出现了“三足鼎立”(Kubernetes、Docker Swarm 和 Mesos),但 Kubernetes 最终脱颖而出,成为绝对的赢家。云是一个分布式系统,而 Kubernetes 是它的 OS(分布式的 Linux)。2019 年北美 KubeCon+CloudNativeCon 大会的参会者达到了 12000 名,比 2018 年增长了 50%。以下是过去 4 年参会人数的增长情况。 在 2020 年,Kubernetes 不仅不会后退,只会变得越来越强,你完全可以把赌注压在 Kubernetes 身上。另外值得一提的是,Migrantis 最近收购了 Docker Enterprise,不过收购数额不详。 几年前,人们张口闭口说的都是 Docker,而现在换成了 Kubernetes。Docker 在它的全盛时期未能盈利,反而在优势渐退几年之后才尝试变现。这再次说明,在现代技术世界,时机就是一切。 软件架构:微服务将成为主流 谷歌趋势表明,微服务架构范式在 2019 年持续增长了一整年。 随着软件行业整体逐步迁移到云端,微服务也将成为占主导地位的架构范式。微服务架构崛起的一个主要原因是它与云原生完美契合,可以实现快速的软件开发。我在之前的一篇博文中解释了微服务架构的基本原则及其优势和劣势。 https://towardsdatascience.com/microservice-architecture-a-brief-overview-and-why-you-should-use-it-in-your-next-project-a17b6e19adfd 我假设现在也存在一种回归到单体架构的趋势,因为在很多情况下,微服务架构有点过头了,而且做好微服务架构设计其实很难。微服务架构有哪些好的实践?在之前的另一篇博文中,我也给出了一些大概,希望对读者有用。 https://towardsdatascience.com/effective-microservices-10-best-practices-c6e4ba0c6ee2 编程语言(整体):Python 将吞噬世界 机器学习、数据分析、数据处理、Web 开发、企业软件开发,甚至是拼接黑洞照片,Python 的影子无处不在。 在著名的编程语言排行榜网站 TIOBE 上,Python 位居最流行编程语言第三位,仅次于 Java 和 C 语言。 更有意思的是,在 2019 年,Python 的流行度翻了一番(从 5% 到 10%)。 Python 的崛起将在 2020 年延续,并缩短与 Java 和 C 语言之间的差距。另一门无所不在的编程语言 JavaScript 正面临下行的风险。为什么 Python 的势头会如此强劲?因为它的入手门槛低,有一个优秀的社区在支持,并受到数据科学家和新生代开发者的喜爱。 编程语言(企业方面):Java 将占主导 之前的 TIOBE 网站截图显示,Java 仍然是一门占主导地位的编程语言,并将在 2020 年继续保持这种地位。JVM 是 Java 的基石,其他编程语言(如 Kotlin、Scala、Clojure、Groovy)也将 JVM 作为运行时。最近,Oracle 修改了 JVM 的许可协议。 新的许可协议意味着使用 Java、Kotlin、Scala 或其他 JVM 编程语言的公司需要向 Oracle 支付大额费用。所幸的是,OpenJDK 让 JVM 继续免费。另外,还有其他一些公司为 JVM 提供企业支持。 因为体积和速度方面的问题,基于 JVM 的编程语言并不适合用在今天的无服务器环境中。Oracle 正在推动 GraalVM 计划,旨在让 Java 变得更加敏捷和快速,让它更适合用在无服务器环境中。因为除了 Java,没有其他编程语言可以提供企业级的稳定性和可靠性,所以 Java 将在 2020 年继续占主导地位。 企业版 Java:Spring 继续发力 曾几何时,在企业开发领域,Spring 和 JavaEE 之间存在着白热化的竞争。但因为 Oracle 在 JavaEE 方面没有作为,在竞争中惨败,这导致了“MicroProfile”计划的形成,并最终促成了 JakartaEE。 虽然所有的政策和活动都是围绕 JavaEE 展开,但 Spring 事实上已经赢得了这场企业 JVM 之争。2020 年,Spring 将成为 JVM 生态系统的头牌。 有两个正在进展中的项目,它们旨在减小 Java 的体积,让它更适合用在无服务器环境中。 其中一个是 Micronaut(https://micronaut.io/)。 另一个是 Quarkus(https://quarkus.io/)。 这两个项目都使用了 GraalVM,它们在 2020 年将会得到 Java 社区更多的关注。 编程语言:后起之秀的突破 2000 年代,编程语言的发展出现了停滞。大多数人认为没有必要再去开发新的编程语言,Java、C 语言、C++、JavaScript 和 Python 已经可以满足所有的需求。但是,谷歌的 Go 语言为新编程语言大门打开了一扇大门。在过去十年出现了很多有趣的编程语言,比如 Rust、Swift、Kotlin、TypeScript。导致这种情况的一个主要原因是已有的编程语言无法充分利用硬件优势(例如多核、更快的网络、云)。另一个原因是现代编程语言更加关注开发者经济,即实现更快速更容易的开发。在 Stackoverflow 提供的一份开发者报告中,排名靠前的现代编程语言如下所示(Rust 连续 4 年名列第一)。 在之前的一篇博文中,我深入探讨了现代编程语言,对比 Rust 和 Go 语言,并说明了为什么现在是采用这些语言的好时机。 https://towardsdatascience.com/back-to-the-metal-top-3-programming-language-to-develop-big-data-frameworks-in-2019-69a44a36a842 最近,微软宣布他们在探索使用 Rust 来开发更安全的软件。 亚马逊最近也宣布要赞助 Rust。 谷歌宣布将 Kotlin 作为 Android 官方开发语言,所以,在 JVM 领域,Kotlin 成了 Java 的主要竞争对手。 Angular 使用 TypeScript 代替 JavaScript,将其作为主要的编程语言,其他 JavaScript 框架(如 React 和 Vue)也开始为 TypeScript 提供更多的支持。 这种趋势将在 2020 年延续下去,很多巨头公司将会深入了解新一代编程语言(如 Rust、Swift、TypeScript、Kotlin),它们会站出来公开表示支持。 Web:JavaScript 继续占主导地位 曾几何时,JavaScript 并不被认为是一门强大的编程语言。在当时,前端内容主要通过后端框架在服务器端进行渲染。2014 年,AngularJS 的出现改变了这种局面。从那个时候开始,更多的 JavaScript 框架开始涌现(Angular 2+、React、Vue、Meteor),JavaScript 已然成为主流的 Web 开发语言。随着 JavaScript 框架不断创新以及微服务架构的崛起,JavaScript 框架在 2020 年将继续主导前端开发。 JavaScript 框架:React 闪耀 虽然 React 是在 AngularJS 之后出现的,但在过去十年对 Web 开发产生了巨大的影响,这也让 Facebook 在与 Google+ 的竞争中打了一场胜战。React 为前端开发带来了一些新的想法,比如事件溯源、虚拟 DOM、单向数据绑定、基于组件的开发,等等。它对开发者社区产生了重大影响,以至于谷歌放弃了 AngularJS,并借鉴 React 的想法推出了彻底重写的 Angular 2+。React 是目前为止最为流行的 JavaScript 框架,下图显示了相关的 NPM 下载统计信息。 为了获得更好的并发和用户体验,Facebook 宣布完全重写 React 的核心算法,推出了 React-Fiber 项目。 2020 年,React 仍然是你开发新项目的首选 Web 框架。其他框架(如 Angular/Angular 2+ 或 Vue)呢?Angular 仍然是一个不错的 Web 开发框架,特别适合企业开发。我敢肯定谷歌在未来几年会在 Angular 上加大投入。Vue 是另一个非常流行的 Web 框架,由中国的巨头公司阿里巴巴提供支持。如果你已经在使用 Angular 或 Vue,就没必要再迁移到 React 了。 App 开发:原生应用 在移动 App 开发方面,有关混合应用开发的炒作有所消停。混合开发提供了更快的开发速度,因为只需要一个开发团队,而不是多个。但原生应用提供了更好的用户体验和性能。另外,混合应用需要经过调整才能使用一些高级特性。对于企业来说,原生应用仍然是首选的解决方案,这种趋势将在 2020 年延续。Airbnb 在一篇博文中非常详细地说明了为什么他们要放弃混合应用开发平台 React Native。 https://medium.com/airbnb-engineering/sunsetting-react-native-1868ba28e30a 尽管 Facebook 尝试改进 React Native,谷歌也非常努力地推动混合 App 开发平台 Flutter,但它们仍然只适合用于原型、POC、MVP 或轻量级应用的开发。所以,原生应用在 2020 年仍将继续占主导地位。 在原生应用开发方面,谷歌和苹果分别将 Kotlin 和 Swift 作为各自平台主要的编程语言。谷歌最近再次重申了对 Kotlin 的支持,这对于 Kotlin 用户来说无疑是个好消息。 混合应用开发:React Native 在很多情况下,混合应用是个不错的选择。在这方面也有很多选择:Xamarin、Inoic、React Native 和 Flutter。Facebook 基于成熟的 React 框架推出了 React Native。就像 React 在 Web 框架领域占据主导地位一样,React Native 在混合应用领域也占据着主导地位,如下图所示。 React Native 和 React 有共同的基因,都提供了高度的代码重用性以及“一次开发,到处运行”的能力。React Native 的另一个优势是 Facebook 本身也用它来开发移动应用。谷歌在这个领域起步较晚,但在去年,谷歌的混合应用开发框架 Flutter 获得了不少关注。Flutter 提供了更好的性能,但需要使用另一门不是那么流行的编程语言 Dart。React Native 在 2020 年将继续占主导地位。 API:REST 将占主导地位 REST 是 API 领域事实上的标准,被广泛用在基于 API 的服务间通信上。当然,除了 REST,我们还有其他选择,比如来自谷歌的 gRPC 和来自 Facebook 的 GraphQL。 它们提供了不同的能力。谷歌开发的 gRPC 作为远程过程调用(如 SOAP)的化身,使用 Protobuf 代替 JSON 作为消息格式。Facebook 开发的 GraphQL 作为一个集成层,避免频繁的 REST 调用。gRPC 和 GraphQL 都在各自的领域取得了成功。2020 年,REST 仍然是占主导地位的 API 技术,而 GraphQL 和 gRPC 将作为补充技术。 人工智能:Tensorflow 2.0 将占主导地位 谷歌和 Facebook 也是深度学习 / 神经网络领域的主要玩家。谷歌基于深度学习框架 Theano 推出了 TensorFlow,它很快就成为深度学习 / 神经网络的主要开发库。谷歌还推出了特别设计的 GPU(TPU)来加速 TensorFlow 的计算。 Facebook 在深度学习领域也不甘落后,他们拥有世界上最大的图像和视频数据集合。Facebook 基于另一个深度学习库 Torch 推出了深度学习库 PyTorch。TensorFlow 和 PyTorch 之间有一些区别,前者使用的是静态图进行计算,而 PyTorch 使用的是动态图。使用动态图的好处是可以在运行时纠正自己。另外,PyTorch 对 Python 支持更好,而 Python 是数据科学领域的一门主要编程语言。 随着 PyTorch 变得越来越流行,谷歌也赶紧在 2019 年 10 月推出了 TensorFlow 2.0,也使用了动态图,对 Python 的支持也更好。 2020 年,TensorFlow 2.0 和 PyTorch 将齐头并进。考虑到 TensorFlow 拥有更大的社区,我估计 TensorFlow 2.0 将成为占主导地位的深度学习库。 数据库:SQL是王者,分布式SQL是王后 在炒作 NoSQL 的日子里,人们嘲笑 SQL,还指出了 SQL 的种种不足。有很多文章说 NoSQL 有多么的好,并将要取代 SQL。但等到炒作的潮水褪去,人们很快就意识到,我们的世界不能没有 SQL。以下是最流行的数据库的排名。 可以看到,SQL 数据库占据了前四名。SQL 之所以占主导地位,是因为它提供了 ACID 事务保证,而 ACID 是业务系统最潜在的需求。NoSQL 数据库提供了横向伸缩能力,但代价是不提供 ACID 保证。 互联网公司一直在寻找“大师级数据库”,也就是既能提供 ACID 保证又能像 NoSQL 那样可横向伸缩的数据库。目前有两个解决方案可以部分满足对“大师级数据库”的要求,一个是亚马逊的 Aurora,一个是谷歌的 Spanner。Aurora 提供了几乎所有的 SQL 功能,但不支持横向写伸缩,而 Spanner 提供了横向写伸缩能力,但对 SQL 支持得不好。 2020 年,但愿这两个数据库能够越走越近,或者有人会带来一个“分布式 SQL”数据库。如果真有人做到了,那一定要给他颁发图灵奖。 数据湖:MinIO 将要崛起 现代数据平台非常的复杂。企业一般都会有支持 ACID 事务的 OLTP 数据库(SQL),也会有用于数据分析的 OLAP 数据库(NoSQL)。除此之外,它们还有其他各种数据存储系统,比如用于搜索的 Solr、ElasticSearch,用于计算的 Spark。企业基于数据库构建自己的数据平台,将 OLTP 数据库的数据拷贝到数据湖中。各种类型的数据应用程序(比如 OLAP、搜索)将数据湖作为它们的事实来源。 HDFS 原本是事实上的数据湖,直到亚马逊推出了对象存储 S3。S3 可伸缩,价格便宜,很快就成为很多公司事实上的数据湖。使用 S3 唯一的问题是数据平台被紧紧地绑定在亚马逊的 AWS 云平台上。虽然微软 Azure 推出了 Blob Storage,谷歌也有类似的对象存储,但都不是 S3 的对手。 对于很多公司来说,MinIO 或许是它们的救星。MinIO 是一个开源的对象存储,与 S3 兼容,提供了企业级的支持,并专门为云原生环境而构建,提供了与云无关的数据湖。 微软在 Azure Marketplace 是这么描述 MinIO 的:“为 Azure Blog Storage 服务提供与亚马逊 S3 API 兼容的数据访问”。如果谷歌 GCP 和其他云厂商也提供 MinIO,那么我们将会向多云迈出一大步。 大数据批处理:Spark 将继续闪耀 现如今,企业通常需要基于大规模数据执行计算,所以需要分布式的批处理作业。Hadoop 的 Map-Reduce 是第一个分布式批处理平台,后来 Spark 取代了 Hadoop 的地位,成为真正的批处理之王。Spark 是怎样提供了比 Hadoop 更好的性能的?我之前写了另一篇文章,对现代数据平台进行了深入分析。 https://towardsdatascience.com/programming-language-that-rules-the-data-intensive-big-data-fast-data-frameworks-6cd7d5f754b0 Spark 解决了 Hadoop Map-Reduce 的痛点,它将所有东西放在内存中,而不是在完成每一个昂贵的操作之后把数据保存在存储系统中。尽管 Spark 重度使用 CPU 和 JVM 来执行批处理作业,但这并不妨碍它成为 2020 年批处理框架之王。我希望有人能够使用 Rust 开发出一个更加高效的批处理框架,取代 Spark,并为企业省下大量的云资源费用。 大数据流式处理:Flink 是未来 几年前,实现实时的流式处理几乎是不可能的事情。一些微批次处理框架(比如 Spark Streaming)可以提供“几近”实时的流式处理能力。不过,Flink 改变了这一状况,它提供了实时的流式处理能力。 2019 年之前,Flink 未能得到足够的关注,因为它无法撼动 Spark。直到 2019 年 1 月份,中国巨头公司阿里巴巴收购了 Data Artisan(Flink 背后的公司)。 在 2020 年,企业如果想要进行实时流式处理,Flink 应该是不二之选。不过,跟 Spark 一样,Flink 同样重度依赖 CPU 和 JVM,并且需要使用大量的云资源。 字节码:WebAssembly将被广泛采用 我从 JavaScript 作者 Brandon Eich 的一次访谈中知道了 WebAssembly 这个东西。现代 JavaScript(ES5 之后的版本)是一门优秀的编程语言,但与其他编程语言一样,都有自己的局限性。最大的局限性是 JavaScript 引擎在执行 JavaScript 时需要读取、解析和处理“抽象语法树”。另一个问题是 JavaScript 的单线程模型无法充分利用现代硬件(如多核 CPU 或 GPU)。正因为这些原因,很多计算密集型的应用程序(如游戏、3D 图像)无法运行在浏览器中。 一些公司(由 Mozilla 带领)开发了 WebAssembly,一种底层字节码格式,让任何一门编程语言都可以在浏览器中运行。目前发布的 WebAssembly 版本可以支持 C++、Rust 等。 WebAssembly 让计算密集型应用程序(比如游戏和 AutoCAD)可以在浏览器中运行。不过,WebAssembly 的目标不仅限于此,它还要让应用程序可以在浏览器之外运行。WebAssembly 可以被用在以下这些“浏览器外”的场景中。 移动设备上的混合原生应用。没有冷启动问题的无服务器计算。在服务器端执行不受信任的代码。 我预测,2020 年将是 WebAssembly 取得突破的一年,很多巨头公司(包括云厂商)和社区将会拥抱 WebAssembly。 代码:低代码 / 无代码将更进一步 快速的数字化和工业 4.0 革命意味着软件开发者的供需缺口巨大。由于缺乏开发人员,很多企业无法实现它们的想法。为了降低进入软件开发的门槛,可以尝试无代码(No Code)或低代码(Low Code)软件开发,也就是所谓的 LCNC(Low-Code No-Code)。它已经在 2019 年取得了一些成功。 LCNC 的目标是让没有编程经验的人也能开发软件,只要他们想要实现自己的想法。 虽然我对在正式环境中使用 LCNC 框架仍然心存疑虑,但它为其他公司奠定了良好的基础,像亚马逊和谷歌这样的公司可以基于这个基础构建出有用的产品,就像 AWS Lambda 的蓬勃发展是以谷歌 App Engine 为基础。 2020 年,LCNC 将会获得更多关注。

茶什i 2019-12-26 11:57:03 0 浏览量 回答数 0

问题

使用IBPP在C++中操作FireBird/Interbase数据库:报错

kun坤 2020-06-06 13:49:18 0 浏览量 回答数 1
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 云栖号物联网 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 云栖号弹性计算 阿里云云栖号 云栖号案例 云栖号直播