0%

核心概念

战术设计(Tactic DDD): Entity, Value Object; Aggregate, Root Entity, Service, Domain Event; Factory, Repository
战略设计(Strategic DDD): Bounded Context, Context Map; Published Language, Shared Kernel, Open Host Service, Customer-Supplier, Conformist, Anti Corruption Layer (context relationship types)

Entity(实体)
  • 存在 2 点特征
    • 唯一标志:当一些对象不是由属性定义,而是由一个唯一标志定义的话,我们就可以认为它是一个实体。
    • 连续性:对象的连续性体现在对象是有生命周期的。
  • 由上2点可以看出,实体并非一定是映射到我们现实世界的某个具体事物
  • 生成实体唯一标识的 4 种方法
    • 用户提供一个或者多个初始唯一值作为输入时
    • 程序内部通过某种算法自动生成身份标识,例如UUID、雪花ID等
    • 程序依赖于持久化存储,比如数据库生成的自增主键
    • 通过其他的限界上下文决定出的唯一标识,作为程序的输入。
  • 实体不变性
    • 一个实体维护了一个或者多个不变条件
    • 不变条件主要是由聚合所关注
阅读全文 »

整体架构

image-20210228184558960

ha3本身是阿里系针对自己的场景自己研发的搜索引擎平台,也是基于自身的技术积累之上构建的,包括依赖的系统和代码库,都是自研自足的。经历了近10年的发展,也经受了核心场景双十一的考验,已经是一套非常完善成熟的系统,值得学习和研究。 图中为ha3的基本架构,比较简洁,主要分为数据源聚合(俗称 dump)、全量/增量/实时索引构建及在线服务等部分,其中数据源聚合在 tisplus 平台和 Blink 平台完成,核心有以下几个模块:

  • QRS
    • 输入的查询解析/校验,转发searcher
    • searcher 结果合并加工返回用户
  • Searcher
    • 文档召回服务,包含打分/排序/summary
  • Build Service
    • 全量/增量/实时索引构建,提供给在线服务使用
  • 其他
    • hippo: 调度系统,分配机器
    • suez/suze_ops,引擎管控/任务分发
    • deploy express,用于分发包,索引,配置等数据
    • swift,消息队列
    • cm2/vipserver,域名解析/服务发现
阅读全文 »

背景

Blink 其实是阿里内部基于 flink 改造的系统,学习 Blink 首先要学习 flink 相关的知识,先了解一下 flink 产生的背景和要解决的问题。

在大数据开始爆发的时代,mapreduce 作为初代的计算引擎,提供了分布式计算的核心思想,map&reduce的分阶段处理。但是 map reduce 本质上还是批处理计算框架,随着业务发展,流式数据计算处理的需求越来越旺盛,storm 等应运而生,但是作为第一代流式计算框架,存在一些设计上的缺陷,包括 exactly once等语义的支持。而且批处理和流处理作为处理同一个业务逻辑的两套系统,需要维护两套代码,并不是很友好。而这个时候 spark也发展起来了,集批处理,流处理,SQL 功能,图计算,机器学习于一身,并且支持 SparkR 和 PySpark 来做科学计算。而同时支持流处理和批处理的计算引擎,只有2个选择,除了spark 便是 flink。

阅读全文 »

背景

通过把nextjs的静态文件放到github pages上,省一波流量钱,但是发现资源文件总是会404,本来以为是github pages构建完成更新cdn需要缓存,但是过了很久都没有成功,以下是静态文件目录

1
2
3
4
5
-- _next
-- chunks
-- *.js
-- css
-- *.css

后来做了猜想是目录深度原因,但是测试下来还是没有用。 后面经过验证是 下划线开头的文件或者文件夹的原因, 折腾了好半天。 实际的原因只是因为 github pages使用jeklly引擎的默认规则。

解法

  • 避免使用下划线开头的文件(需要重新)
  • 通过在根目录创建.nojekyll 空文件, 关闭jeklly引擎
1
2
3
4
5
6
-- .nojekyll
-- _next
-- chunks
-- *.js
-- css
-- *.css

背景

最近学习了一下 nextjs,用这个写了个小网站 cushiwen.cn. 过程中发现 nextjs 天然支持 amp,虽然只有css-in-js的方式支持css, 但是还是很方便的,就尝试了一下。 发现过程中总是出现以下错误:

1
2
3
4
5
6
7
8
Error: Unable to fetch https://cdn.ampproject.org/v0/validator.js - connect ETIMEDOUT 172.217.27.129:443
at ClientRequest.<anonymous> (/Users/xxx/xtestw/xxx/fe-xxx/node_modules/next/dist/compiled/amphtml-validator/index.js:1:1159)
at ClientRequest.emit (node:events:329:20)
at TLSSocket.socketErrorListener (node:_http_client:478:9)
at TLSSocket.emit (node:events:329:20)
at emitErrorNT (node:internal/streams/destroy:188:8)
at emitErrorCloseNT (node:internal/streams/destroy:153:3)
at processTicksAndRejections (node:internal/process/task_queues:80:21)

这就很尴尬了, 我自己架了个ss的代理,但是node本身的请求没有走代理,需要解决这个问题。

大概有几种解法吧:

  • VPN的方式架梯子,成本有点高
  • Charles 全局代理捕获,自定义 response (未验证,理论可行)
  • node全局代理

本文讨论最后一种的解法

实现

查找了一些资料,通过global-agent来实现。其实现主要通过系统环境变量来实现的 主要步骤如下:

  1. 安装 global-agent

    1
    yarn add global-agent
  2. 添加引用

    在需要的页面里面添加引用,我是在 _app.tsx 文件添加的

阅读全文 »

UndeclaredThrowableException 原因

RPC 请求的时候抛出该异常,异常点是 RPC 调用的地方抛出的该异常,除此之外没有其他的异常信息。仔细排查,实际的异常应该是网络IO的TIMEOUT导致的。 那么,就有2个问题需要探讨:

  • 为啥抛出的是UndeclaredThrowableException,而不是 TimeOut 的 Exception
  • 如何抛出 TimeOut 异常

为啥抛出的是UndeclaredThrowableException

先说结论,之所以抛出这个异常,是因为在RPC调用的实现中,使用了 JDK 动态代理的原因。在 JDK Proxy 的调用中,如果实际运行时(InvocationHandler#invoke) 抛出了某个**受检异常(checked exception)**,但该受检异常并未在被代理对象接口定义中进行声明,那么这个异常就会被 JVM包装成 UndeclaredThrowableException 进行抛出。

这里面有个受检异常的概念,简单解释一下,Java 中所有异常,都继承自 java.lang.Throwable 类。

阅读全文 »

去年在做内容库的时候,涉及到了多系统多数据源互相查询的情景,当时就想要将内容库的所有数据,增加统一的数据接入层,通过graphql的方式提供给上层业务使用,后面受限于人力没有实施。目前从头开始做站群相关的业务,顺带着浅尝了一下graphql,感觉还不错。

GraphQL 是什么

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

背景

参看: https://www.youtube.com/watch?v=Ah6GSCK5Rfs

graphql 和 rest api 是同一层的东西,都是一种基于 http 之上的数据接口协议,两者设计理念完全不同。目前来说 graphql 在很多大小厂也都开始使用,确实会方便很多。 但是 rest api 还是最广泛应用的协议,比如 AMP (T T)。 事实上任何东西都有2面性,对于graphql 来说,优缺点都有

阅读全文 »

工程中的网络请求,有时会需要使用http代理,比较简单的方法是使用apache的httpclient 直接设置代理,但有的时候使用java自带的HttpURLConnection的时候,就需要注意多线程的问题了。 使用HttpURLConnection 实现代理的方法也很简单,在建立连接之前先设置代理:

Authenticator.setDefault(authenticator);

需要注意的是,设置代理的方法并不是使用HttpURLConnection的一个方法,而在建立请求的时候,也没有任何调用和使用 Authenticator的地方,可以猜测这里设置了代理是使用了全局量,跟进Authenticator中去,会发现: 1 2 其实setDefault 方法就是设置了一个静态变量,而这个变量被使用的地方在: 3 (三个同名函数,相同的处理)这个静态变量被全局的网络请求所使用,而不是当前连接独占的配置,一般来说,当前网络使用一个http代理的时候没有问题(比如我们就是通过elb代理多个IP出口),但是当我们有多个代理的时候,在多线程环境下就会出现问题,如果代理服务器的账号密码不同,请求的服务球对cookie和ip进行校验的时候,就会比较麻烦,所以需要想办法来让每一个HttpURLConnection独占这个代理配置,直接的方法似乎没有,但是可以折中,同步网络请求过程中,HttpURLConnection是和唯一线程绑定的,我们可以用ThreadLocal,让每个线程独占一个代理配置,从而间接的保证每个HttpURLConnection始终使用一个代理配置。 可以定一个类:

阅读全文 »

前段时间,因为一年前篡改了一个sdk的包,导致了一系列不可预知的损失,这也充分说明了技术的正确性,需要决策的正确性来支撑的。作为技术人员,不仅仅要考虑技术的可行性,也要考虑实施后的风险和结果的预期假设。 从工程角度,简单记录一下篡改sdk包的技术。

  1. 解压jar或者apk的包
  2. JD-GUI 反编译查看class的相关代码,找到修改点
  3. 自己编写相应的方法或者类,使用 javaassist 注入到class文件
  4. 重新打包

javassist 使用方法参考: https://jboss-javassist.github.io/javassist/tutorial/tutorial.html 附上测试代码,修改一个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void main(String[] args) {
try {
javassist.tools.reflect.Loader cl = new javassist.tools.reflect.Loader();
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath("/tmp/aa/");
CtClass cc = pool.get("com.facebook.ads.internal.d.g");
CtMethod ctmethod = cc.getDeclaredMethod("c");
cc.getDeclaredField("c");
// getCode()即为需要替换的的代码
ctmethod.setBody(getCode());
cc.writeFile("/tmp/aa/");
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

最近的论文用到了RSA相关的东西,做一个整理。

流程图

  • 密钥生成过程: RSA
  • 加密解密过程: RSA

选取2个质数p、q

\(RSA\)算法的主要就是基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难。 同时为了增强强度,\(p-1\)和\(q-1\)的最大公因子要小 质数的选取方法:

  • 随机搜索法随机产生一个奇数 \(p_1\) 进行素数测试,若是素数,则结束;否则,重新随机产生一个奇数 \(p_2\) 进行素性测试,直至找到一个素数 \(p_t\)。
  • 随机递增搜索法随机产生一个奇数,对以该数为起点的奇数依次进行测试,直至找到一个素数。这种方法相对于随机搜索法,在速度上有一定的提高,但是并没有本质上的区别
阅读全文 »
×