分类: 默认

  • 升级maven项目到Java 11

    升级maven插件

    升级的第一个重点就是maven插件需要升级到最新版本,因为大部分项目还是在Java 8状态,而Java 9新增了Jigsaw,还有部分API的废弃,所以大部分maven插件都有相应的支持调整。所以插件版本是第一个需要升级的。

    如果使用的插件比较多,可以使用versions-maven-plugin来检查可用的升级版本。

    <plugin<groupIdorg.codehaus.mojo</groupId<artifactIdversions-maven-plugin</artifactId<version2.7</version<configuration<generateBackupPomsfalse</generateBackupPoms</configuration</plugin

    执行mvn versions:display-plugin-updates

    升级完成之后需要修改编译使用的版本,之前的maven-compiler-plugin需要指定source和target参数,现在只需要release参数就行了

    <plugin<groupIdorg.apache.maven.plugins</groupId<artifactIdmaven-compiler-plugin</artifactId<version3.8.0</version<configuration<release11</release</configuration</plugin

    另外由于JDK的升级,当有setAccessible(true)调用的时候会有warning消息

    WARNING: Please consider reporting this to the

  • 清理Docker占用的空间

    平时经常在自己的电脑上运行Docker,有时候是快速试用新东西,有时候是搭一个环境用一下,都不是长期使用的。久而久之Docker占用的空间越来越大。

    网上有很多清理的脚本,可以清理的无非是以下几样:

    • 关闭的没有运行的容器
    • 没有tag的镜像
    • 没有tag的数据卷

    相关的命令网上也有,可以存储下来做成一个简单的命令。

    还有一个方法就是用docker-gc镜像,命令如下:

    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /etc:/etc spotify/docker-gc

  • 仿真系统概述

    文章首发于阿里云开发者社区(https://developer.aliyun.com/article/717213),修改后发布于本博客

    什么是系统

    讨论仿真系统之前我们需要明确什么是系统,这个概念可以帮助我们理解边界和范围。

    那么什么是系统?

    德谟克利特的著作《世界大系统》有一段关于系统的阐述:

    任何事物都是在联系中显现出来的,都是在系统中存在的,系统联系规定了每一个事物,而每一个事物又能反映系统的联系的总貌。

    中国著名学者钱学森的观点是:

    系统是由相互作用相互依赖的若干组成部分结合而成的,具有特定功能的有机整体,而且这个有机整体又是它从属的更大系统的组成部分。

    词典对于系统的解释是:

    组成一个复杂整体的一组互相作用、互相联系或者依存的事物。

    用一个汽车总装线来举例,各种零部件通过传送设备(履带或者其他设备),再有工人(或者是机械手臂)按照顺序组装。在这个系统中,工人,机械手臂,零部件相互作用。履带的速度影响零部件的到达,进而影响装配,流水线自身的划分和设计又影响了整体效率。

    从上面这个例子可以感受到我们看系统的时候有两个重要的点:

    一是边界,即确认需要研究事物范围,比如货币的供应量从某种程度上也可能对流水线有影响,但是我们并不会考虑它。

    二是抽象,针对研究内容的不同,需要考虑的事物的详细程度也是不同的,比如机械手臂的出产公司虽然也是一种外部输入,但是会被统一抽象为机械手臂,对于其的特征建模也可以按照平均来计算。

    还有一种更通用的描述系统的方式,即三要素,分别为实体,属性和活动。实体确定了系统构成,属性描述了实体特征,而活动描述了系统内部的相互作用。

    什么是仿真

    仿真一般是指对现实中的系统进行模仿,观测并产生人造过程记录的过程。

    仿真最早用于水利研究,逐渐用于航空、航天和原子能技术等领域。后来随着计算机技术的大力发展,扩展到各行各业。

    针对互联网公司,特别是线上线下融合较深的业务,由于线上试错成本高,反馈周期慢,通过仿真可以很好服务以下几点:

    • 业务形式新,基本没有可以参考的模型或者参数,加上缺少学术上的积累,仿真可以加速研究一个业务场景中复杂系统间的相互影响。
    • 仿真由于是对真实系统的模仿,所以速度和外部参数是可以调整,且对真实系统无影响,可以快速安全进行实验或者验证,加深对于系统行为的理解。
    • 仿真模型和实验的产出可能成为新知识的来源,用于优化业务。

    仿真系统的构建方法

    构建仿真系统流程如下:

    系统建模

    离散or连续

    系统可以是离散,也可以是连续的。当然对于现实中的大多数系统,这两种变化都是共存的,一般我们取其中占多数的为准。

    大部分自然系统都是连续系统,比如湖面的水位,由于降雨,自然蒸发等处于一个时刻变化的状态,而离散系统一般只在离散时间点发生变化的系统,绝对部分人造系统都属于离散系统。

    除了特别的需要以外,大部分系统设计上都会做成离散系统,因为连续系统可以通过引入采样装置转为离散系统,比如上面提到的湖泊系统,就可以通过引入定时采样水质,水位等的装置让系统变成离散系统以方便处理。

    确定核心要素

    需要明确系统中的实体(包括属性),事件,活动。

    我们以外卖配送来看,实体即骑手,顾客,商家,属性可能包括骑手速度,顾客位置,商家位置等,属性可以是从真实系统中获得,也可以是统计上的数据。

    事件主要是对于整个配送有重要影响的,点外卖的时候有一些外卖APP会有进度提示,比如商家接单,商家出餐,骑手抢单,骑手送餐,送达顾客处等,当然这些只是展示出来的事件,系统内部可能更复杂,还有更多事件,确认核心要素的时候一般需要业务专家或者领域专家。

    大部分系统单单靠事件就可以驱动了,但是有时候还需要明确活动。

    一般两个相邻且有先后顺序的事件,如果从逻辑上导致了状态的转移,那可以化为一个活动。比如外卖配送中从待取餐状态转移配送中状态,其实暗含了到店和取餐两个事件。活动并不是必须的,如果研究目的不涉及可以不关注。

    确定仿真算法

    目前有四种成熟仿真算法:

    1. 事件调度
  • 对Serverless的一点理解和思考

    对Serverless的一点理解和思考

    本文首发于阿里云云栖社区,修改后发于本博客。原链接:https://yq.aliyun.com/articles/714659

    什么是Serverless

    技术圈新鲜的词汇和概念层出不同,有些是新的理念,有些是新瓶装旧酒,还有就是已经广泛应用了但是最近才理论抽象化的。

    那么Serverless是什么?

    Serverless还真算不上一个全新的词汇。从字面上看就是无服务器的意思,最早的时候就是单纯指不需要服务器端的软件,绝大部分本地软件都属于这个范畴。

    到了云时代,这个词就囊括了不需要关心服务器的相关技术和服务,比如使用了LeanCloud作为数据库,使用了Auth0作为用户认证服务等。此类服务对于使用者而言屏蔽了服务器等概念,一般也称为Baas(Backend as a Service)。Baas更偏向于服务外包,因为不管是服务器还是内在代码本身都是不透明的,使用者也无法感知。

    再进一步,Faas(Function as a service)出现了,即函数服务/函数计算。这里的函数就是一个代码块,这个代码块没有明确的定义,但是在实际使用了为了响应速度,这个代码块的冷启动时间必须在毫秒级。

    这样就可以在只有需要的时候才调用,做到按需运行,按量扣费。结合云服务商的其他服务,实现多种方式驱动和调度,做到真正的无服务化。当然这里的无服务化只是针对使用方而言的。

    实现这个的本质其实是将一部分或者说一大部分控制都托付给了云服务商。Faas让开发者专注于业务逻辑本身,实际上也只有业务代码本身是开发者受控制,其运行环境,预热时间,缓存机制等都不再受控。

    所以说Faas是Serverless的一种,而且CNCF也将提供Faas和Baas中一种或两种的服务商算作Serverless服务商。但是因为Faas的变革性更大,目前很多场合基本混用Serverless和Faas两者。

    所以本文接下来讨论的Serverless专指Faas,中文也有函数计算,云函数,无服务器计算等称呼。

    Serverless的服务商绑定问题

    对于公有云平台的任何技术,使用者的主要顾虑就是单一服务商绑定。

    因为一旦绑定,将造成数据和业务迁移困难,后续发展可能缺乏选择。还需要考虑云平台出现故障的情况,是否有异构容灾能力,是否会对业务造成不可逆的影响等。

    虽然乍一看,因为业务代码是受控的,且不依赖特定环境,Faas似乎不像Baas那样有绑定问题,但是仔细看Serverless的使用范围不光受代码语言影响,更重要的是驱动的事件。

    对于部署的函数,最终都需要使用云服务商提供的事件来驱动。

    来看下使用Serverless的简要步骤:

    1. 编写函数,并发布到云
    2. 声明事件触发器,由事件触发器触发函数
    3. 云服务商的基础设施监控事件触发器,在触发时分配必要的资源和运行环境给对应的函数,执行函数

    云服务商提供的事件类型越丰富,Serverless的适用面越广。比较通用的事件是HTTP调用和定时调度,其他大部分都是云服务商独有的,所以Serverless是存在较大绑定性的。

    Serverless的服务提供者

    从Amazon在2014推出Lambda至今已有5年,各大云服务商基本都是陆续跟进提供了Serverless服务。

    主流大玩家们包括:AWS Lambda,Azure Functions,Cloud Functions,国内阿里云,腾讯云,华为云等都提供类似服务。

    还有一派自然是开源类型的,需要自建Serverless平台,包括:IBM OpenWhisk,kubeless,knative等。

    云服务商中对于语言的支持基本类似,包括主流的Java,Python,Nodejs,AWS Lambda还支持C#,Ruby,Go等,应该是支持语言中最多的。

    事件类型方面是云服务商强绑定的,比如阿里云支持OSS事件触发器,HTTP 触发器,定时触发器,MNS …

  • MQ延迟消息

    在各类业务中有一种很常见的要求就是在XX小时之后,执行XX。

    简单常用一点的就是用户点了外卖取餐以后24小时内可以给骑手/商家评价,超时不可评价且修改评价为X星。

    简单粗暴的办法肯定是来一个定时任务,扫描为评价的且超过评价时间的数据,并修改相关值。

    这个方法很直接,主要的缺陷如下:

    • 实效性低
    • 效率低

    实效性主要是定时任务执行间隔,这个主要看任务每次运行的间隔是多少。效率问题主要是扫表引起的,特别是数据量较大的时候,加上查询条件复杂,那速度和效率肯定是上不来的。

    比较方便的方案是把延迟这个事情本身让外部控制,比如MQ,发送一个延迟MQ消息,在XX小时过后消费即可。

    开源RocketMQ

    RocketMQ的开源版本提供了延迟消息,但是它的延迟消息并不是任意精度的,而是所谓的延迟时间级别,具体时间是可以配置的,默认配置是

    public class MessageStoreConfig {
    
        private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
        
    }

    具体实现可以参考文末的链接。如果这种模式是可以满足业务的,其实也是可以的。

    阿里云RocketMQ

    如果实在需要精确的延迟控制,目前没有合适的开源版本可用。阿里云的收费RocketMQ是支持秒级别的任意时间延迟。…

  • 数据库主键的生成和处理

    数据库主键的生成和处理

    数据库主键的作用是唯一标识一条记录,所以在同一张表中,任意一条记录的主键都是唯一的。如果没有唯一的主键,数据库就无法根据主键直接定位记录。

    在各种流行的数据库中都存在主键这个概念,一般在建表的时候就需要指定主键,不过不同的数据库有不同语法而已

    MySQL

    CREATE TABLE People
    (
     Id_P int NOT NULL,
     PRIMARY KEY (Id_P)
    )

    Oracle

    CREATE TABLE People
    (
      Id_P int NOT NULL PRIMARY KEY
    )

    对于数据库来说,主键是可以修改的,只要不和保证唯一性即可。但是对于一般应用来说修改主键通常会引起很多问题。比如表A的主键,作为外键在表B中。

    主键策略

    主键的使用可以考虑两个大方向:整数或者字符串。

    先来看看整数,无非两个选项

    • 数据库自增
    • 自己生成

    数据库自增是数据库提供的功能,稳定性可靠性高,自增主键的主要问题是在于把公司业务的关键运营数据完全暴露给了外部,可能导致信息泄露或者潜在的攻击。

    虽然相关配置是可以变更的,比如MySQL可以自定义auto_increment_offset和auto_increment_increment,但是这个始终治标不治本。

    自己生成的话常见的算法有Snowflake,美团开源的leaf也是容易上手的一个选项。

    Snowflake算法是为了分布式ID生成的,用于数据库主键对于唯一性的保证不难,且本身不想自增长ID那么容易暴露业务信息。

    如果使用字符串呢?

    为了保证唯一性,最简单的手段就是UUID,当然字符串的随机性由于数据库索引的结构,可能影响插入性能。这个简单一点的方案就是在前面再加时间戳。GUID也是类似。

    其他选择

  • 一个好的定时任务

    一个好的定时任务

    定时任务在各类的系统中很常见。

    以下是平时比较常接触到各类场景:

    1. 定时发送邮件/消息
    2. 周期行生成报表数据
    3. 定时数据同步
    4. 定时业务补偿,比如失败流程重新启动,超时流程自动关闭等

    而大部分定时任务在运行上都比较偏向于低峰期,白天开始是高峰期,晚上又是发版期,在加上业务的要求,比如每天凌晨产出前一日的XX指标等,大量任务都是每天0~8点运行,这就极大增加了值班成本,出问题很难第一时间解决问题。

    所以写一个好的定时任务,一方面减少线上问题的发生,另一方面也加快了解决问题的速度。

    个人理解对于定时任务,“好”的标准应该是以下几个方面:

    1. 时间
    2. 执行成功率
    3. 通知和监控
    4. 处理异常

    时间

    对于时间有预估,超时报警,发现性能问题
    这里的时间首先是最长执行耗时,当然对于耗时特别短的情况,也要有报警,避免异常结束。

    执行成功率

    外部依赖前置检测,比如关键外部依赖数据源,必须预先查询数据是否就绪。
    对于外部接口如果幂等,可以增加调用重试机制,以降低失败概率
    如果对于批量处理,可以接受少量失败的,那就可以做好异常隔离,避免某一条数据失败,造成整个任务失败。
    另外支持指定参数,这个主要是针对一些特殊情况,包括修复数据,或者线上测试使用。

    通知和监控

    通知首先异常要杜绝漏报。其次就是关键指标的监控,可以使用

    1. 绝对值合理范围区间;
    2. 数据分布合理范围区间;
    3. 同环比变更合理范围区间;

    处理异常

    提供异常挂牌预案
    异常之后任务应该可以重跑,至少做到以下几点:

    1. 幂等
    2. 数据回退
    3. 一键执行
    4. 对外透明
  • 点评Cat 3.0快速上手

    CAT 是基于 Java 开发的实时应用监控平台,为美团点评提供了全面的实时监控告警服务。相比于普通APM平台,主要优势在于了日志告警,多种client和实时性。

    服务端

    CAT从2015年开源,最新的大版本是3.0,同时提供了相关的client包也发布到了仓库不再需要用户自己打包了。

    CAT的部署算不上简单,要快速实验的话最好还是使用Docker镜像的方式来启动。最小依赖就是CAT自身外加一个MySQL数据库,当然这种单机模型是谈不上什么高可用的,只是简单的使用和集成调试。

    由于官方没有提供镜像,我自己打包了一个放在dockerhub上,如果使用国内镜像应该速度也还行。

    执行以下命令

    wget https://raw.githubusercontent.com/htynkn/dockerfiles/master/dianping-cat/stack.yml
    
    wget https://raw.githubusercontent.com/htynkn/dockerfiles/master/dianping-cat/V1__initCatDatabase.sql
    
    docker-compose -f stack.yml up

    由于CAT的数据库需要先初始化,所以使用了flyway作为数据库版本管理工具。最好新建一个文件夹,然后在其中执行,不然容易混入其他SQL文件。

    启动后,注意查看端口,2280端口是CAT上报的端口,必须强绑定,8080那个则会使用随机端口,注意查看。直接访问 localhost:{port}/cat 就行了。

    客户端

    如果要测试client链接的效果,首先在/data/appdatas/cat/目录下新建client.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
        <servers>
            <server ip="127.0.0.1" port="2280" http-port="你的端口" />
        </servers>
    </config>

    然后在你要接入的项目中写入应用名称 src/main/resources/META-INF/app.properties

    app.name={appkey}
  • Apache Dubbo使用Nacos作为注册中心

    Nacos是阿里开源的用于发现、配置和管理微服务的基础设施。目前迭代到1.0版本了。

    Apache Dubbo从2.7.1版本开始提供使用Nacos作为注册中心的功能,如果之前使用的zookeeper作为注册中心,需要以下几步切换以下。

    首先添加新的依赖

    compile 'org.apache.dubbo:dubbo-registry-nacos:2.7.1'
    compile 'com.alibaba.nacos:nacos-client:1.0.0'

    这里解释一下,因为Apache Dubbo 2.7.1版本构建的时候没有把dubbo-registry-nacos打到all-in-one的包中,这里只有手动处理一下。而2.7.1依赖的是nacos-client不是最新版,这里也升级到最新版。

    然后更新注册中心配置,这里用Docker启动一个单机版的Nacos。

    dubbo.registry.address=nacos://localhost:8848

    然后在Nacos中就可以看到服务和元信息了

  • Elasticsearch的游标查询

    在做大批量查询的时候,比如批量导出数据的时候可以使用游标(scroll)查询,单纯的setFrom分页的方式在数据量变大以后性能下降。

    用游标可以用来对 Elasticsearch 有效地执行大批量的文档查询,而又不用付出深度分页那种代价。

    具体的时候很简单就是需要维持一个scrollId,也就是首次查询以后就会获得一个scrollId,然后后面的查询传递这个scrollId就可以查询下一批数据。

    游标查询的本质其实就是缓存了一个查询结果,然后分批返回,scrollId用base64解码可以查看,本质上对应了缓存的结果。

    既然用到了缓存那肯定存在缓存管理的问题,这里有两个点

    1. 所有游标查询都需要设置一个过期时间,超过过期时间以后的查询会报错。这里的过期时间在每次请求之后会延长,所以这里的过期时间是每批次的过期时间,而不是整个查询集合的时间
    2. 到了过期时间就会自动过期,释放空间,如果要提前释放可以主动调用ClearScrollRequest

    如果缓存有效时间设置的过长,且没有回收,容易导致整个集群出现空间,所以这个值最好精确设置。

    在当前场景(批量导出数据)下其实请求是连续的,只需要设置一个比较小的值,考虑本身的响应时间和可能的网络问题,根据具体场景1s~2s都是可以的。文档示例中是1分钟,最好根据自己的情况修改。…