GitHub标星10,000+,Apache项目ShardingSphere的开源之路
【编者按】几天前,当 GitHub 全球产品技术生态总经理 Michael Francisco 谈到中国开发者已经成为 GitHub 上最活跃的群体时,有开发者提出数量之后质量也要跟上。的确,过去十数年间,中国开源一直呈现企业热使用热社区冷开发冷的景象,不过现在正在显著发生变化,从 Apache ShardingSphere 的成长历程就可以一窥。
历经 4 年,从第一行代码到今天,ShardingSphere 正式成为 Apache 顶级开源项目,GitHub 开发者关系主管 Martin Woodward 如此评价道:“我们很高兴看到这个社区在过去两年里发展得非常好,现在有 120 多个直接贡献者。”在本文中,其核心初创人员为我们分享了它的开源之路,相信会对所有热爱开源希望有所建树的开发者们大有裨益。
作者 | 潘娟,Apache ShardingSphere PMC
张亮,Apache ShardingSphere VP
编辑 | 唐小引
出品 | CSDN 开源实验室
前言
从 Sharding-JDBC 到 Apache ShardingSphere;
从轻量级的分库分表中间件到完整闭环的分布式数据库中间件平台;
从 2016 年 1 月的第一行代码到现今的 300K+行代码;
从寥寥无几的关注到 GitHub 10K+ 的 star;
从无人问津的社区到 100+ 位贡献者;
从公司内部的应用类库到 100+ 的采用公司列表;
从寻找 mentor 到顺利成为 Apache 顶级项目。
……
Apache ShardingSphere 团队核心初创人员将讲述这其中的跌宕起伏,并以时间轴为线索为你呈现它开源之路背后的故事。
项目介绍
Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 3 款相互独立,却又能够混合部署配合使用的产品组成。它们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景,核心功能如 1-1 所示。
1-1 ShardingSphere 核心功能架构图
Apache ShardingSphere 由三个子项目组成,形成一个完整的数据库解决方案,合称 J.P.S. 生态系统。
ShardingSphere-JDBC:定位为轻量级 Java 框架,在 Java 的 JDBC 层提供额外服务。它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
ShardingSphere-Proxy:定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。目前提供 MySQL/PostgreSQL 版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端操作数据,对 DBA 更加友好。
ShardingSphere-Sidecar(TODO):定位为 Kubernetes 的云原生数据库代理,以 Sidecar 的形式代理所有对数据库的访问。通过无中心、零侵入的方案提供与数据库交互的的啮合层,即 Database Mesh,又可称数据网格。
Apache ShardingSphere 的亮点主要包括:
完整的分布式数据库解决方案:提供数据分片、分布式事务、数据弹性迁移、数据库和数据治理等核心能力。
独立的 SQL 解析引擎:支持多 SQL 方言的完全独立化 SQL 解析引擎,能够脱离 ShardingSphere 独立使用。
可插拔微内核:所有的 SQL 方言、数据库协议和功能都能够通过 SPI 的可插拔方式加载或卸载,微内核甚至在未来可以运行于无任何功能的空白环境中。
Apache 基金会
The most popular open source software is Apache.
这是对 Apache 开源软件基金最好的描述和肯定。它旨在为全世界提供优质的开源软件,同时欢迎全世界的朋友加入 Apache 社区贡献力量,并在这个过程中不断成长、得到肯定、共建开源社区。无论是否从事软件开发工作,大家多少都知道它的存在及其提供的优质开源项目,可见其影响之大、之深远。
此外,参与 Apache 开源社区,并在自己的努力下成为 Apache Committer,更是大多数软件开发工程师心之所向。
ShardingSphere 在开源之初,就有进入 Apache 开源组织基金会的计划。其原因有以下几点:
Apache 基金会独特的 Apache way 和社区建设思想会让一个开源项目更规范、更有生命力;
Apache 基金会的导师制度会为一个开源社区带来优秀的指导和帮助;
Apache 基金会会为其下的开源项目带来版权和商标上的法律保护;
Apache 基金会在全世界范围内的影响不言而喻,若是能进入 Apache 基金会,则会扩大项目的影响力,使其进入世界范围的开源领域。
Apache 基金会内的项目会更有机会登上世界舞台,并与其他开源项目建立友好交流,也能吸引更多贡献者加入社区。
但同样,进入 Apache 开源基金会的门槛可并不简单,特别对于国内的项目来说,语言和地域的障碍无疑雪上加霜。
如何为 Apache 做准备?
找寻 mentor 是进入 Apache 基金的最初且最重要的一步。
在了解了 Apache 基金会的运作方式后,我们便踏上了找寻 mentor 之旅。参加各种与开源相关的分享会或 meetup,借此来认识 Apache 的 member。但是,事情却并不顺利。多次的尝试、接触换来的只是口头的认可。这段时间我们确实倍感压力和焦虑,甚至打算以后再说,一切随缘。
后来一个契机,我们认识了吴晟和华为的姜宁。吴晟是 Apache SkyWalking 项目的 VP,在开源领域有丰富的经验。他和 ShardingSphere 的前身 Sharding-JDBC 很有渊源,Sharding-JDBC 项目原型也有他参与设计,因此,他最终作为 ShardingSphere 的 PPMC 一同建设社区。在参与 ShardingSphere 社区建设的这一年多的时间里,他又陆续担任了多个 Apache 孵化项目的 Mentor,并在今年被选举为 Apache Member。
而姜宁同样是一位热心又有经验的老手,是国内最资深的 Apache Member 之一,在与他交流的过程中,终于让我们看到一些希望,他也最终成为了我们的 mentor。
再后来,团队 VP 张亮又前去上海参加 HDC 大会,认识了我们的另一位 mentor—— Craig L Russell,Craig 当时是 Apache 的秘书长,所有的 SGA、ICLA 等法务文件均由他负责签署。在 ShardingSphere 孵化的过程中,Craig 当选了 Apache 软件基金会的主席。他友善而和气,给予了我们很多有关社区规范的实用建议,也愿意助我们一臂之力。
第三位 mentor 则是由 Apache RocketMQ 的核心成员冯嘉担任;最后由 Roman Shaposhnik 担任项目的 Champion,为项目寻找导师之旅画上完美句号。至今还记得我们当时的欣喜和激动。之前的无助、徘徊、失落在这一瞬间柳暗花明。
每个进入 Apache 基金会的项目,一定都有自己的故事。尤其对于中国的项目来说,语言与地域的障碍会让我们更加艰难。好在有越来越多的来自于中国的项目进入了 Apache 基金会,也能看到越来越多的华人活跃在 Apache 的邮件列表里,还有 ALC Beijing 的建立让参与门槛不断降低,这对想要参与的国内朋友来说,确实是个 good news!
进入 Apache 孵化器
为了正式进入 Apache 孵化器,项目代码、社区、文档等都需要进行一系列的规范和整理。这确实是个琐碎但很重要的事情。
代码层面,合规操作是首要原则。我们梳理第三方依赖的许可协议,确保满足 Apache 软件许可协议(ASL)合规的要求;
社区方面,我们开始由中文转变成英文;
文档方面则需要我们准备英文文档,并准备相关的 proposal。
由于项目最开始的目标就是进入 Apache 基金会,所以在项目初期,依赖就尽可能地简单,社区相对规范,文档在不断翻译。不打无准备之仗,这些提前的准备让这部分工作进展顺利,而项目获得 Apache 域名的那一刻,大家才真切感受到所有付出得到了最有价值的回报。
除了学习写规范代码,团队成员也开始学习 Apache 的规范、运作方式、英文沟通渠道等细节。我们开始了解到如何关注社区,什么是 consensus decision,如何用异步方式进行邮件沟通。特别是邮件列表的学习非常重要,你可以在其中找到历史问题记录、合规的解决方案、优秀的案例等。
Apache way 的探索
很多人认为只要代码开放,就叫做开源。但其实,这仅仅只是开源旅程的第一步。
如何构建一个活跃的社区,如何理解 Apache way,是一个更为重要的话题。ShardingSphere 在进入 Apache 孵化器初期并未能完全理解 Apache way,并且由于过度注重代码风格,以至于参与门槛较高、社区活跃度平平。
起初,我们并不知道问题出在哪里,迷茫了很长一段时间,直到在跟 Apache 的 member 不断交流的过程中才渐渐意识到问题所在,因此社区发起了有关 committer bar 的讨论,见图 1-2。这是社区建设之路的转折点,因为从此 community over code 的理念开始逐渐渗入人心,并指导我们的行动。
1-2 Committer bar 讨论邮件
仔细阅读 Apache way 的关注点:
Earned Authority, Community of Peers, Open Communications, Consensus Decision Making, Responsible Oversight
你会发现它一直在强调合规、开放、平等、协作,为的就是建立合规且活跃的项目社区,尽可能地做到让更多的人参与,平等沟通,推动项目发展,促进个人成长。秉持这个理念,ShardingSphere 开始在多维度进行调整:
代码:规整代码结构,划分模块功能,提供项目可插拔能力,从而允许用户局部参与某一模块的同时,尽量不破坏整体代码结构;
心态:开放的心态,编制社区任务,鼓励社区朋友参与,相关 PPMC 或 Committer 积极提供指导和帮助;
规范:梳理文档和代码规范,并提供详细的订阅、参与指南,大范围促进用户自主进行社区贡献;
交流:鼓励社区尽可能使用邮件和 Issue 进行讨论从而公开讨论内容,同时针对较为细节的讨论则放在微信群里进行。此外,官方公众号还会介绍社区的进展、Release、刊登技术文章等;
合作:与其他 Apache 社区建立联系、增加沟通,从合作交流中进行学习和发展。
在孵化期间,Apache ShardingSphere 先后与 Apache SkyWalking、Apache ServiceComb 进行项目的合作与集成,不仅彼此的产品功能更加完善,还增加了社区成员之间的交流。此外,还与 Apache DolphinScheduler(Incubating)和 Apache IoTDB(Incubating)举办了 co-meetup,详见图 1-3。还与 Apach pulsar 和 Apache APISIX(Incubating)的核心成员们进行了多次交流和探讨。
1-3 co-meetup
经过时间的积累,社区已有了质的变化。从社区的邮件讨论、GitHub 的数据展示中,你会发现 ShardingSphere 的社区开始真正变得活跃与多元化。图 1-4 展示了 ShardingSphere 在 Apache 孵化器一年多的社区数据变化。
1-4 社区数据变化
社区与贡献者之间的依赖和互赢也在整个过程中体现的淋漓尽致。对于贡献者来说,他们会在这个开源社区中与其他人交流、协作。而这个持续的过程,将带来以下成果:
扩大人际交友圈
不断学习与成长
提高自己的技术影响力
拓宽职业渠道
结合兴趣,享受过程
对于社区来说,这个相互帮助和沟通的过程则会:
拓展项目的功能
收获活跃多元化的生态圈
增加项目知名度
获得社区的可持续发展
从这个角度来看,不断探索 Apache way 不也是希望出现这样一种共赢而互助的局面吗?Please remember community over code。
从孵化器毕业
所有孵化器的项目最终都希望能走向 TLP(Top Level Project)。在 mentor 的指导、PPMC 的探索、committer 和 contributor 的支持与付出下,ShardingSphere 开始筹备 Apache 孵化器毕业。
依据 Apache 的成熟度评估模型图 1-5,在以下几个方面评估社区和项目是否成熟。其实在 Apache 项目社区的初建阶段,我们建议大家就在这几个方面发力,因为这是官方给予的毕业标准及指导方针。以此为方向,探索属于各自项目的独特社区运作方式,也可谓是百花齐放。
1-5 1-5 Apache 项目成熟度评估模型
经历 Release、社区建设、Apache member 的指导、meetup 举办等一系列事件,ShardingSphere 终于在社区发起了毕业讨论,开始接受 Apache member 及所有 Apache 成员的指导和评估。虽然最终以 10 +1 binding votes,6 +1 non-binding votes 和 no -1 or +/-0 votes 通过毕业投票,但过程也是一波三折。
即便是经过 1 年多的社区建设,项目基本成熟,但面对毕业还是有很多工作要合乎毕业规范。例如确认商标是否可使用、完成项目官网有关 Apache brand 和 trademark 的陈述、网站符合 Apache way 等。在这个投票期间,由于官网存在 fork me on github 的 slogan,而这一问题一直频繁出现并且没有结论,所以其他 Apache 成员借此单独开辟了 thread 来讨论这一问题,查看 Email List 了解详情。虽说这一举让 ShardingSphere 被成功推到前台,间接提高了项目的曝光,却也能看出 Apache 对于第三方独立、禁止参与商业行为的重视和严苛。
可喜可贺的是,2020 年 4 月 16 日,Apache ShardingSphere 最终通过基金会董事会决议,加入了 TLP 行业!
未来的路
回首这一路,收获与付出兼存。这篇文章旨在用故事为大家带来更为生动、全面的阐述和论据支撑,而在文章结尾,我们也特别想对开发者朋友说:
愿这篇文章能为你打开新的思路,它像一扇窗,为有心的人呈现另一种职业风景,带来新的思潮。
希望文章有关”参与开源社区意义“的部分能为你解答有关开源价值的问题。
每一个 Apache 开源项目都有自己独特的社区发展方向和价值观。参与其中,选择与你气味相投的社区,是一件很有价值且很有意思的事情。
有张有弛,有进有退;不妄自菲薄,也不目空一切;在开源的领域,更确切说在 Apache 开源社区,更多的是遵守规范、开放包容、平等交流、互相学习。
低头工作,便全力以赴;耳闻窗外,便接收新潮,更新大脑。
从 Apache 孵化器毕业成为 TLP,对 ShardingSphere 来说,并不是一个结束,而是另一个开始。在产品功能上,ShardingSphere 将继续在分布式数据库中间件平台上深耕,打磨出以“分布式”为核心的数据库中间件生态圈,从而提供完整的解决方案,如图 1-6 所示。从社区角度讲,ShardingSphere 仍将继续活跃社区,鼓励更多朋友成为社区的 committer 和 contributor。所以,我们欢迎大家关注 ShardingSphere,并加入到社区来,与更多知己结伴前行。未来之路不可预测,但立足当下,眺望未来,初心未改,即便亦步亦趋,也愿一苇以航!
1-6 Apache ShardingSphere 生态圈
Apache ShardingSphere Committer 列表
Mentor
Craig L Russell
冯嘉,阿里巴巴
姜宁,华为
PMC
张亮,京东数科
潘娟,京东数科
赵俊,京东数科
张永伦,京东数科
陈清阳,翼支付
曹昊,海南新软
马晓光
杜红军,领创智信
杨翊,京东数科
吴晟,tetrate.io
高洪涛,tetrate.io
Committer
李亚,九个小海豹
颜志一,DaoCloud
董宗磊,京东零售
孙海生,瓜子
王奇,京东零售
欧阳文,一卡易
蒋晓峰,阿里巴巴
王光远
秦金卫,京东数科
岳令
赵亚楠
Apache ShardingSphere 官网:
https://shardingsphere.apache.org/
GitHub 地址:
https://github.com/apache/shardingsphere
作者简介:
潘娟,京东数科高级 DBA,Apache ShardingSphere PMC。
张亮,京东数科数据研发负责人,Apache ShardingSphere VP,Apache Dubbo PMC,人气开源项目 Elastic-Job 作者。
推荐阅读
360金融首席科学家张家兴:别指望AI Lab做成中台
我们想研发一个机器学习框架,6 个月后失败了
八年,腾讯优图攒了多厚的技术“家底”?
无需训练 RNN 或生成模型,如何编写一个快速且通用的 AI “讲故事”项目?
区块链重大技术分析:IBM、微软、苹果、Google 都做了什么?
你点的每个“在看”,我都认真当成了AI
相关文章:

JAVA中LOCK
原文链接:http://www.cnblogs.com/dolphin0520/p/3923167.html 一.synchronized的缺陷 我们知道如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的…
【公开课预告】AutoML知多少
5月7日周四19:00,商汤泰坦公开课第010期,论文解读系列课程第二期即将开播!我们邀请到商汤科技的4位研究员,分享团队在AutoML方面的一系列研究工作,其中包含CVPR 2020、ICLR 2020等多篇最新论文成果,想要了解…
Linux kernel futex.c的bug导致JVM不可用
JVM死锁导致线程不可用,然后会瞬间起N个线程,当然也是不可用的,因为需要的对象死锁,然后耗尽文件句柄导致外部TCP无法建议拒绝服务,jstack之后就会恢复。 解决办法:替换中间件类库 ,比如httpcli…

ruby爬虫综述
http://ihower.tw/blog/archives/2941一个ruby爬虫的例子http://hi.baidu.com/anspider/blog/item/9da210425a0e4e179213c6fb.html

Exchange 2016集成ADRMS系列-12:域内outlook 2010客户端测试
接下来,我们来到域内安装了office 2010的机器上进行测试。 首先我们在客户端上强制刷新组策略,把我们刚才设置的策略刷新下来。 然后我们可以运行gpresult /h result.html来看看策略是不是已经下来了。 策略下来之后,我们打开客户端上面的out…

在Linux下编写Daemon
在Linux下编写Daemon 转自:http://blog.163.com/prevBlogPerma.do?hostmanyhappy163&srl1644768312010718111142260&modeprev 在Linux(以Redhat Linux Enterprise Edition 5.3为例)下,有时需要编写Service。Service也是…

JVM虚拟机参数配置官方文档
JDK8 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/index.html JDK7 https://docs.oracle.com/javase/7/docs/technotes/tools/solaris/java.html 官方博客 https://blogs.or…
在Rust代码中编写Python是种怎样的体验?
作者 | Mara Bos,Rust资深工程师译者 | Arvin,编辑 | 屠敏来源 | CSDN(ID:CSDNnews)大约一年前,我发布了一个名为inline-python(https://crates.io/crates/inline-python)的Rust类库…

Docker配置指南系列(二):指令集(二)
pause: 停止一个容器的所有进程语法:ocker pause CONTAINER [CONTAINER...] port: 列出容器的端口映射,或者查看指定开放端口的NAT映射语法:docker port [--help] CONTAINER [PRIVATE_PORT[/PROTO]] ps: 列出容器语法࿱…
无需训练RNN或生成模型,我写了一个AI来讲故事
作者 | Andre Ye译者 | 弯月出品 | AI科技大本营(ID:rgznai100)这段日子里,我们都被隔离了,就特别想听故事。然而,我们并非对所有故事都感兴趣,有些人喜欢浪漫的故事,他们肯定不喜欢…
Java字节码instrument研究
MyAgent项目 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…

怎样保持良好的心态
有一位朋友有一次气冲冲的跟我说:“气死我了!我刚刚发现我一位员工出了错,令产品出现了质量的问题,我修理了他一顿。。。 我问:”你认为你的生产流程里面可能一点错误都没有吗?“ 他说:”应该不…

web编程速度大比拼(nodejs go python)(非专业对比)
C10K问题的解决,涌现出一大批新框架,或者新语言,那么问题来了:到底谁最快呢?非专业程序猿来个非专业对比。 比较程序:输出Hello World! 测试程序:siege –c 100 –r 100 –b 例子包括࿱…

linux邮件服务
邮件服务要求:l 能够构建完整的邮件系统 能够正确设置DNS邮件服务器记录 l 能够配置sendmail服务器 设置客户端软件使用邮件服务器 准备工作: l 主机名:srv.benet.com /etc/sysconfig/network <永久的> l 域名 正向区域 bt.com完成NDS的…
MaskFlownet:基于可学习遮挡掩模的非对称特征匹配丨CVPR 2020
来源 | 微软研究院AI头条(ID: MSRAsia)编者按:在光流预测任务中,形变带来的歧义与无效信息会干扰特征匹配的结果。在这篇 CVPR 2020 Oral 论文中,微软亚洲研究院提出了一种可学习遮挡掩模的非对称特征匹配模块 &#x…

GDB调试--以汇编语言为例
#rpm -qa |grep gdb 下载: 安装 #tar -zxvf #./configure #make 使用GDB 以汇编语言调试为例 汇编语言实现CPUID指令 CPUID cpuid是Intel Pentinum以上级CPU内置的一个指令(486级以下的CPU不支持),他用于识别某一类型…

汇编语言系统调用过程
以printf为例,详细解析一个简单的printf调用里头,系统究竟做了什么,各寄存器究竟如何变化。 如何在汇编调用glibc的函数?其实也很简单,根据c convention call的规则,参数反向压栈,call…

switch语句中在case块里声明变量会遇到提示“Expected expression before...的问题
switch语句中在case块里声明变量会遇到提示“Expected expression before..."的问题 例如在如下代码中 1case constant:2 int i 1;3 int j 2;4 self.sum i j;5 break;GCC在case语句之后的第一行中声明变量时遇到问题。 这时需要在case块两端添加花括号&am…
帮AI体检看病一条龙服务,阿里发布“AI安全诊断大师”
如同一些出生免疫力就有缺陷的人一样,AI也存在免疫力缺陷。基于从源头打造安全免疫力的新一代安全架构理念,最近,阿里安全研究发布了一项核心技术“AI安全诊断大师”,可对AI模型全面体检,“看诊开方”,让AI…

Spring学习总结(7)——applicationContext.xml 配置文详解
web.xml中classpath:和classpath*: 有什么区别? classpath:只会到你的class路径中查找找文件; classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找. 存放位置: 1:src下面 需要在web.xml中定义如下&…

GDB查看栈信息
栈:是程序存放数据内存区域之一,特点是LIFO(后进先出)。 PUSH:入栈 POP:出战 使用场景: 1.保存动态分配的自动变量使用栈 2.函数调用时,用栈传递函数参数,半寸返回地址…

数据库学习之路
今天迎来入冬的第二场雪,闲来无事就整理了下总结下工作以来所有数据库方面的书籍和资料,发现了不少,很多已经读过或者正在读的书籍,oracle真的很强大,直到现在发现才入门的水平,当然很多书读一遍是不行的&a…
为什么铺天盖地都是Python的广告?
最近,知乎关于Python有一个热议问题: 甚至在抖音上,笔者有一次还看到Python占领了热搜!应该有很多不懂技术的吃瓜群众也被Python的热度炒懵了……但是,Python真的值得学吗?真的值得花这么多钱去学吗&#x…

python3正则表达式符号和用法
转载于:https://www.cnblogs.com/wumac/p/5441322.html
从寄存器看I386和x64位中函数调用中参数传递
x86_64基本使用寄存器存储函数参数,寄存器不够才入栈; 而i386将所有参数保存在栈上,通过gcc的扩展功能__attribute__((regparm()))即可实现部分参数的寄存器传递。 调试语法: --《深入理解计算机系统(原书第2版)》 代码 #incl…

转:去掉Flex4生成的SWF加载时的进度条
方法一: <?xml version"1.0" encoding"utf-8"?> <s:Application xmlns:fx"http://ns.adobe.com/mxml/2009" xmlns:s"library://ns.adobe.com/flex/spark" xmlns:mx"library://ns.adobe.com/f…
饿了么交易系统5年演化史
作者 | 挽晴来源 | 阿里巴巴中间件(ID:Aliware_2018)个人简介:2014年12月加入饿了么,当时参与后台系统的研发(WalisJavis>Walle),主要面向客服和BD。2015年5月开始接触订单系统的研发,7月负责订单研发组…

Python迁移MySQL数据到MongoDB脚本
MongoDB是一个文档数据库,在存储小文件方面存在天然优势。随着业务求的变化,需要将线上MySQL数据库中的行记录,导入到MongoDB中文档记录。 一、场景:线上MySQL数据库某表迁移到MongoDB,字段无变化。 二、Python模块&am…

使用valgrind分析C程序调用线路图
Valgrind可以检测内存泄漏和内存违例,但是用Valgrind生成的日志信息结合kcachegrind就可以查看C程序的执行线路图,调用时间,是做性能优化和查看代码的非常好的工具。 1.下载安装 Valgrind 安装 到www.valgrind.org下载最新版valgrind # wg…

纯CSS实现蓝色圆角下拉菜单
代码简介: 这个菜单没有使用任何的图片,完全是用CSS实现的,包括圆角效果也同样是,而且还考虑了多浏览器的兼容性,可以说非常不错,既兼容性好,又外观漂亮,下拉导航菜单目前比较流行&a…