AlexiaChen.github.io icon indicating copy to clipboard operation
AlexiaChen.github.io copied to clipboard

My Blog https://github.com/AlexiaChen/AlexiaChen.github.io/issues

Results 123 AlexiaChen.github.io issues
Sort by recently updated
recently updated
newest added

## 什么是Kubernetes(k8s) 就是一个开源的容器编排系统,与Docker开发的swarm差不多。但是现在k8s已经是主流社区的事实标准了,让我不得不学习。 它源自于Google内部的Borg,后来由Google重新用golang开发并开源,具体历史可以去查。 为什么会有这种编排工具呢?一个是由于运行在网络上的大型业务已经逐渐从单体应用发展成了成百上千的分布式的微服务,一个就是容器的流行化,需要方便地管理大规模的容器应用,所以类似于k8s这样的管理容器的工具应运而生。 编排工具的设计直接就提供了高可用,可扩展性还有故障恢复。 ## k8s提供了哪些主要的组件 这些组件的功能基本就可以把k8s用起来了。 ### Pod 说到Pod之前需要提到Node的概念,这里的Node表示一台虚拟机或者物理机器这样的节点。Pod是k8s的最小调度单元,同时它可以被认为是容器之上的抽象,说人话就是,你可以认为容器就跑在Pod里面(它创建了容器的运行时环境)。这样也就意味着有这么一个抽象的中间层,k8s就提供了不同的容器运行时的插件机制,比如Docker,还可以换成其他的容器技术。反正容器的CRI标准都已经定义好了。k8s完全可以不依赖Docker。一般来说是一个应用服务(最多)跑在一个Pod中,你可以多个应用跑在一个Pod中,但是一般不推荐这样做。 每个Pod都有自己的IP地址,在一个k8s集群内的所有Pod通过VxLAN这样的大二层技术组成了一个大的二层局域网络,每个Pod都可以通过IP地址访问其他的Pod。当然,这个IP地址外部不可访问,是一个内部地址。Pod有生命周期,会死亡,容器里面的进程会崩溃比如访问越界导致Pod崩溃重启,会被调度到别的node上,这时Pod的IP地址会变化,这些IP地址不是固定的。所以这些IP地址显然不是给人使用的,所以Service这个概念诞生了。 ### Service Service在集群内就有一个“永久”的固定IP(假设集群不死的话),这才是给人用的。Service还提供了解耦Pod的功能(它与Pod的消亡和创建调度无关),你可以理解为Service是一个Pod或某几个Pod的前端稳定统一的网关入口。创建一个Service你就需要把这个Service给attach到指定的Pod上。当然,Service有几种类型,本质上来说姑且分为两种,一种是外部Service,可以让外部浏览器访问Service关联的Pod内部容器提供的服务,一种是内部Service,不允许外部访问,主要是内部沟通。比如数据库的端口服务就不允许外部访问。 ![图片](https://user-images.githubusercontent.com/8574915/140706128-2539b3ca-e50c-46d7-930a-449766d63e4f.png) 上面的my-app-service-ip就是Service的固定IP地址,也就是所谓的Service的ClusterIP。 上面提到的外部类型的service可能叫法不专业,一般来说就是k8s中LoadBalancer类型的Service了,但是你会发现,如果你的多个服务都需要暴露给外部访问,那么你就需要创建多个对应的LoadBalancer类型的Service,多么不方便啊,而且每个LoadBalancer Service的IP都不同,太麻烦了。这样Ingress这个组件就应运而生了。 ### Ingress 你可以使用一个Ingress,它位于这些服务的前面,进行路由选择。这样就不用创建LoadBalancer的Service了,以下就是Ingress的yaml配置例子 ```yaml apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name:...

云计算
工具
运维
容器
DevOps

# 深入了解Ed25519 都知道Ed25519是一种比较新的椭圆曲线签名方案,相比ECDSA,也就是基于传统 Weierstrass形式的椭圆曲线(secp256r1 secp256k1)的签名方案,它综合对比下来是要好上不少的。它是EdDSA方案的一种实现之一。 现在ECDSA的工程实现,从效率上来看,已经被实现优化得非常快了,比如在OpenSSL等密码签名库中。 但是安全性还是有些欠缺,随着技术的改进以及CPU新指令的出现,还可以逐步提升执行速度. 然而更好安全性与更高的执行效率的诉求, 或许无法通过这种小步迭代和缝缝补补方式得到满足。同时解决前述的应用安全, 实现安全以及执行效率的问题, 要求在工程手段之外更为深度的改进, 一个自然的方向是重新构建椭圆曲线以及签名机制以便在多个层次上同时改进。 直到2007年HAROLD M. EDWARDS发表了一篇[《A Normal Form For Elliptic Curves》](https://www.ams.org/journals/bull/2007-44-03/S0273-0979-07-01153-6/S0273-0979-07-01153-6.pdf)的论文,由此引出了一种椭圆曲线的一种新的表达形式,这种形式表达的椭圆曲线就叫爱德华曲线(Edwards Curves)。这曲线是最近几年才被密码学社区广泛关注的,因为这种形式的椭圆曲线更简洁,高效,曲线上点的加法表达也更优美。 爱德华曲线是这样的: ``` x^2+y^2=a^2+a^2*x^2*^y2,其中a是常数。其实也就是曲线的参数。 ``` 至于为什么椭圆曲线有这样更一般化的表达形式,是因为每个在非二元域(non-binary field)的椭圆曲线在代数上同构于这个曲线在该非二元域的扩张域下的爱德华形式,甚至在多数情况下同构于该非二元域的爱德华形式。同构你可以理解成在代数上等价,或者说,在代数角度看,这两个曲线是一样的,简单点说就是它两灵魂相同但是几何形状不同。为什么在数学上要找同构? 因为就是让研究者们研究更本质的东西,去除掉这些虚有其表的肤浅的东西。在另一个简单的对象中研究一个与之本质相同的复杂的对象,化繁为简。 就在2007年的当年,随后Daniel J....

密码学
数学

为什么OOM打双引号,因为最终发现,不是内存泄露导致的OOM。 最近leader刚给我分配了一个OOM的任务给我,现象是explorer node在grafana的监控上出现在大量并发访问explorer node时,内存在监控上急剧上升,然后并没有下降,最终被systemd给kill掉了。 这种现象一般可以肯定都是OOM,就是代码哪里内存泄露了,导致分配的内存没有被GC。经过了我的一番排查,还写了一大段的英文分析报告,inuse_space是随着请求量增大而增高,但是随着请求量下降关闭,它也回归到了正常值,但是linux的top命令的RES项还是没有降低下来,所以当时我都怀疑人生了,是不是pprof哪里没用对或者哪里理解错了,后来还是请教了golang社区的一位哥们,他正好看过一个关于golang社区的提案,跟我说了,说的就是这个问题,很多人都遇到了,实际就是runtime GC掉的内存不会立刻归还给操作系统,所以就就给监控造成了麻烦。 这个feature主要是为了一些性能才这样做的,但是好心没办成好事。经过社区的讨论,最终还是恢复成原来的设置了,也就是在go 1.16中,被GC掉的内存会立刻归还给系统。 go的老版本需要` run binary with GODEBUG=madvdontneed=1` 就可以归还给系统了,或者直接升级到go 1.16。 一下是社区的一些讨论: - https://github.com/golang/go/issues/42330 - https://github.com/golang/go/issues/37585 - https://go-review.googlesource.com/c/go/+/267100/ - https://github.com/google/cadvisor/issues/2242 - https://github.com/golang/go/issues/23687 - https://github.com/golang/go/issues/28466 - https://github.com/prometheus/prometheus/issues/5524...

软件调试
杂记
golang

# 程序员应该知道的数据库知识 ## 数据库范式与反范式 这里没啥好讲的,一般传统企业重业务,对性能,高并发要求小的开发,对数据库设计的时候尽量遵守范式,尽可能达到第三范式要求,如果是大并发,追求灵活的开发,可以适当的对范式取舍,加入违背范式的设计也没什么,互联网反范式的设计有很多。 ## 分库分表 ### 怎么拆分 根据业务拆分,根据读写比重拆分 ### 分布式ID生成服务 分库之前,用数据库主键的自增就可以了,但是分库以后,需要一个全局ID服务,业界有snowflake。 ### 拆分维度的选择 比如有个电商订单表,表里面有订单ID,用户ID,商户ID,到底是按照哪个ID进行拆分? 如果要进行多维度的查询,一般要建立一个映射表,建立辅助维度和主维度的映射关系,比如商户ID到用户ID的映射。 这个根据业务来看,不然东西太多,说不了。 ### Join查询问题 分库分表之后,join查询就不能用了,一般有以下方式解决,祖传秘方,如果不出意外,性能不好,一定是数据库的问题: - 把Join拆分成多个单表查询,不让数据库join,在业务代码层面对结果进行拼装,大大降低慢查询概率 - 做宽表,重写轻读。做一个join表,提前把结果join好写入,空间换时间。 - 利用类似ES等搜索引擎,把数据导入进去,解决join问题 ### 分布式事务 分库之后,数据库内建的事务就做不了了,一般解决办法就是优化业务,避免跨库的分布式事务,保证所有事务都落到单库中,实在无法避免,再考虑分布式事务的解决方案。...

数据库
架构设计

# 分布式理论----CAP ## CAP理论 CAP定理是由UC Berkeley的Brewer教授在2000年的ACM PODC上提出的一个猜想,然后由MIT的某两个教授继续完善并证明了这个猜想,这样就让这个猜想成为了分布式领域的一个定理。如果你要设计或者是搭建一个分布式系统,那么CAP理论你需要懂一些的。 CAP猜想被提出来的时候,并没有详细定义Consistency,Availability,Partition Tolerance三个概念的明确含义,之后才有人慢慢完善概念,所以你去网络上搜索,解释在细节上还是有3一点点差别的。 下面会摘录国外一位大神对CAP理论的渐进式理解,他也是慢慢来的。 简单粗暴版本: - 对于一个分布式系统而言,不能同时满足一致性,可用性,分区容忍性这三个设计约束。 科学严谨版本: - 在一个分布式系统(互相连接并共享数据的节点)中,当涉及读写操作时,只能保证一致性,可用性,分区容忍性三者中的两个,另外一个必须舍弃掉。 这两个版本有点差异,主要有两点: - 严谨版本定义了什么才是CAP理论探讨的对象,强调了互相连接和共享数据的分布式系统,为什么要强调这两点? 因为并不是所有的分布式系统都会互联和共享数据。最简单的就是memcached集群,互相之间就没有连接和共享数据,因此这样类似的分布式集群不符合CAP理论的讨论对象。MySQL集群就是互联和共享数据的(进行数据复制),这才是CAP理论的讨论对象。 - 强调了读写操作,CAP关注的是对数据的读写操作,而不是分布式系统的所有功能。Zookeeper的选举机制就不是CAP理论的讨论对象。选举机制是分布式系统里面的共识部分。你见过由讨论共识算法的人把CAP搬出来吗? 下面单独分开讲解CAP的3个设计约束。 ### 一致性(Consistency) 简单粗暴版本: - 所有节点在同一时刻都能看到相同的数据(不考虑网络时延,不考虑物理世界规则,100%强一致) 科学严谨版本: -...

分布式系统
数据库
架构设计

# 数据库事务实现原理 之前写过《程序员应该知道的数据库知识》,原本是打算把事务实现写在那里的,但是发现篇幅太长,所以需要拿出来单独写成一篇。 ## Redo Log 数据库事务有ACID四个核心属性,之前说过,再提一下: - Atomic,原子性。事务要么不执行,要么完全执行。如果执行到一半,宕机重启,已执行的一半要回滚回去 - Consistency,一致性。这里的一致性跟分布式的CAP理论的一致性不是一个概念,这里的一致性是各种约束条件,比如主键不为空,参照完整性等,也就是说这里是关系模型中的完整性约束。 - Isolation,隔离性。这个概念与多线程,并发性密切相关,如果事务全是串行的(最高隔离级别),也就不需要隔离,因为全是排队独占,事务没有并发。 - Durability,持久性。一个事务一旦被commit提交,它对数据库中的数据改变就是永久性的,接下来即使数据库宕机,也不应该对其有任何影响,说白话一点就是事务关联的数据确定落盘了。 这四个属性中,D比较容易,最简单,C主要是上层的各种规则来约束,也相对简单。但是A和I牵扯到并发问题,崩溃恢复(掉电保护),是事务实现的核心难点。 说到事务实现原理,就要提到ARIES算法(Algorithms for recovery and isolation expoliting semantics),这个算法是由早年IBM的几个研究员提出的算法集合,论文名字叫《ARIES: A Transaction Recovery method supporting Fine-Granularity Locking...

数据库

因为项目中的RPC接口经过大量调用,通过pprof看到的结果就是消耗在了reflect.,mapassign 等由json decoder引起的问题。 ![unknown](https://user-images.githubusercontent.com/8574915/117593903-870a0880-b16f-11eb-93a1-f22aea0a038d.png) 上图就是我本地复现的情况 经过google,发现/thanos也有这个[issue](https://github.com/thanos-io/thanos/issues/1160),经过他们讨论被一个[临时的PR](https://github.com/thanos-io/thanos/pull/1173)缓解了,他们的svg调用图为以下,看起来跟我们的pprof结果很一致。 ![](https://user-images.githubusercontent.com/2804025/47689031-29121700-dc3c-11e8-87c7-f0c78ee7135e.png) 最终的临时方案就是用json.Unmarshal 替换NewDecoder().decode。 这样会好一些,但是也只是缓解该现象。没有彻底解决,所以当时他们这个[issue](https://github.com/thanos-io/thanos/issues/448) 还是打开的。 也许reflect相关的GC问题比较难修复,go官方的issue也提到了,但是还没有close https://github.com/golang/go/issues/28783 静观其变吧。要不就是直接把json这个换成其他的格式,但是这与我们项目的的目的背道而驰,因为几乎所有区块链都支持json RPC。 最后还是发现一个中文社区的朋友也遇到我类似的问题: http://javagoo.com/go/mapassign.html, 他的解决方案是: > 既然decodeMap消耗内存严重,我们就放弃使用map。Transfer rpc之前,先将map转成string,然后Judge再将string转成map。 所以他是设法绕过一些问题。我看也有一些项目是用protobuf等格式取代json的,但是我们的项目行不通,json无法取代。 当然这个问题如果有大量RPC访问,是会触发OOM的,json.decode还有RLP.decode都会消耗大量内存,以太坊就有很类似的两个issues(因为从pprof的结果上上看很一致),最终经过一番调查都没有内存泄露,给出的建议是加入rate limiter: - https://github.com/ethereum/go-ethereum/issues/22567 - https://github.com/ethereum/go-ethereum/issues/22529 当然,还有一个就是尽量把json的缓存,还有其他缓存加上。

软件调试
golang

之前我们提到的非交互式零知识证明都是从Sigma Protocol来的,这个是ZKP里面比较简单的构造零知识证明的手段,首先设计一个交互式协议,再用Fiat-Shamir变换(Fiat-Shamir heuristic)把交互式变成非交互式(NIZK),commit challange prove就是它的核心三步骤。现在要讲的防弹证明(BulletProofs)是比较新的一种零知识证明算法。它有两大应用就是: - 做范围证明(Range Proof),也就是证明一个值在某个给定范围内,但是不泄露这个具体的值(witness),这里就是关于这个值是零知识的。这里就可以应用在Confidential Transaction上面,防止泄露转账金额。 - 作为Sigma Protocol的一般替代算法 对比当今的zk-SNARKs和zk-STARK系的ZKP有什么优缺点: 优点: - 对比zk-SNARKs,它不需要可信设置(trusted setup) - 对比zk-STARK,它的生成证明的数据大小比较小,大概可以小到1kb以下,Proof size与witess成对数关系 O(log(witness)) - 支持证明数据的聚合(aggregation), 也就是把多个证明合并在一个单个证明字段中,这样就减小了存储的占用,对于BTC这样UTXO很多的链来说,能省不少存储。 缺点: - 对比zk-SNARKs,它的verify证明的过程,需要消耗更多的时间 ## References: -...

密码学

## 前言 这里主要是了解基本原理,暂不作很深入的学习。 ## 身份基加密(Identity-Based Encryption, IBE) 先来介绍下IBE的背景知识吧,首先我们现在传统的PKI公钥密码体制存在的一些问题,比如发送者必须拥有接收者的证书,证书管理和CRL的复杂性,还有可能存在的证书数据库被暴露给组织机构等。 主要就是在传统的RSA公钥密码,公钥一般是人类不可理解的大数,无法把公钥与个人身份联系起来。所以在传统的公钥密码体制中,就需要有个可信的第三方中心(证书数据库)为每一个用户的公钥生成一个公钥数字签名(数字证书),主要作用就是认证用户公钥的作用(公钥与用户个人身份的绑定)。一旦有了数字证书,那么就存在管理,撤销,传输等等一系列的复杂操作,这些复杂的操作管理可能就是导致非密码学相关的安全事故发生的根本原因,所以为了解决这些问题,身份基密码体制被提出。 身份基密码体制有以下优势: - 针对未准备(注册)用户的密码学 - 公钥是用户身份的某些属性,例如电子邮件地址,QQ号码,电话号码,指纹数据等 - 发送者只需要知道接受者的身份属性即可发送加密邮件(公钥加密私钥解密) - 接收者在收到加密邮件后才需要与身份基密码系统进行交互 身份基密码的概念最开始是1984年由Shamir提出的,在论文Identity-Based Cryptosystems and Signature Schemes中提出了一个身份基签名(Identity-Based signature,IBS)的工作系统,但是并没有提出身份基加密(Identity-Based encryption)的系统方案。所以这个时候,身份基密码还停留在很初步的概念草稿阶段,所以构造一个高效可行的IBE是后来的密码学比较热门的方向。 直到2001年,第一个身份基加密(IBE)的系统方案由斯坦福密码学大佬Dan Boneh和Franklin的2001的论文Identity-Based Encryption from Weil...

密码学

## 前言 学习强国App真是个好物,很多Mooc学习资源它都有入口,看到电子科大有一门《现代密码学》所以就简单过了一遍。虽然平时是做区块链,但是涉及隐私计算这部分少,并且我们公司的技术并没有盲签名,群签名(组签名)的应用,所以还是打算简要介绍下。PlatON就是主要做隐私计算的,嗯。 ## 正文 ### 盲签名(Blind Signature) 盲签名是在发送者A和签名者B之间的双方协议,基本套路是:A发送一段信息给B,B对这和消息签名并返回给A,从这个签名中,A能够计算B关于A预先选取的消息m的签名。 以上说法有点绕,平时的签名我们接触到,就是签名者用自己的私钥对消息m(明文),进行签名,也就是签名者是知道消息m的内容的,这样暴露了消息隐私,那么有没有什么方法可以既不让签名者知道消息明文m,又可以对其进行签名并还不知道真实的签名数据呢?答案就是盲签名。盲签名的作用就是让签名者无法知道它对什么东西签了名,也无法知道其真实的签名,那么以后签名者B也不能将所签的消息和发送者A联系起来,也就是签名者貌似是把“眼睛”蒙蔽起来了。 那么盲签名具体有什么应用场景呢? 发送者A(客户)不希望签名者B(银行)能够将一条消息m及其签名Sig_B(m)与客户自己联系起来,可能消息m中有具体的金额数额,当m和Sig_B(m) 提交给B进行支付时,B无法推断原先接收签名的是谁。这就允许了A的匿名性,从而A的消费模式B也不知道。 大概的盲签名协议如下: - 签名者B需要一种数字签名机制。用Sig_B(m)记为B对m的签名 - 函数f和g(只有发送者A知道),满足关系 g(Sig_B(f(m))) = Sig_B(m)。 f叫做盲化函数,g叫做去盲函数,f(m)叫做盲消息 以上协议大致就这样,你看到第二条就知道了,关键就是函数f和g的选择,这样才可以满足第二条的等式关系,你可以从关系等式中看到,对消息明文m进行签名就等价于给消息m“加密“以后的签名再“解密“以得到最原始的签名,也就是签名者B签出来的名不是对原始数据的签名,这样A既达到了签名的目的,也没有泄露自己消息m的隐私。非常强大。 一个比较成熟的盲签名协议---Chaum盲签名协议 这个协议是基于RSA公钥体系的,也是最原始的盲签名协议 - 首先编码消息明文是m为一个大数字, m满足 0

密码学