AlexiaChen.github.io
AlexiaChen.github.io copied to clipboard
My Blog https://github.com/AlexiaChen/AlexiaChen.github.io/issues
# 什么是架构? Linux内核有架构,MySQL有架构,JVM有架构,微信有架构,支付宝有架构,我们平时所说的架构到底是谈什么类型的架构? 当然,从上面所说的提问,我们知道了,架构一般泛指软件系统更加高层的设计或者组织方式,是更加宏观的层面,而不是代码细节层面,比如类的关系组织。 架构也有很多层次: - 基础架构:云平台,操作系统,网络,存储,数据库,编译器,一般自研基础架构吃力不讨好。 - 中间件与大数据平台:消息中间件,数据库中间件,缓存,监控,工作流都算,还有玩Hadoop生态圈 - 业务架构: 就是业务应用层的架构师,通常互联网说的架构师,最多的就是这一类。 ## 系统与子系统 系统(软件系统)一般是一堆有关联的实体组成,通过某种规则运行,完成单个实体不能单独完成工作的群体。当然,子系统也是一样的,也是一群有关联的实体组成的系统,一般是大系统的一部分,看角度了。大致是一个树形结构。 举个例子: - 微信是一个大系统,包含聊天,登录,支付,朋友圈等子系统 - 朋友圈这个系统有动态,评论,点赞等子系统 - 评论这个系统又有防刷子系统,审核子系统,发布子系统,存储子系统 - 评论审核的子系统不再包含业务意义上的子系统,而是包括各个模块或组件。Redis,MySQL就是存储系统,不是业务子系统了。 子系统追溯到叶子节点的时候,一般就是模块与组件了,因为工程量,规模或许是其他维度的原因,只能是组件,模块规模了。 ## 模块与组件 - 模块是从逻辑角度拆分得到的软件单元,比如一个模块由很多Java package构成。再比如,MySQL模块负责存储数据,ES模块主要负责搜索数据。...
# 如何选择一个开源项目 ## 选型阶段 ### 关注是否满足业务 相似开源方案比较多,新项目总是对外宣称技术更先进更优秀。如果面对这样的情况,请首先关注该开源项目是否满足当前业务,不要过于关注开源项目是否优秀。 ### 关注是否成熟 显然,无论多牛逼的程序员写出来的项目都会有bug,千万不要以为作者厉害就没有bug,不成熟的开源项目用到生产环境,风险极大。成熟的开源项目一般都是有数年的积淀的。个人经验,要成熟,至少3年起步。 - 版本号:不要选择0.x的版本号,至少选1.x版本,理论上来说,版本号越高越好,但是也不一定是,版本号高,会有新添加的功能,可能也会同时引入新bug。现在都推崇版本语义化,建议了解下,进行选择。相同功能不变的情况下,建议选择,fix以后的最新版本。 - 开源项目的用户数量:一般开源项目都会把采用了自己项目的公司写在主页上,公司越大越好,数量越多越好 - 社区活跃度: github上的star数量,issue数量以及回复处理速度,PR数量,commit数量以及频率等都是活跃度的度量指标 ### 关注运维能力 大部分小公司的“架构师”在选择开源项目时,基本都是关注技术指标,以及上面提到的两个维度,很少几乎不会关注运维方面的能力,可能小公司没有专门的运维团队吧,程序员自己就是开发+运维。然而,用户量也不大,反正昆明这边很少。 这里说下用户量稍大点的公司的情况,如果将技术选型方案应用到线上环境,则运维能力是必不可少的一环,否则一旦出问题,运维,开发,测试全部都傻了,根本无从下手。 - 开源项目日志是否齐全: 有的开源项目日志不详细,寥寥数行,出了问题根本没法查。 - 开源项目周边生态如何?是否有配套或者第三方的命令行,Web控制台等监控维护工具,能够看到系统运行时?尽量选择周边生态繁荣的开源项目。 - 开源项目是否好使?门槛和学习成本高不高?配置项是否复杂? - 是否有故障检测和恢复能力?...
CQRS的概念来自于领域驱动设计(DDD),就是命令与查询职责分离,相当于根据领域模型进行更高一层次的读写分离。一般读写两端的数据库在物理上是分割的。写端就是commands端,读端其实就是query端,这样做能最大化性能和提高系统的可伸缩性,更加灵活,如果CQRS模式结合Event sourcing模式实现复杂度也会更高,至今还没有一个成熟的框架。如果要实现,比较考验架构师的能力,因为要从CQRS的概念出发,实现基本的底层特性。 当然,读写两端的存储层就不用自己动手写了,一般用成熟的数据库,比如写端可以是MySQL或者PostgreSQL,读端可以是MongoDB或者PostgreSL(PG支持materialized views)。 当然,按理来说写端和读端的数据库是不一样的。但据知乎上更专业的人士评价,PostgreSQL作为号称全世界最先进的数据库,一个牛逼之处就是,几乎可以通吃主流场景(OLAP,OLTP),而且**都能达到不错的规模**,这是相当不得了,或许读写两端都可以用PostgreSQL了?https://github.com/tobyhede/postgresql-event-sourcing/ https://medium.com/@tobyhede/event-sourcing-with-postgresql-28c5e8f211a2 https://github.com/commanded/eventstore 看以上几个链接,看来PG通吃读写两端了。 CQRS配合Event sourcing的基本实现原理如下: - 应用界面程序发起一个command,这个command在Commands端是的CommandHandler异步接收的,然后一个command一般只做好一件事(对领域模型对象的聚合进行修改,实现业务逻辑),command之间尽量正交。 - 然后把关于一个领域对象变更的多个command的操作打包成一个不可变的事件(Event),这个事件追加(append-only)写入事件存储层(Event store)中。这样顺序写可以最大化磁盘IO性能,学过数据库的都知道,磁盘随机写是最耗时的了。同时也可以尽量减少事务冲突竞争,提高并发,想象下,数据库是有行锁的,并发修改同一行数据元组会产生竞争。 - 事件写入存储层之后,一般会发布这个事件,就是把这个事件放到MQ中来“通知”Query端的系统甚至其他我们现在暂时不关心的外围应用。(这里用到MQ需要考虑MQ的常见问题,比如消息去重,at least once语义等,MQ可以采用Kafka,RabbitMQ等) - Query端异步接收这些事件消息,通过这些有顺序的事件序列,重放事件序列关联的数据实体的当前状态,Query端根据这些事件流可以定时或定量地创建快照,以提高重放性能,因为事件流如果太大太长,从原始状态恢复当前状态会影响性能。(跨机器异步接收Event,就需要考虑最终一致性的问题了,比如采用补偿事务,重试等手段保证,这种手段微服务架构经常提到,比如saga事务等。这里**一定不会**用到分布式事务的强一致性算法,比如2PC等,所以潜在逻辑也说明,CQRS不适合做金融领域的余额等要求强一致性的业务) - Query端然后根据构建出来的数据实体的当前状态来构建物化视图(materialized view),这些视图结构要根据查询需求调整定制。这些视图都是只读的,这样可以最大化Query端的查询性能以及灵活性(到这里你会发现,Event sourcing很像比特币的UTXO模型了,Scala大神邓草原说过,区块链虽然落地困难,但是其思想或许提供了一个新的设计模式) 另外提一些细节:因为事件序列(Event sequence)是有顺序的,与UTXO模型很像,类似区块链里面的交易(Transaction)链,顺序一旦搞乱了,重放事件序列会有错误,所以每个事件有自己的ID和时间戳,Event ID需要关联到一个数据实体上,也就是说,该事件是对哪一个数据实体做的变更记录。也可以通过实体ID拿到关于它的事件序列,通过事件序列来重放(恢复)它的当前状态。 当然,还有更多的细节,可以看以下参考资料,或者结合自己的架构,工程经验来实现了,目前应该没啥捷径可走。 **参考资料**...
## 异地多活 异地就是指地理位置的不同,多活就是不同的地理位置上的系统都能够提供业务服务,这里的活是Active的意思。 这种方案真是要真正的大型互联网公司才有这种架构了,抗自然灾害能力比较强。 ### 异地多活架构 #### 同城异区 现在城市都有区嘛,昆明有五华,盘龙等。一般各个区的网络或者电路都是松耦合的。所以会在各个区部署多个机房,距离一般都是几十公里,通过搭建高速网络,能够实现和同机房的网络传输速度。如果该城市遭遇地震,水灾,一般就废了。 #### 跨城异地 业务部署在不同的城市的多个机房,距离最好远离些,因为能有效面对极端灾难事件。但是这样的架构复杂,而且网络传输速度会降低,因为现实世界都是各种路由和中转,不可控因素增加。比如广州到北京的正常情况下RTT大约是50ms,如果有网络抖动,RTT可能飙升到500ms甚至1s,如果还有线路丢包,那延迟可能就是几秒几十秒了。 既然物理世界决定了延迟不低,那么在这个时间窗口内数据不一致,还要能正常提供服务,这样就比较矛盾:数据不一致业务肯定不会正常,但是跨城异地肯定会导致数据不一致。 如何解决?重点还是在“数据”类型上,根据数据的业务特性来做不同的架构。如果是金融行业一些强一致需求,比如,银行存款余额,支付宝余额等,这类数据实际上是无法做到跨城异地多活的。所以对于余额这类数据,最多只能采用同城异区这种架构。 而对数据一致性要求不高,数据变更不频繁,甚至数据丢失影响也不大的业务,跨城异地多活就能用上了。比如,用户登录,新闻网站,微博,百度贴吧等等。 #### 跨国异地 业务部署在不同国家的多个机房。哈,这个距离一般更远了,网络延时更大,延时平均在几秒,对于用户感觉特别明显,很显然,这样的架构就连微博,贴吧都不适用了。一般用在为不同地区的用户提供服务,比如:微软的Bing搜索有国内版和国际版,亚马逊有美亚,日亚。还有一个场景就是,为只读类业务做多活,比如Google的搜索业务,爬虫爬到的那些网页索引,不需要实时,搜索结果基本相同,访问哪里都差不多。 ### 异地多活设计技巧 #### 1. 保证核心业务异地多活 前提不要犯一个错误:保证所有业务“异地多活”。这种显然是最终要完蛋的,有些业务特性做异地多活可能无解。 所以要优先实现核心业务的异地多活架构。 #### 2. 核心数据最终一致性 前提不要犯一个错误:所有数据实时同步。也是扯淡的。你应该考虑尽量减少数据同步,只同步核心业务相关的数据,保证最终一致性。 ####...
# 存储高可用 一般本质上都是通过将数据复制到多个存储设备,通过数据冗余的方式来实现高可用,其复杂性主要体现在如何应对网络延迟和网络中断导致的数据不一致的问题。 所以思考的问题是: - 数据如何复制? - 各个节点的职责是? - 如何应对网络复制延迟? - 如何应对网络复制中断? ## 主备复制 最常见的方案,也是最简单的。几乎所有存储系统都提供了主备复制的功能,比如MySQL,Redis,MongoDB等。 ### 基本实现 - 主机存储数据,通过复制通道将数据复制到备机 - 正常情况下,客户端无论读写操作,都发送给主机,备机不对外提供任何读写服务 - 主机故障情况下,客户端也不会自动将请求发给备机,此时,整个系统处于不可用状态,不能读写数据,但是数据没有全部丢失,因为备机上有数据。 - 如果主机能够恢复(无论人工恢复还是自动恢复),客户端继续访问主机,主机继续将数据复制给备机。 - 如果主机短时间不能恢复,则需要人工干预,将备机提升为主机,然后客户端访问新的主机。同时,为了继续保持主备架构,需要人工增加新的机器作为备机。 - 主机不能恢复的情况下,成功写如了主机的数据但还没有来得及复制到备机,那么数据会有丢失风险,需要人工进行排查和恢复,也许数据永远不在了,业务上需要考虑如何应对此风险 -...
# 网络高性能 高性能是所有程序员的追求,无论是做底层系统还是做应用App,我们都希望在成本内尽可能的优化性能。它是最复杂的一环,磁盘,操作系统,CPU,内存,缓存,网络,编程语言,架构都有可能影响系统整体达到高性能呢个,一行不恰当的debug日志就可能把一个高性能服务器拖慢成龟速。一个服务器配置的参数,比如tcp_nodelay就可能将响应时间从2ms延长到40ms。 站在架构的角度,当然需要关注高性能的架构,关注在两个方面: - 尽量提升单机服务器的性能,将单服务器的性能发挥到极致。 - 如果单服务器无法支撑性能, 设计服务器集群方案。 架构设计是高性能的基础,如果架构设计没有做到高性能,则后面的具体实现和编码能提升的空间有限。简单一句话就是,架构决定了系统的性能上限,具体实现细节决定了性能下限。 这里主要讲服务器端的网络高并发的性能 ## 单服务器网络高性能 关键之一就是服务端采取的网络编程模型,有以下两个设计关键点: - 服务器如何管理连接 - 服务器如何处理请求 以上两个设计点最终都和操作系统的I/O模型及进程模型相关。 - I/O模型:阻塞,非阻塞,同步,异步 - 进程模型: 单进程,多进程,多线程 ### one Process per connection 标题的字面意思就是,一个连接对应一个进程处理。每次有新的连接过来就新建一个进程专门处理这个连接的请求。大概是以下步骤:...
# 高性能存储 ## 关系型数据库 虽然IT行业这十几年取得飞跃式的发展,但是由于其强大的ACID事务特性,关系型数据库还是各种业务系统中的关键和核心存储。很多场景下的高性能设计也是关系数据库的设计。 各种数据库厂商,Oracle,MySQL,SQL Server在优化和提升单机数据库服务器的性能方面做了非常多的优化和改进。即使这样,这样的优化速度可能还是不能满足用户量增长,业务复杂的增加速度。所以必须考虑数据库集群来提高性能。 一个企业,考虑优化数据库的步骤应该是这样: - 首先优化SQL语句,避免多表Join,把SQL语句在业务层上拆分,并且优化你的表索引。 - 不行的话,再考虑Redis,memcached等数据缓存 - 如果以上两个步骤做好了,还慢的话,就往数据库的主从复制,主主复制,读写分离考虑。可以在应用层做,也可以用第三方组件,比如360的atlas等MySQL proxy。 - 如果还不行的话(公司牛逼,业务这么惊人,昆明有这样的公司吗?),先不要考虑分库分表,还没有到那步,MySQL自带分区表,可以试试这个。 - 分库分表---垂直拆分,垂直拆分比水平拆分复杂度低不少 - 分库分表---水平拆分,针对数据量大的表,实现复杂度最高,最考验技术水平,选择一个sharding key,要做一定冗余。就是sharding + MySQL方案。从抽象上来看,现代的NewSQL系统也是这么玩,比如PingCAP的TiDB + TiKV,只不过它们的sharding是做在了存储层,基于Google Spanner论文实现。 - 最终,上纯正分布式数据库方案,原生支持sharding,分布式事务等。比如PingCAP家的。或者OceanBase。不需要考虑那么多,主要是听说现在2019年了,大厂开源的数据库中间件没维护的很多了,各厂精力不在这里了,听说都是上了纯正分布式数据库。(不信不可以搜github,各厂的数据库中间件,commit更新频率惨不忍睹) 下面只会介绍关键点的细节。...
# 前言 近三个月一致在入门ZKP,算是半只脚迈入门槛吧,也同时在写一篇ZKP的博客文章 #3 (还没写完,两个月前开始的),顺带听了昨晚的讲座。 # 资料正文 我不会摘录我已经理解的科普级别的原理了,主要发Github的链接,或者其他的我关注的文本片段。下面主要是郭宇博士的文本语录: 零知识证明在学术界静悄悄地研究了30多年,在区块链领域一下子得到了广泛的应用。区块链中的TPS等性能问题,直接或者间接地都可以通过零知识证明解决。 以太坊上最近有一个名词特别火,叫做zkRollup, V神称为准二层协议,它是通过智能合约来构造一个虚拟的区块链,然后链下的一个服务节点处理业务,当然这个业务处理是需要经过零知识证明的,然后服务节点定期把证明和业务状态提交到智能合约,形成一个区块链的结构。 由于零知识证明有压缩计算的功效,这样可以把链下的许多业务处理过程压缩成一个很小的证明,然后智能合约只需要通过检查证明就能保证服务节点没有办法作弊。 这样就相当于实现了一个高性能的去中心化应用,经过这种方式,在现有以太坊架构上,实现几千TPS并不困难。 https://github.com/matter-labs/rollup 这是zkRollup的一个Rust语言的实现,有兴趣可以看看代码,清晰易懂。 以太坊上有一个Aztec协议,它可以实现erc20 token的隐私保护,之前我们一直喊:上链,上链!似乎上链数据就可信了,其实数据上链了也就泄露了。 数据不上链就没有信任,但是上了链就泄露,那就上零知识证明啊。采用ZKP技术可以同时做到看似两个矛盾的地方融合:数据上链校验和隐私保护。 Aztec Protocol代码在这里 https://github.com/AztecProtocol/AZTEC 最近还有一个特别火的项目叫做Coda,它可以通过零知识证明技术来压缩区块。现在以太坊全节点磁盘占用已经奔着4TB走了,感觉区块的增长速度要大于硬盘降价速度。特别是ETH 2.0部署之后,全网数据量还会加速增长。通过零知识证明可以有效压缩区块,降低新加入的全节点的同步难度。 手机节点怎么办,有一个项目叫做Celo,它通过零知识证明技术来实现区块链轻节点,而且并不丧失安全性。 最后介绍下,路印团队开发的去中心化交易所协议---Loopring v3。想必大家对中心化的交易所的问题都清楚,暗箱操作,黑客盗币,甚至跑路。如果未来的数字资产普及开来,这里肯定会出现大问题。 路印协议可以做到,万一交易所跑路,用户的数字资产安然无恙,可以从容提币,基本可以说,100%保证用户的数字资产安全。 路印协议是基于zkRollup的思想,现在初步性能已经可以做到6000 TPS,这已经千倍于之前的DEX协议,这都归功于零知识证明这个强大的工具。 当然为了实现交易的撮合,链下的所有业务逻辑为了做零知识证明,都是由电路逻辑来编写,我们团队前后花了三个多月来检验这个交易所业务逻辑的可靠性,工程非常浩大,期待Loopring早日上线,彻底解决交易的安全问题。...
--- title: 用马尔科夫链来做自动补全 date: 2019-03-10 15:26:00 tags: - 马尔科夫链 - 自然语言处理 --- ## 前言 马尔科夫链是个什么呢?如果你去网上搜索, 噼里啪啦一堆公式,可能你会看的不耐烦了。当然,你可能见到有些人总结了一句经典的话,比如: - 如果将下一个状态的依赖条件,简化成:仅取决于当前状态,和之前其他状态无关。那么,这个随机过程就是马尔可夫链。 - 今天的事情只取决于昨天,而明天的事情只取决于今天,与历史毫无关联 当然,你可以在[知乎这里](https://www.zhihu.com/question/26665048)看到更多的解释。 这样的性质就给我们带来了预测下一个状态带来了可能,比如天气预报,智能联想提示等等。 今天我们就用python来用马尔科夫链来做点有实际意义的事情,用更直观的角度理解它。 正文是我用python脚本来分析了一本英文书,把这本书的英文句子作为一个训练集,用[马尔科夫链](https://en.wikipedia.org/wiki/Markov_chain)来做处理产生短文,短文句子有一定“联想”,这样也可以算作是一个自动补全的程序了。比如,一些聊天工具和输入法可能就有这样的功能,基于你以前历史的语句输入来判断你当前输入后面可能会输入的单词或语句作提示或者补全。 网络社区也有一些爱好者用[马尔科夫链来生成鸡汤文](https://blog.csdn.net/renhaofan/article/details/82191387), 都算是一定性质的科普文章。 ## 正文 首先,需要随便下载一个英文小说或者书籍来作为训练集合,英文当然越正宗越地道越好,这样的数据质量比较高,之后生成的段落语句结果也更好些。这里我下载了[哈利波特1-7的英文txt](http://vdisk.weibo.com/s/uiFtZjZIxy3Gz)。哈哈,英文原版我只读了第一部魔法石,惭愧啊。 ```python...
--- title: C++11之函数式风格编程 date: 2017-03-3 10:48:40 tags: - C/C++ - 函数式编程 --- > *C++是多范式编程语言,程序员可以选择多重范式的结合来编程,比如面向对象,面向过程,泛型编程,函数式特性。尤其是C++ 11标准中完善了函数式的一些特性,比如,lambda表达式,变参模版,新的STL函数bind。下面就讲讲怎样用C++ 11来写函数式风格的代码。* # 函数式风格编程 - 自动类型推导,auto和decltype - lambda表达式的支持, 闭包,函数即数据 - 偏函数应用(partial funtion application),std::function和std::bind,lambda表达式和auto - STL与高阶函数的组合 -...