热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《企业迁云实战》——3.4应用改造实践

3.4应用改造实践在完成阿里云上应用系统架构设计后,开始进入实施阶段,对应用系统进行架构和代码级的编码改造实施工作。3.4.1应用架构改造在应用架构

3.4 应用改造实践

在完成阿里云上应用系统架构设计后,开始进入实施阶段,对应用系统进行架构和代码级的编码改造实施工作。
3.4.1 应用架构改造
在应用架构改造中,主要涉及负载均衡改造、Web和应用层改造、服务化改造几方面问题。
1 . 负载均衡改造
原有系统Web、应用服务器采用硬件负载均衡设备F5或开源LVS实现Web、应用服务器负载均衡。迁云时需要改造为云上SLB负载均衡服务。云上SLB服务可以支持TCP、HTTP、HTTPS等三种协议实现流量负载均衡,同时支持自动对Web、应用服务器进行健康检查,自动屏蔽异常状态的服务器,在服务器恢复正常后自动解除屏蔽重新提供服务。如图3-10所示,整个业务架构中将硬件负载均衡设备F5或自建LVS集群改造为SLB负载均衡服务。

image

2 . Web和应用层改造
如果原系统Web、应用部署在小型机、PC Server、商业或开源虚拟化服务器上,则可直接部署在云上弹性计算服务ECS上。目前ECS可支持多种Linux和Windows类型的操作系统。为保证Web、应用服务的高可用性,建议同一类服务至少部署在两台ECS服务器上,使用SLB实现负载均衡和服务容错。图3-11给出了Web和应用层架构改造的示意图。
3 . 服务化改造
对应用系统进行服务化改造,可使用消息中间件来实现业务系统的解耦,通过对数据库按不同业务进行拆分提升数据库的性能。例如,淘宝的系统架构充分使用了服务化设计思想和消息中间件产品实现业务系统的服务化设计和解耦。图3-12给出了业务服务化改造的过程。

image

image

在图3-12的架构图中,消息中间件主要的应用场景包括:
分布式事务:为面向服务架构实现最终一致性的分布式事务提供支持,保证全局数据的最终一致性。
延时队列:把消息中间件当做可靠的延迟队列。
广播通知:把消息中间件作为可靠的集群内广播通知,用于通知cache失效等事件。
3.4.2 数据库改造
数据库改造分为OLTP类关系数据库架构改造和OLAP类关系数据库架构改造,下面分别介绍这两类情况下的改造方案。

  1. OLTP类关系数据库架构改造
    对于访问量比较小的基于关系数据库的系统,系统架构如图3-13所示。

image

随着业务压力不断增大,单个RDS的读写已经无法满足业务访问请求的时候,尤其是读压力非常大的系统,可以考虑使用阿里云Memcahe或Redis缓存系统来分摊读压力,通过缓存热点数据来提供快速访问,详细架构如图3-14所示。
对于读压力较大的场景也可以考虑通过增加RDS只读实例,将系统改造成读写分离的应用架构。特别是对于有些数据分析类的场景,读写分离也是非常有效的解决方案之一。采用读写分离架构对业务读能力进行扩展改造时,业务人员需要对业务系统进行评估,将系统中对延时不敏感的业务切换到到只读实例访问。数据库读写分离架构如图3-15所示。
考虑到RDS存储容量不超过2T的限制,以及RDS单实例的性能瓶颈,当数据库的单实例存储空间无法满足或写入的TPS接近数据库能力上线时,数据库通常需要做垂直与水平拆分,垂直拆分是指根据不同业务类型或功能将数据库拆分到不同的RDS实例存储,水平拆分是指将同一类业务或数据通过一定的路由规则存储到不同的RDS实例中。数据库拆分的难度通常比较大,需要考虑如何做业务切分。当业务切分后,数据会分布到多个节点,导致一系列分布式问题,如分布式事务、跨库查询、全局唯一ID等,所以在进行数据库架构设计或改造的过程中,我们应尽量减少拆分,降低应用实现的难度。如必须拆分,可遵从先做服务化改造以进行数据库垂直拆分,再考虑进行数据库水平拆分。

image

image

阿里云平台上的分布式数据库服务DRDS提供数据库水平拆分和读写分离功能。它尽量屏蔽了分布式对应用开发的影响,同时也帮助用户在一定程度上解决了数据库水平拆分导致的全局唯一ID、跨库查询、分布式事务等问题。DRDS数据库水平拆分和读写分离原理如图3-16所示,同一张表的数据通过一定路由策略和算法均衡的分布到多个RDS读写实例,并通过DRDS的读写分离功能自动帮用户将读流量路由到只读RDS实例。

image

2 . OLAP类关系数据库的架构改造
OLAP联机分析处理类型系统是数据仓库系统最主要的应用类型,用于支持复杂的分析操作,侧重对决策人员和高层管理人员的决策支持,可以根据分析人员的要求快速、灵活地进行大数据量的复杂查询处理,并且以一种直观而易懂的形式将查询结果提供给决策人员,以便他们准确掌握企业的经营状况,了解客户的需求,制定正确运营方案。
阿里云针对OLAP联机分析处理类应用的规模大小有不同的解决方案:
小规模分析系统:这类OLAP系统仅针对具体某一类业务的历史数据进行离线和实时数据分析,一般数据量在1TB以内,分析所使用的数据在十个维度以内,对数据分析的时效性要求较低。对于这类应用系统,一般可直接采用RDS关系数据库作为底层的数据存储系统,并在其上构建OLAP分析工具。
大规模实时数据分析:这类OLAP系统面向数据存储规模在TB级别以上,单表记录数达到千亿级别,业务对数据分析时效性要求较高,一般需要秒级内返回结果的系统可通过阿里云实现大规模数据分析存储系统AnalyticDB构架实时分析系统。
大规模离线数据分析:这类OLAP系统面向数据存储规模在TB、PB级别以上,单表记录数亿级以上,需要做非常复杂的计算操作,业务对数据分析时效性要求较低,一般在分钟级返回结果的系统。此类业务可基于阿里云MaxCompute大计算产品构建离线分析系统。
3.4.3 文件存储改造
传统行业通常采用SAN、NAS、关系型数据库存储文件或图片等数据。但SAN方案成本过高且扩展性受限,NAS无法保证高性能,关系型数据库存储文件成本高且严重影响应用系统性能,因此给存储带来一定困难。阿里云OSS开发存储服务(Open Storage Service)能提供海量、安全、低成本、高可靠的云存储服务,适合存放文件、图片等非结构化数据。同时,OSS提供Java、Python、PHP、C#语言的SDK。用户可以通过调用对应开发语言的API,在任何应用、任何时间、任何地点上传和下载数据,也可以通过Web控制台对数据进行管理。
在OSS中,用户的每个文件都是一个Object(对象),Object包含key(关键字)、data(数据)和user meta(用户元组)。key是Object名,user meta是对数据的描述。存储在OSS上的每个Object必须都包含在Bucket中,Bucket名在整个OSS中具有全局唯一性且不能修改。
从其他文件存储产品迁移至OSS上时,只需要使用阿里官方提供SDK和API接口替换原有接口即可。
OSS使用的场景包括存储文件、图片、视频等非结构化数据;存储应用系统日志、数据备份;替换用户自建文件存储系统。
图3-17给出了OSS的业务架构,基于OSS构建面向文件对象的存储系统架构的特点如下:
OSS负责存储文件、照片、视频等海量非结构化数据。
RDS负责存储业务系统所有的结构化数据,包含文件、照片、视频等非结构化数据OSS访问地址或索引。
基于OSS构建独立的文件存储管理系统,应用程序可使用SDK或API方式与OSS存储服务对接,实现对文件、照片、视频等非结构化数据的管理。在整个文件系统的存储架构中,应用系统设计者无须考虑系统的高可用、性能和扩展能力,这些都会由底层OSS对象存储服务来保证。
(1)OSS主要访问接口
OSS为用户提供数据存储服务,用户可以通过以下API接口和SDK来管理和维护OSS上的数据:
OSS Bucket相关接口:可支持Bucket创建、查看、罗列、删除以及修改、获取Bucket的访问权限等操作。
OSS Object相关接口:可支持Object对象上传、查看、罗列、删除,并支持大文件分片上传等操作。
OSS访问相关:支持If-Modified-Since和If-Match等HTTP参数。
OSS支持Object生命周期管理,用户可自定义OSS上存储数据的过期时间,在到期后,OSS会自动帮助用户完成过期数据清理和空间回收。
OSS支持防盗链,采用基于HTTP header中表头字段referer的防盗链方法。
OSS支持使用STS服务临时授权和URL签名授权访问。
OSS提供相应接口,方便开发者控制跨域访问的权限。

image

(2)OSS文件存储接口改造
OSS提供两种访问方式:SDK和API接口。目前已支持SDK的开发语言有:Java、Python、Android、iOS、PHP、.NET、NodeJS、C SDK开发包。如使用其他语言,需要用户自己封装API接口。
对于原来采用文件存储服务器方式存储文件、图片信息的程序,需要将原访问接口改造为OSS官方提供的标准SDK或API接口。
对于原来采用关系数据库方式存储文件、图片信息的程序,需要修改关系数据库表结构和程序的数据读写代码。改造关系数据库表结构时,需要将原BLOB类型修改为varchar类型,存储文件对象所在OSS的地址。

3.4.4 大数据实时计算应用改造
很多情况下,传统行业一个业务系统对应后台一个Oracle数据库,Oracle数据库基本支持全部业务,既包含在线事务型的业务,也包含实时分析类业务,同时还有离线处理类型的业务。当实时分析、离线处理的业务和在线事务型业务叠加的时候,往往会导致Oracle数据库系统不堪重负,使在线业务系统性能出现严重问题,甚至无法使用。
对于导致性能压力过大的实时分析处理类的功能,建议从原有在线业务系统中剥离开。AnalyticDB作为传统关系型数据库的补充,将部分分析处理类的业务迁移至AnalyticDB上执行。对于离线处理类的业务改造将在下一节阐述。
目前适合使用AnalyticDB的业务需符合如下特征:
不要求强一致性,可接受最终一致性的业务场景。
对数据更新频率要求不高,可以接受分钟级及以上数据写入延时。
需要计算的数据量单表至少在百万量级,最高可到千亿量级。
对计算速度相对要求苛刻,可满足响应时间在1s至10s间业务场景的要求。
支持SQL语句访问,暂不对外支持复杂的计算,如MPI、MapReduce、BSP等计算模型接口。
单个数据表访问,不需要进行多表之间的关联查询,主要是单个大表的上卷、下钻、过滤等多维分析场景。
数据分析类业务,以一个大的事实表为中心,多个较小的维度表和事实表进行关联查询,然后进行上卷、下钻、过滤等多维分析场景。
1 . AnalyticDB库表设计
1)表类型:AnalyticDB库表包括维度表和事实表两类。其中,维度表一般是指存储配置和元信息的表,数据量较小。事实表一般是指系统中数据量为千万级以上的表。
2)表组:在AnalyticDB中,每一个表都必须属于一个表组。设计时需要充分考虑业务使用情况,将需要关联查询的表划分到同一个表组,同一个表组内,一级分区数量必须一致。
3)表分区:AnalyticDB分区支持HASH分区和LIST分区,并支持两级分区。事实表必须要指定分区和表组,维度表不需要指定分区但要指定表组。选择一级分区字段时,要尽可能保证数据分布均匀,单个分区的数据量在1GB以内或1000w级以下。Hash分区是根据导入数据时已有的一列的内容进行散列后进行分区的,因此目前多张表进行Join时,Join列必须包含分区列,并且表的Hash分区数必须一致。另外,采用Hash分区的数据表,在数据装载时会全量覆盖历史数据的。List分区则是根据进行导入操作时指定的分区列值来进行分区的。
事实表的分区设计有两种类型:只采用一级分区,采用Hash分区方式;采用二级分区,一级分区为Hash分区,二级分区采用List分区。第一种方式是AnalyticDB最常用的分区设计方式,适用于大部分情况。第二种方式中,一级分区使用Hash分区,二级分区采用List分区。二级List分区可支持数据增量导入,如每天新增一个二级List分区存储业务新增数据。
4)数据类型:AnalyticDB数据类型是MySQL数据类型的子集。如表3-1所示。
image

注:分析型数据库所有的数据类型都不支持unsigned,下表不包含该差异
2 . AnalyticDB数据同步和集成
阿里云提供了多种数据同步和集成工具,如CDP、DTS,可支持从RDS、Oracle、OSS、文本文件等数据源实时或定期同步到AnalyticDB数据库。DTS数据传输产品可支持从RDS(MySQL)实时同步数据到AnalyticDB数据库,数据延时在分钟级别。CDP云上数据同步管道可支持关系数据库到阿里云数据存储产品、阿里云数据存储产品之间的定期批量数据同步。同时AnalyticDB提供Web化的管理控制台,可将MaxCompute数据批量导入到AnalyticDB,以及提供SQL接口支持应用程序向AnalyticDB写入数据。
3 . 使用AnalyticDB的注意事项
表限制
AnalyticDB数据以二维表方式存储,一般可分为维度表和事实表。
维度表主要用于存储数据量较小,且修改不频繁的业务数据,如meta类数据。一般建议维度表数据行数小于1000万且占用存储空间小于1GB。AnalyticDB维度表不支持分区。维度表和事实表关联查询时,关联列需要在数据导入前添加哈希索引,否则无法进行表关联。
事实表一般建议存储数据量较大,且更新频繁的业务数据,如消费记录数据。事实表一般比较大、数据行在千万级以上。事实表可支持分区,分区列可支持日期或数值类型。使用事实表时需要注意,创建事实表必须指定所属数据库和表组。
事实表的限制如下:
一张事实表至少有一级Hash分区并且分区数不能小于8个。
一个事实表组最多可以创建256个事实表。
一个事实表最多不能超过1024个列。
数据导入限制
AnalyticDB提供多种数据批量导入的功能,执行数据导入操作前需要进行相应的授权操作。例如,数据来源在MaxCompute上,则需要在MaxCompute上对特定账号授予源表的describe和select权限。
AnalyticDB目前仅允许操作者导入自身为Project Owner的MaxCompute Project中的数据。如果不满足这些条件,发起导入命令时会报can not load table meta错误。
使用限制
为了更高效地进行表关联,AnalyticDB中两个事实表进行关联查询必须满足以下充要条件:
两张表在一个表组。
两张表的Join Key是Hash分区列。
两张表的Hash分区数必须一致,否则Join结果不准确。
两张表的Join Key至少有一列建立了HashMap索引,推荐建立在数据量较小的一侧。
维度表参与关联查询,只需要符合上述第4点即可。
上述内容为AnalyticDB对多表关联查询的限制。另外,AnalyticDB还会对通过SELECT语句进行查询的结果返回行数设置限制,默认只返回10000行。
3.4.5 大数据离线分析应用改造
对于用户大数据离线分析类应用,建议对其进行改造,以已匹配阿里云MaxCompute大数据计算服务。
大数据计算服务是一种快速、完全托管的海量数据仓库解决方案。MaxCompute向用户提供了完善的数据导入方案以及多种经典的分布式计算模型,能够更快速地解决用户海量数据计算问题。MaxCompute主要服务于批量结构化数据的存储和计算,可以提供海量数据仓库的解决方案以及针对大数据的分析建模服务。
1 . 使用场景
MaxCompute主要用于离散数据存储和批量计算场景,不适用于实时存储和分析场景。一般运行在MaxCompute之上的业务系统对数据时效性要求低,通常是T+1的系统,同时MaxCompute可支持TB/PB级数据的离线分析和处理。使用MaxCompute的一般做法是,数据从业务系统抽取到MaxCompute后,经过MaxCompute离线分析处理后,将分析处理后的结果回写到业务系统,业务系统直接查询和访问MaxCompute分析处理后的结果。
目前有大量用户的数据仓库类应用都是基于Oracle关系数据库建设的,当用户数据量达到TB级特别是10TB以上后,大规模离线数据计算场景Oracle数据库计算性能已无法满足用户的业务需求。下面将以基于Oracle数据库构建的大数据分析应用为例,介绍如何从Oracle迁移到阿里云MaxCompute服务。
2 . MaxCompute结构设计与改造
(1)MaxCompute表设计
MaxCompute的存储结构与关系型数据库有本质差异,需要根据Oracle原始表结构,对其在MaxCompute中的存储方式与结构进行设计。由于其不是一一对应的关系,故需要对每个数据表进行逐一的核对后,方可最终确定MaxCompute的数据结构。
数据类型转换规则如表3-2所示。
image

(2)MaxCompute表属性设计
MaxCompute表属性设计主要包含表命名规范、表注释、表数据生命周期、是否开启极限存储等方案。
在表命名规则方面,建议和业务系统数据库名、表名保持一致,如采用业务系统库名_业务系统表名方式。表注释主要用于描述表的功能和作用,注释内容要求不超过1024字节。
MaxCompute提供数据生命周期管理功能,方便用户释放存储空间,简化回收数据空间的流程。用户可在创建表时通过lifecycle属性指定数据生命周期,生命周期时间必须设置为正整数,单位是天。数据表是否开启极限存储功能主要适用于按天分区的全量快照表,且不同分区的数据重复度高的场景。
(3)MaxCompute分区设计
MaxCompute主要用于离线存储、批量计算和分析,数据源于在线业务系统数据库。一般采用批量同步技术,按指定周期将在线业务数据库数据同步到MaxCompute进行存储和分析。为方便存储和分析,会使用MaxCompute分区表存储数据,表分区规则建议按时间划分分区,表分区键及定义为:dt string。MaxCompute分区分为静态分区和动态分区,可以做多个分区层级。一个表允许的分区个数支持按照具体的project配置,默认值为60 000个。
静态分区在插入数据前已通过添加分区方式建立。动态分区在使用insert overwrite插入到一张分区表时,可以在分区中指定一个分区列名,但不给出值。相应的,在select子句中的对应列来提供分区的值。动态分区的限制如下:
目前,在使用动态分区功能的SQL中,在分布式环境下,单个进程最多只能输出512个动态分区,否则引发运行时异常。
在现阶段,任意动态分区SQL不可以生成超过2000个动态分区,否则会引发运行时异常。
动态生成的分区值不能为NULL,否则会引发异常。
如果目标表有多级分区,在运行insert语句时允许指定部分分区为静态,但是静态分区必须是高级分区。
注意,在表中出现的分区层次不能超过6级。
3 . SQL改造
MaxCompute只能以表的形式存储数据,并对外提供了SQL查询功能。用户可以将MaxCompute作为传统的数据库软件操作,但其却能处理TB、PB级别的海量数据。MaxCompute SQL与Hive SQL高度兼容,但MaxCompute不支持事务、索引及Update/Delete等操作,同时MaxCompute的SQL语法与Oracle、MySQL有一定差别,用户无法将其他数据库中的SQL语句无缝迁移到MaxCompute上来。因此,需要结合MaxCompute语法进行SQL语句改写,MaxCompute SQL语法请见官方文档:

https://help.aliyun.com/document_detail/27862.html?spm=5176.doc27863.6.603.o1grir
https://help.aliyun.com/document_detail/27863.html?spm=5176.doc51823.6.604.SJatSw
https://help.aliyun.com/document_detail/48950.html?spm=5176.doc27860.6.605.fQYbxR

4 . 数据同步和更新
使用MaxCompute服务后,需要配置同步任务从在线业务系统定时或实时同步更新MaxCompute数据。可以使用阿里云BASE平台配置数据同步任务完成MaxCompute数据同步,再通过MaxCompute SQL实现MaxCompute历史数据的更新操作。
5 . MaxCompute的注意事项
使用MaxCompute时,有一些注意事项,如表3-3所示。
image



推荐阅读
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 在Java分层设计模式中,典型的三层架构(3-tier application)将业务应用细分为表现层(UI)、业务逻辑层(BLL)和数据访问层(DAL)。这种分层结构不仅有助于提高代码的可维护性和可扩展性,还能有效分离关注点,使各层职责更加明确。通过合理的设计和实现,三层架构能够显著提升系统的整体性能和稳定性。 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
  • 在CentOS 7上部署WebRTC网关Janus
    在CentOS 7上部署WebRTC网关Janus ... [详细]
  • 本文详细介绍了如何在 Linux 系统上安装 JDK 1.8、MySQL 和 Redis,并提供了相应的环境配置和验证步骤。 ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • 帝国CMS中的信息归档功能详解及其重要性
    本文详细解析了帝国CMS中的信息归档功能,并探讨了其在内容管理中的重要性。通过归档功能,用户可以有效地管理和组织大量内容,提高网站的运行效率和用户体验。此外,文章还介绍了如何利用该功能进行数据备份和恢复,确保网站数据的安全性和完整性。 ... [详细]
  • 2021年Java开发实战:当前时间戳转换方法详解与实用网址推荐
    在当前的就业市场中,金九银十过后,金三银四也即将到来。本文将分享一些实用的面试技巧和题目,特别是针对正在寻找新工作机会的Java开发者。作者在准备字节跳动的面试过程中积累了丰富的经验,并成功获得了Offer。文中详细介绍了如何将当前时间戳进行转换的方法,并推荐了一些实用的在线资源,帮助读者更好地应对技术面试。 ... [详细]
  • (1)前期知识:1. 单机架构:单一服务器计算机——其处理能力和存储容量有限。2. 集群架构(负载均衡器与多节点服务器)——通过增加节点数量来提升系统性能和可靠性,实现高效的任务分配和资源利用。 ... [详细]
  • 第二章:Kafka基础入门与核心概念解析
    本章节主要介绍了Kafka的基本概念及其核心特性。Kafka是一种分布式消息发布和订阅系统,以其卓越的性能和高吞吐量而著称。最初,Kafka被设计用于LinkedIn的活动流和运营数据处理,旨在高效地管理和传输大规模的数据流。这些数据主要包括用户活动记录、系统日志和其他实时信息。通过深入解析Kafka的设计原理和应用场景,读者将能够更好地理解其在现代大数据架构中的重要地位。 ... [详细]
  • Jeecg开源社区正式启动第12届架构技术培训班,现已开放报名。本次培训采用师徒制模式,深入探讨Java架构技术。类似于大学导师指导研究生的方式,特别适合在职人员。导师将为学员布置课题,提供丰富的视频资料,并进行一对一指导,帮助学员高效学习和完成任务。我们的教学方法注重实践与理论结合,旨在培养学员的综合技术能力。 ... [详细]
  • 2016-2017学年《网络安全实战》第三次作业
    2016-2017学年《网络安全实战》第三次作业总结了教材中关于网络信息收集技术的内容。本章主要探讨了网络踩点、网络扫描和网络查点三个关键步骤。其中,网络踩点旨在通过公开渠道收集目标信息,为后续的安全测试奠定基础,而不涉及实际的入侵行为。 ... [详细]
  • 解读中台架构:微服务与分布式技术的区别及应用
    中心化与去中心化是长期讨论的话题。中心化架构的优势在于部署和维护相对简单,尤其在服务负载较为稳定的情况下,能够提供高效稳定的性能。然而,随着业务规模的扩大和技术需求的多样化,中心化架构的局限性逐渐显现,如扩展性和故障恢复能力较差。相比之下,微服务和分布式技术通过解耦系统组件,提高了系统的灵活性和可扩展性,更适合处理复杂多变的业务场景。本文将深入探讨中台架构中微服务与分布式技术的区别及其应用场景,帮助读者更好地理解和选择适合自身业务的技术方案。 ... [详细]
author-avatar
谢撒旦法_774
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有