zoukankan      html  css  js  c++  java
  • 专访阿里陈康贤:我所理解的网站架构

    陈康贤(花名龙隆,博客),淘宝技术部技术专家,著有《大型分布式网站架构设计与实践》一书,在分布式系统架构设计、高并发系统设计、系统稳定性保障等领域积累了较为丰富的实践经验,对新技术有浓厚的兴趣,目前负责阿里直播平台的建设,新一年的校招及社招也已经开始,有兴趣加入阿里直播平台的朋友,欢迎发送简历至longlong@taobao.com ,有很多岗位可以选择,期待与大家有更多的交流。

    避免失败是所有工程技术的核心

    CSDN:你个人对架构/软件架构的理解是?

    陈康贤:以下仅是个人的一些理解,架构不仅仅融合了思想,融合了技术,同时也融合了艺术,好的架构并不仅仅是停留在技术文档里,而是在实践的过程中不断地修正和调整的,这对架构师也提出了更高的要求,仅仅是停留在抽象和概念阶段是没有太大价值的,细节是魔鬼,一些从抽象层面看起来比较简单的架构,实际上最大的挑战往往来自于细节,这些细节既包含产品视觉交互功能的实现,也包含业务规则、风险等种种逻辑的处理,还包括技术上的一些难以预知的“坑”,具体的技术方案在实施的过程中,可能需要花费大量的时间跟精力去解决和避免那些极端情况下可能出现的问题。

    架构应该满足一段时间内的业务发展,但是这一段时间到底有多长,有说三个月,有说半年,有说一年,也有说三年,不同的人不同的环境对于这个问题的理解可能不同,创业型公司,或者是尝试型的业务,风雨飘摇九死一生,优先考虑的是业务模式而非技术架构,因此,此时的架构应该尽可能简单尽可能容易实现,三个月之后业务变成什么样子甚至是否存在,还很难说,这个时候去想三年之后的架构,基本上也是天马行空,对于比较成熟的业务,或者是对之前稳定的业务系统进行重构,则需要将眼光放长远些,避免一些在中长期可能面临的问题,比如数据库的分库分表数量,ID的长度,分库分表的维度等。

    另外就是系统需要可扩展,在设计时要留有一定的扩展点,避免稍有变更就需要整个系统重构的情况出现,对扩展开放,对修改封闭,实际上这很好理解,修改原有的系统而不是扩展原有的系统,更容易引入新的问题,也会带来更大的测试工作量。一段时间之内架构的演变,常常会经历从清晰,再到模糊混乱,再重构,再清晰,然后又变得模糊的过程,市场环境总是瞬息万变的,因此,系统的设计要遵循对扩展开放,对修改封闭的原则,做到这点即可方便及时的接入新流程,又能够不影响既有的流程。

    从宏观来看,各个系统间的关系一定不应该是烟囱与烟囱的关系,而是犹如城市里的高楼大厦,通过公路连接起来,因此,要提高建房子的速度,就要充分利用已有的基础设施,已有的中间件,来降低系统构建的成本和风险。

    架构设计的几个层次,没有架构也是架构,专注于解决现有问题也能称为架构,而好的架构应该是即能够约束开发者又能够解放开发者使其专注于功能的设计。尽量将复杂的事情变的简单,而不要将简单的事情变的复杂,技术从来都不是用来炫的,而是用来解决实际问题的。避免失败是所有工程技术的核心,架构也是技术,要运用架构技术去缓解风险。

    分布式架构 VS. 集中式架构系统,以及思考

    CSDN:分布式系统架构是一个非常广发的概念,他有着怎样的特点,以及在网站何时要用分布式?另外它有哪些的场景?

    陈康贤:分布式架构实际上是解决了集中式架构系统能力进一步向上扩展的所面临的瓶颈,这些瓶颈包括资源、运维、开发维护等,因为单机的硬件受到技术条件的限制,越往上扩展,成本可能并非是线性的而是指数级的,分布式架构通过大量廉价的PC Server集群,使得能力的扩展与经济成本的关系再次回归线性,另外当开发团队的规模越来越大,业务越来越复杂,分布式及服务化也使得系统能够更好的进行拆解,让更多的团队能够更高效率的在一起协作。

    但是,从另一个角度来看,分布式架构也是一种复杂的架构,很多传统架构下面可以弱化的问题,在分布式环境下变得凸显,甚至是成为至关重要的问题,比如数据一致性问题,比如网络通信、序列化、延时问题,比如如何应对失败的问题,传统环境下数据一致性通过数据库事务在相当程度下被弱化了,而分布式环境下将成为一个非常复杂的问题,另外就是分布式架构使得集群内部的网络通信变得更加频繁,通信协议、序列化方式、通信延迟、容错、性能这些都会变得复杂化,分布式环境下的失败将成为常态,如何处理这些失败也会变得一个非常复杂的问题,一个成熟的分布式架构体系所依赖的基础设施很多,从各种中间件,到自动化运维体系,监控体系,容灾体系,这些都需要一段时间的积累,并且持续投入和付出,因此,在考虑分布式架构的同时,也需要从投入产出以及回报角度综合考虑,对于创业公司来说,需要想清楚优先要解决的问题是什么,再来思考企业需要什么样的架构,一味地参考大公司的架构,可能会提前让系统变得过于复杂,失去响应灵活的特点,从而失去竞争力。

    我所理解的网站架构

    CSDN:大型网站架构设计的思想与原则是什么?

    陈康贤:实际上很难说有个一个统一的思想和设计原则,能够放之四海而皆准,因为每个人对于设计的理解和理念是不同的,个人觉得设计一个复杂的大型网站,实际上是一个分而治之的过程:

    首先得充分的理解业务,理解需求,理解当下需要解决的首要问题,以及可能的风险有哪些,再将目标进行分解,进行具体的技术选型、模型设计、架构设计。如果需要解决的核心问题是并发,则可以通过各种缓存手段(本地缓存、分布式缓存),来提高查询的吞吐,这样虽然会一定程度上需要在数据一致性上做出牺牲,由强一致性变为最终一致性,但是,如果数据一致性不是核心需要解决的问题,那么,此问题的优先级则可以先放一放,反过来如果核心问题变为数据的一致性,如交易系统,那么再怎么强调数据的一致性都不为过,由于分布式环境下为了应对高并发的写入以及海量数据的存储,通常需要对关系型数据库进行分库分表扩展,这也给数据一致性带来了很大的挑战,原本的单库事务的强一致性保障,在这个时候升级为跨库的分布式事务,而通过二阶段或者三阶段提交所保障的分布式事务,由于分布式事务管理器与资源管理器之间的多次网络通信成本,吞吐及效率上很难满足高并发场景下的要求,而这实际上对于交易系统来说,又是一个很难回避的问题,因此,大家又想出很多的招来解决这个问题,通过可靠消息系统来保障不失为一种方式,变同步为异步,但是,又引入新的问题,消息系统为保证不丢消息,则很难保证消息的顺序性以及是否重复投递,这样作为消息的接收方,则需要保障消息处理的幂等性,以及对消息去重。

    个人比较推崇洛克希德·马丁公司的著名飞机设计师凯利·约翰逊所提出的KISS原则,架构设计能简单绝不复杂,坚决砍掉任何华而不实的设计,不要因为3年后可能怎样甚至是一些现实中根本无法出现的场景,加入到当下的架构设计中,导致系统无比复杂。有时候看似引入的是一个很简单很容易解决的问题,可能在具体的执行过程中,会因此带来一系列不必要的麻烦,按下葫芦起来瓢。

    另外一点就是对于未经验证的新技术、新理念的引入一定要慎重,一定要在全方位的验证过后,再大规模的使用,新技术、新理念的出现,自然有它的诱惑,慎重并不代表保守,技术总是在不断前进,拥抱变化本身没有问题,但是引入不成熟的技术看似能带来短期的收益,但是它的风险或者是后期的成本可能远远大于收益。

    CSDN:设计一个大型网站架构时,通常需要从哪些层面去考虑?服务器/存储部署方面需要注意哪些问题?

    陈康贤:大型网站的设计是一个非常复杂的问题,需要考虑的问题很多,比如海量数据的存储,存储又分为在线存储与离线存储,在线又有关系型数据库存储和非关系型数据库存储,持久化存储和内存存储,这些都需要架构师根据具体的场景进行选型。

    高并发且允许数据丢失的情况下,可以采用内存存储,而查询条件单一,只需要根据主键进行查询,则可以选择key-value型的存储,对于海量的文档及图片内容,则可借助分布式文件系统以及CDN边缘节点,即解决了存储的问题,又能够将冷热数据分离,并且通过边缘节点提高用户访问的效率,如果是需要多维度的复杂查询,则需要使用关系型数据库。当数据量大,并发写入请求多的时候,又需要进行分库分表,由于分库分表会限制数据的查询维度,查询条件必须得带上分库分表的键,如果需要多个查询维度,则需要使用数据同步工具同步出另一维度的数据结构,或者是搭建垂直搜索引擎,以提供多维度的数据查询,很多情况下难以通过一种存储工具解决所有问题,因此需要多种存储复合使用,以提高效率及用户的使用体验。

    再又如应用的部署,从集中式架构到分布式架构,SOA服务化,再到时下流行的微服务架构,接入层的负载均衡设备解决了无状态WEB应用的扩展问题,而软负载中心则解决了服务发现和服务路由的问题,轻量虚拟化及docker的出现使得Martin Fowler所提出的微服务理念能够更容易成为现实,当然,大型网站还需要考虑比如某个地域出现不可抗力因素时,如何保障整站的可用性以及数据完整性,诸如同城容灾,异地容灾(如两地三中心),以及时下正处于风口浪尖的异地双活、异地多活架构。

    大型网站的架构往往不是一蹴而就的,而是通过需求的推动经过多年演变一步步形成的,不同的时期不同的阶段不同的规模,所面临的业务不同、需求不同、需要解决的核心问题也不同,这就导致不同的阶段不同的架构,并且架构也是不断演进与发展的。

    CSND:大型网站有哪些典型的故障以及通常有哪些解决之道或相应的优化建议呢?

    陈康贤:一个成规模的网站可能每天都在经历故障,只不过故障可能在绝大部分人感知到之前就已经修复了,导致故障的原因很多,有可能是业务逻辑的变更对于依赖的测试不充分,或者是不兼容的版本升级导致的序列化错误,又或者是测试用例未覆盖到的程序bug,又或者是不同版本jar包的同名类冲突问题等等,也有可能是访问量太高导致日志将磁盘打爆,又或者是机器负载过高导致大量线程阻塞,又或者是锁竞争过于激烈导致进程僵死,或者是数据库连接池用完,JVM频繁GC等等。

    另外也有可能是由于物理环境问题,比如网线被拔掉,光纤被挖断,机房停电,硬件设备损坏等等,导致故障的原因可能千奇百怪,很难一一枚举,对于变更所导致的故障,能做的是让测试用例尽可能全面的覆盖到每一个细节,包括依赖项,项目设计阶段多考虑风险,按照流程来发布,但是也不能因噎废食,使得发布流程沉重僵化,对新的业务需求响应缓慢,实际上这也是一个很难拿捏的度。

    此外就是要建立起完善的监控系统,包括异常日志收集分析,业务流程全链路校验,机器运行状态检测(负载、qps、磁盘、内存、网络、运行水位),历史数据的分析,异常报警等,对于服务化的架构,还需要完善服务治理,包括强弱依赖管理,调用关系(谁调用了谁,谁被谁调用了),调用频次,异常状况等,这实际上是一个体系化的工作,也是一个比较基础的工作,有了这些之后,你才能够及时的感知到系统的异常状况,及时定位问题,修复问题。

    CSDN:构建一个网站时,可以选择开源或自主研发,前者因万一选用的开源方案在将来才发现某一些特性不满足,就得推倒重来,而后者则似乎有重复造轮子的嫌疑,对此你怎么看?

    陈康贤:这个问题得辩证来看,使用开源能够降低很大的工作量,但是也会存在潜在的风险,特别是一些未得到广泛验证的技术,即便是使用的十分广泛的如Struts、SSL,也时不时会爆出一些惊人的漏洞,对于小公司来说,使用开源的技术能够快速的构建出一个勘用的网站,即便是在使用开源软件的过程中遇到问题,切换的成本可能也不会很高,但是对于大公司而言,切换的成本可能会变得非常的高,因为业务和依赖关系实在是太复杂,一旦大规模使用,影响的范围可能非常广,因此在做选择之前不得不非常之慎重,当然,我们也会有一些比较特殊的需求,开源软件无法满足,或者说是走在了开源的前面,这些工具、中间件就需要自己动手开发了。

    另外就是开源的软件有些特性实际上与我们的期望有很大的差距,而他们本身的架构可能又不是那么方便扩展,但是这些特性对于我们来说又十分的关键,比如Hadoop,它的MapReduce、HDFS、Hive提供一整套海量数据的分析解决方案,但是底层的权限控制做的很弱,因此我们不得不花了很大的精力开发出一套替代方案,又花费很大的精力将原来Hadoop上的数据和Job迁移到新平台。对于开源技术的选择,我们更倾向于选择一些社区比较活跃比较成熟的软件,最好是有一些比较成规模的成功案例的,这样的风险会小一些,毕竟对于一家成熟的电商网站来说,稳定大于一切,系统的不可用时间是跟成交金额直接关联的,分分秒秒过去的时间,就是实实在在的金钱。

    对于较为核心的应用所引入的开源技术,我们也会花费较大的精力深入地去了解,做一些bugfix,避免踩到一些坑。

    另外一点就是大公司的很多场景可能是非常特殊的,比如高并发场景下的MySAL数据库行锁,大对象常驻内存时的JVM的内存回收,一些软件可能为了满足通用的需求,牺牲了一些特殊场景下的性能。因此,对于我们来说,了解这些后,也是有一定的优化空间的,包括从实现上去规避,或者是去改造开源软件,而做这些的前提就是对开源软件的了解。

    CSDN:一般网站面临的问题就是负载的问题,当人数多,导致速度慢是主要解决的问题,对此你有什么建议?

    陈康贤:相较于传统企业来说,大部分互联网企业都会面临的一个很大的挑战,随着用户规模的不断扩大,系统的压力会越来越大,而在创业初期,系统的架构设计往往是一切从简甚至根本没有架构,快速迭代,优先满足业务,而受市场环境的影响业务往往是多变的,因此往往会背下“技术债”,业务逻辑高度耦合,系统不可扩展,代码结构臃肿,此时不得不进行重构。

    “分布式”是应对大流量核心思想,首先,系统得做好准备,支持扩展,尤其是在数据、模型层面,因为数据的拆分、扩容、数据迁移最麻烦最费时间,稍有不慎,还可能导致数据不一致,造成的损失也有可能是无法挽回的,方案设计必须得慎之又慎,在数据拆分迁移的同时,新的数据正在源源不断的写入,老的数据也常常会面临高并发的更新,因此,业界经常将数据拆分扩容比喻成是在给一架高速飞行的飞机换引擎,这也是整个扩容过程中,最复杂,技术含量最高,最有挑战的任务。

    再就是集中式应用的业务逻辑拆分,原先团队规模小,业务量也小,可能会在少数几个应用上堆了很多代码和业务逻辑,而随着公司规模的增长,业务迅速发展,团队规模越来越大,集中式的应用维护将会变得十分困难,这既包括开发部署,笔者曾经开发过一个应用,改几行代码,本地编译打包需要10几分钟,本地部署又需要十几分钟,这极大的降低了开发的效率,另外这样的巨无霸工程也会占用很多服务器资源,而单机的硬件资源又不可能无限升级,这也会是一个问题,再者就是耦合的业务逻辑也不便于复用,得四处重复造轮子,浪费资源,这又引申出另一块,也就是企业内部的服务化。

    SOA架构包括时下流行的微服务理念,解决的是企业内部资源复用的问题,避免信息孤岛和重复造轮子,提高系统可维护性,降低业务试错以及系统构建成本,提升企业竞争力。通用的统一的SOA通信标准,包括通信协议、序列化反序列化方式,能够简化SOA架构的实现,服务的自动注册、路由、软负载能降低运维成本,随着服务的增加,单靠人工来进行服务治理越来越困难,又衍生了服务治理系统,对服务的调用,依赖,异常等信息进行统一的管理。当应用变得无状态之后,扩容就非常方便了,通过负载均衡软硬件设施,或者是SOA的软负载机制,可以根据需要十分方便的增减机器扩充容量,而这种能力几乎是线性的(在一定规模下)。当然,大部分的场景以及技术解决方案,国外的Yahoo、Google、Facebook、Linkin 、Twitter…,国内的BAT,这些知名的互联网企业,实际上很大程度上已经充当先驱,后来的追随者,只需要紧随前人的脚步,蓦直前行,架构的风险已经被大大的降低。

    架构师的技能或素养,架构师到底要不要写代码?

    CSDN:成为一名架构师需要哪些的技能或素养?

    陈康贤:以下仅代表个人观点,设计符合要求的系统是架构师的基本技能,功能、可用性、可扩展性,以及团队能力、项目执行风险、运行环境都需要综合考虑,架构师的功力更多体现在技术的综合运用上,因此对于项目所需要的技术细节的了解必须是全面的,这样才能够将最合适的技术用在最需要的地方,并且还需要有技术的前瞻性,通过经验以及积累发现可能潜在的风险,对于问题的理解,不能够仅停留在表面,逻辑思维和抽象思维能力是一个架构师的重要素质。

    当然,作为架构师还需要一个非常重要的技能,就是充分的沟通,完成系统的设计只是万里长征的第一步,设计思想需要充分的传达给团队中,并且从团队中得到相应的反馈,对方案进行调整,不断完善,只有在团队中所有人都了解领悟了你的设计之后,后续的推进包括项目的实施才能够变得顺畅,细节是魔鬼,在后续的执行过程中,可能会面临各种问题,涉及到的方案调整,沟通协调是不可避免的,作为架构师来说,需要有充分的准备,好的架构师能够带领团队高歌猛进,而不称职的架构师最终会导致矛盾重重,对于合作的团队来说,需要确认可能的风险,包括接口,时间节点,兼容性,对接可能遇到的技术问题,对于可能遇到的风险,架构师必须了然于胸,提前准备,从容应对。

    Linus Torvalds说,

    Talk is cheap, show me the code.

    但是我想说的是,

    Talk is not cheap, talk is important too!

    很多人会问,架构师到底要不要写代码,首先,个人认为,架构师是需要写代码的,无奈时间是有限的,项目的规模越大,所需要思考的细节点越多,自然而然花费的时间越多;除此之外,作为架构师的你还需要传播布道,告诉所有人你理解的架构是什么样子,告诉大家怎么做如何做,核心的目标是什么,核心的风险是什么;架构师还需要协调各个依赖的关联系统,告诉其他人你要做一件什么事情,需要其他人怎么配合,做这件事的价值以及其他人为何要配合你,这同样需要花费大量的时间,那么,在剩下不多的时间里,架构师能写的代码可能不多,但是,为了让你设计的系统不脱离现实,你必须写代码,必须Review核心关键代码,确保整体架构的思路得到贯彻,确保你的设计是易于实施的,确保潜在的风险得到妥善的控制,特别是在有新技术引入的情况下,原型验证是必不可少的步骤。有种观点认为,架构师必须是代码贡献最多的,一个人写代码,自然不需统一思想,但是实际上这很难做到,作为架构师你得记住,不是你一个人在奋斗,不要让自己成为团队的瓶颈,但是,我同样也不赞成架构师完全不编码,不亲身体验过,有的风险是很难事先做出判断的,何况技术本身也在发展,今天的经验放在明天不一定有效,作为程序员的最基本技能,编码是你学习和积累的最直接的方式。

    架构师也是一个普通人,一天只有24小时,需要花费很多时间进行方案设计,技术合理性思考,原型验证,还需要花费大量的时间给团队传达设计思想和目标,为何这样设计,这样设计有什么好处,不这样设计会有什么样的问题,人是最复杂的生物,程序员都是非常有个性并且非常聪明的,统一思想统一目标是一个非常艰巨的任务,一千个人心中有一千个哈姆雷特,同样,做一件事情可能也有不同的方法,方法太多有时候并不是好事,作为架构师,需要找出最合适的方法,并让它得到大家认可,这并非是把个人目标转化为团队目标的过程,而是不断地沟通不断的改进演化之后,在大家充分参与的前提下找到的最适合当前业务场景的方案。

    CSND:对未来你有着怎样的规划和期许?

    陈康贤:技术这条路注定不是坦途,码农大多数时候的生活是枯燥无味的,并且这又是一个学无止境的行业,技术的更新换代非常快,失败的纠结,苦思冥想的无奈,成功的喜悦,其中的酸甜苦辣,我想只有真正的码农才能体会。

    近期来看,应该会继续专注于直播,阿里在电商领域积累了丰富的经验,但是对于直播来说还属于一个有待成熟的领域,还有很大的提升空间,技术挑战也是比较大的,后续希望能够做一些事情,降低直播的门槛,降低资源的消耗,提高服务的稳定性。 就跟《战争之王》这部电影里尤里·奥洛夫(Yuri Orlov)的经典台词所说的一样,人总想在有生之年做件大事,只是暂时还没想好要做什么,诚然,我不会跟尤里一样去贩卖军火,社会的发展和变化太快,很难预料自己五年之后会专注于什么,从事哪方面的工作,但是,作为一个热爱技术,喜欢专研的人,应该还是会是做跟技术、跟工程能扯上点关系的事情。

    CSDN:最后,想给看这篇文章的读者说些什么?

    陈康贤:当初毕业找工作的时候,说实话也没想过说一份工作会干这么长时间,而且后面可能还要继续做下去很长时间,实际上毕业的第一份工作非常重要,因为当你开始工作之后,你将不再是一张白纸,而你后续再去找工作的时候,前面的工作经历将会是很重要的参考,第一份工作将很大程度影响你后续工作的大方向,后续再想要转型,可所付出的努力和冒的风险可能更大。

    选择有时候很重要,首先得清楚自己喜欢做什么样的工作,因为做自己喜欢做的事情,你更愿意付出,不会觉得辛苦,更不会觉得痛苦,而是乐在其中,工作是一件长期的事情,因此,值得你好好想想自己到底喜欢做什么。

    另外就是看后续的成长空间,一滴水到了一杯奶中,水就变成了奶,一滴奶到了一杯水中,奶就变成了水,有可能某个公司A给你的offer多了1-2K,而公司B却能够提供给你一个更大的舞台去发挥,去成长,给你提供一套系统的培训和成长体系,并且周围都是业界大牛,此时的选择,考验着你的智慧。

    短期的1-2K,从长远来看,实际上真的不算什么,但是损失可能是长期的发展空间,那有人说,工资给的高不说明更重视么,话虽没错,但是去到一个没有发展空间的公司,或者已经是夕阳产业,也许你确实很优秀,可能你的高度就代表了公司最高的高度,那么你的空间在哪,这实际上是一个鸡头凤尾的抉择问题,选择一个更有空间更有潜力的公司,可能刚开始你在团队中并不是那么出色,但是,认真工作几年后,你再出去跟同龄人比,区别还是蛮大的,并且,优秀、成熟的公司会有一套相对公平的评价机制,总的来讲,会让足够优秀并且给公司创造更多价值的人,得到相应的回报,所以也不用担心回报的问题。实际上HR也不傻,你得到的回报可能是经济上的回报+成长空间的总和,而两部分加起来,大部分公司给出的价位应该是差不多的。

    机会是总是留给有准备的人,选择很重要,坚持有时候也很重要,做事情得要能沉的下心,不要怕困难,人生就像骑单车,想保持平衡就得往前走。

    希望前面所说的内容能够对大家有所帮助,也欢迎大家跟我交流。

    陈康贤的联系方式:

    Email: longlong@taobao.com

    sina微博: 淘宝龙隆

    (责编/钱曙光,关注架构和算法领域,寻求报道或者投稿请发邮件qianshg@csdn.net,交流探讨可加微信qshuguang2008,备注姓名+公司+职位)

    「CSDN 高级架构师群」,内有诸多知名互联网公司的大牛架构师,欢迎架构师加微信qshuguang2008入群,备注姓名+公司+职位。

    2016年3月18日-19日,由CSDN重磅打造的数据库核心技术与实战应用峰会、互联网应用架构实战峰会将在上海举行。这两场峰会将邀请业内顶尖的架构师和技术专家,共同探讨高可用/高并发系统架构设计、新技术应用、移动应用架构、微服务、智能硬件架构、云数据库实战、新一代数据库平台、产品选型、性能调优、大数据应用实战等领域的热点话题与技术。

  • 相关阅读:
    Spring@Profile注解
    day 32 子进程的开启 及其用法
    day 31 udp 协议SOCK_DGRAM
    day 30 客户端获取cmd 命令的步骤
    day 29 socket 理论
    day 29 socket 初级版
    有关 组合 继承
    day 27 多态 接口 类方法 静态方法 hashlib 摘要算法模块
    新式类和经典类的区别
    day 28 hasattr getattr serattr delattr 和带__内置__ 类的内置方法
  • 原文地址:https://www.cnblogs.com/zhanghaiyang/p/7213187.html
Copyright © 2011-2022 走看看