技术

  • Java,  技术

    Baeldung-最好的技术网站,没有之一

    已经记不清楚看过多少baeldung的文章,今天又用它解决了一个java debug的问题。Tungsten以前一直可以remote debug忽然最近发现不行了。 最后还是这边文章解决了问题:https://www.baeldung.com/java-application-remote-debugging 原来根本原因是我们升级了JDK到8,老的Java 5的debug参数已经不能用了。。而且貌似Java 9以后参数又变了。 我看Baeldung有中文版,但是翻译工作做的真的一般。。中文真的应该有一个类似的权威的技术门户,文章的质量控制真的非常非常重要。有很多的技术网站,但是内容都是网友贡献,有些很好,有些质量却很差。还是需要中心化的审核机制

  • 工具,  技术

    对象的序列化

    对象的序列化和传输在过去这些年也发生了很多的变化。 Java序列化 很早以前用这个,因为这种序列化方式只能局限于一个单一语言,已经不再用了。 Json 用Jackson的ObjectMapper把一个对象序列化成Jason,然后再反序列化. Avro Kafka的默认方式。需要提前预定义好model,序列化,反序列化的时候都需要用那个model。model更新的时候我记得并不像想象的那么简单。比如说加一个字段。我们必须asdl定义NoAE的所有的消息都有自己对应的Class,Serializer和Deseriallizer,都是基于Avro的。比如 NotificationInstanceDeserializer NotificationInstanceSerializer AvroSerializer.java (This copied from GenericBinarySerializer.java in CDC-model) 而DACO的Serializer和Deserializer都是用一个 JsonSerializer.其实就是Jakson的ObjectMapper的实现。不过传输的都是二进制(但是其实就是json专程bytes而已,Kafka的所有消息都是bytes)。DataModel必须是JsonNode的实现(其实不需要,objectMapper.writeValueAsBytes这个方法就是接受Object)。没有语言独立的表达。。绑定Jackson. 这个就是偷懒的做法。不需要定义avil文件,只需要写一个继承JsonNode的bean就好。主要是公司没有一个统一的标准,大家都选择自己最convinience的方法去做。以后如果要改格式就还挺麻烦。 JsonSerializer.java KafkaJsonDeserializer.java. 所以Kafka consumer都是拿的JsonNode,需要再转为子类。比如NotificationMessage.java Protocal Buffer gRPC的默认方式。和Avro类似。尺寸都比较小。

  • 技术,  算法

    Recursive递归的时间空间复杂度计算

    基本概念 递归可以层次可以通过tree的形式展现。 比如下面的递归: 时间复杂度:就是总的树的节点s数。如果每一次层嵌套都包涵2层平行的call,那时间复杂度就是O(2^N).如果有四层,那么就是O(4^N). 空间复杂度:就是总的树的深度。在这里就是N 深度优先算法(DFS: Depth First Search) 深度优先算法是一个递归调用。对于图的深度优先,我们有Vertices和Edge的数量,分别用V和E来表示。 时间复杂度:因为是图,所以在递归的时候每一次层有多少节点是不知道的,所以没办法按照2^n的普遍算法来算。但是换一个思路就是无论如何每条边都至少需要走一遍。时间复杂度就是总的边的数量,每条边会被访问两次,一次是遍历,一次是会退。O(E). 空间复杂: 如果所有的Vertices都是相连的,那么就会有V层深度的书。那空间复杂度就是O(V) 广度优先算法(BFS: Breadth First Search) todo 时间复杂度: O(V+E). 这里不是说O(E)比O(V+E)好。其实O(E)是O(2E).因为复杂度计算忽略常量,这里容易引起误解。 空间复杂: O(V) Reference: https://stackoverflow.com/questions/43298938/space-complexity-of-recursive-functionhttps://zhuanlan.zhihu.com/p/95081559#:~:text=%E5%9C%A8%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2%E7%AE%97%E6%B3%95,%E5%BA%A6%E4%B8%BAO(V)%E3%80%82

  • 技术,  算法

    Java中数组操作的性能

    其实不同数据结构的性能差别还是很明显的,只是在实际使用中这种差别会被网络等各种开销所掩盖。所以这里看到的1000倍以上的差别可能在实际场景中并不那么明显。 下面写写出结果: 运行环境时m1 CPU的macbook mini。可以看到插入1000个int到数组是0.017ms, ArrayList是0.584ms, LinkedList是0.379ms,HashSet是5ms,LinkedHashSet是2ms。最好和最差之间相差500倍。 但是如果要在网络传输这么1000个integer对象,可能直接就是几十毫秒的花销了,存储的时间根据不同介质也要几毫秒不等。而且通常如果需要存储的话肯定也需要网络开销,本地存储的概率很低。 但是这些基础的性能开销上的差别在大数据处理的时候应该还是能显现出差别的。最慢的5ms 1k数据,如果数量级到1million的话,那么就是5s,1billion的话就是1个多小时。如果用int的话,那就是10s。1个多小时 VS 10s 还是很可观的差距。只是不知道把1billion的数据load到内存需要多久😂 在实际的项目中其实也从来没有遇到过这种内存计算开销导致的性能瓶颈。如果以后什么时候遇到了,我再回来update这里。。

  • Java,  技术

    Java Streaming Basic

    10年前加入现在的公司的时候公司的产品还在用JDK5,写code自然完全不会用Lamda,Streaming这些8才出现的特性。 后来开始做micro service了,用到新版本的JDK,但是我也很少写code了。中间看了一些书,不过一直是似是而非。是时间仔细看下了。 Intermediate Operations filter limit map flatMap Stream.map和Stream.flatMap的区别 先看signature. 区别是 flatMap穿进去一个Item,出来一个Stream: 这两个其实是完全不一样的东西,map就是把steam里面的item转换成另外一个,非常简单。flatMap是用来处理item也是list的情况,有时候我们想把两维列表转化成一个,就可以用这。下面是一个简单的例子: 下面是项目的一个更加实际的例子: 这个例子是拿到一个父对象,父对象里面有子对象,这样就能拿到所有的子对象。 总的来说stream就是一个循环,而flatMap就是一个嵌套循环。 下面是另外一个lamda的例子(不是method reference): Terminal Operation forEach forEach其实就是iterate.不用改被用作计算,就是用简单的report,或者简单的操作比如把结果加到另一个colection里面. –<Effective Java> collect 常用的的下面几种: toList toSet toMap:如果有重复key,会出错。第三个参数可以用来去重。比如可以选择最大,选择最后的一个。 groupingBy:Value可以是一个数组,也可以是summary,比如`counting()`. Joining: 三个参数,join的delimiter, start character,end character

  • Docker,  技术

    Docker的权限控制

    昨天晚上几个小时折腾一个docker上的mysql数据库的问题,最后发现根本原因是自己脑残把docker的目录的权限写成777. 由此导致了一系列问题。 事情的起因是想给mysql加一些参数,限制总的binlog的size。因为昨天发现磁盘空间被mysql用完然后导致这个网站down机。。 本来加一个参数很简单的事情,但是修改了/etc/my.cnf 之后发现参数并没有生效。于是各种研究,后来发现在log里面显示由于my.cnf的权限是全局可写,然后mysql自动忽略了这个配置文件而用缺省文件。所以所有的添加到my.cnf里面的信息自然不会生效。 在这里的时候完全没想到是因为自己把docker的目录改成777导致了,心里却在埋怨做image的人怎么留下了这个bug。于是上手又是用volume map本地的my.cnf到远程(我的docker daemon是run在远程linux下),又是直接修改my.cnf的权限。终于配置文件生效了。但是tungsten replicator怎么样也连接不到mysql。于是添加ssl=0 试图disablessl,但是又遇到无效caching_sha2_password的问题. 搜索文档还要修改用户的默认密码存放方式,想修改还是不成功,还要修改system db的engine。。 因为在这开始之前,我的tungsten replicator 通过修改ssl的方式就可以连接,完全没有做那些繁琐的操作,于是开始怀疑到底哪里出错,为什么这次需要这么复杂。 2个小时以后开始怀疑可能是/etc/my.cnf的权限问题不是image的问题,而是我做了777导致了。又做了一些尝试终于算是解释了所有的现象: 由于错误的使用777,导致mysql image初始化的时候使用了默认的参数配置,这就是为什么当我之后再修改my.cnf的配置的时候已经晚了,因为缺省配置很多时候是没办法初始化之后修改的。比如说创建用户的时候的密码设定( 应该是“mysql_native_password“而不是缺生的”caching_sha2_password”). Volume映射的时候文件权限默认使用的是宿主的文件权限。我的docker compose文件在mac,docker engine在linux。最终的映射是 mac -> linux host -> container. 这中间还有一个把nas的文件映射到linxus host上的过程(这里也出现了一些问题,docker后来莫名其面起不来某些container,原来是我的nas映射出问题了,重启mac电脑解决。。) 中间试图修改docker的文件目录权限,但是发现太麻烦,潜在的问题太多,因为我也不知道最早的文件的权限是啥。所以干脆删除所有的目录,让docker重现下载image,重建目录。问题解决。 经验总结 要及时document各种步骤。我之前通过ssl=0解决了tungsten的链接问题,但是昨晚改动,工作了就没有document。结果几天以后自己都忘了自己做了什么,只记得在mysql上改了一个配置。当后来出现问题的时候,因为不确定之前怎么工作的,导致浪费了很多时间。 现在的docker 貌似是run在linux,但是由于使用docker compose运行很多containers,而docker compose文件是在mac,而且volume的映射最终是在mac (mac->linux host),所以docker 还是没办法脱离mac电脑而在远程执行。只能说runtime的话有linux host就好了,但是要做操作修改,还是要在mac端完成。 用Docker也有几年时间,但是没有真的很系统的学习,其实可能只需要认真花一两天看看书,很多我今天遇到的问题都不会出现。与其花时间debug问题还不如把基础打牢啊。。

  • 技术,  算法

    一些面试算法中的Java基本操作运算

    很久没有真的写程序,一些基本的Utils的使用也淡忘了。这里总结一下: 数组 数组转化成List List转化为数组 排序数组 排序List 打印一维数组 打印多于一维数组 打印List 答应list里面含有array MAP Merge Print a map 其他 boolean的值只能是true,false,而不能是0,1. char是用单引号: char abc=’a’;

  • AWS,  技术

    如何在AWS中提供API服务

    这里讲如何通过利用AWS提供的基础服务对外提供Service。从域名解析到Load Balancer,再到Docker Container的端口映射。 下面是结构图。 以下是几点说明: Loader Balancer 定义了internal的DNS Name (比如说:internal-daco-sbx08-102899950.us-west-2.elb.amazonaws.com ) . Route 53的 Hosted Zone里面的records就是把外部域名解析到内部的DNS Load Balancer分三种. Application Load Balancer 是HTTP级别的,Network Load Balancer是TCP级别的。 ALB可以做端口映射,并根据http header(上面的例子是Host),把请求分发到Target Group. Target Group定义了外部的端口,然后管理外部端口到instance的端口。通常target group的端口和instance的端口是一样的(如果在task definition也就是docker container里面映射了外部端口),也可能不一样(如果没有映射). Target Group, Service是1:1映射。Target Group会提供health check定时check是不是健康。Task内部实现约定API,做实际check. ECS, ASG, Lauch Configuration协同工作,各司其职,提供服务和scaling,monitor等各种管理。 疑问 貌似没有配置load balancer的数量。难道这里从来不会是系统瓶颈? 关于Target Group的外部端口和docker container(task)的内部端口是一对一映射,还是随机映射,而让target group自己管理,不知道哪个是best practice。