小红书在容器环境的CD实践

2017-10-12 孙国清 Go中国 前言 容器推出以来,给软件开发带来了极具传染性的振奋和创新,并获得了来自各个行业、各个领域的巨大的支持——从大企业到初创公司,从研发到各类IT人员等等。跨境知名电商小红书随着业务的铺开,线上部署单元的数量急剧增加,以 Jenkins 调用脚本进行文件推送的部署模式已经不能适应需求。这一期实践日,小红书运维团队负责人孙国清将为大家带来小红书如何以最小的投入,最低的开发量快速的实现容器化镜像部署,以及由此带来的收益。以下是此次演讲的整理。 作者介绍 孙国清 小红书运维团队负责人 浙大计算机系毕业,曾在传统企业 IT 部门工作多年, 最近几年开始在互联网行业从事技术及技术管理工作,曾就职于携程基础架构,负责 Linux 系统标准化及分布式存储的研究和落地,目前在小红书带领运维团队,负责业务应用,基础架构以及IT支持。个人接触的技术比较杂,从开发到运维的一些领域都有兴趣,是 Scala 语言的爱好者,曾翻译了”The Neophyte’s Guide to Scala”,有上千 Scala 开发者从中受益,到小红书后开始负责系统化落地 DevOps 和提高运维效率。 小红书 图 1 小红书本身是一个社区做起来的。一开始是大家在平台上发帖子,分享一些生活中的好东西,健身什么的。目前我们已经有有 5 千万的用户,1 千万的图文,每日 有1 亿次笔记曝光,涉及彩妆、护肤,健身,旅游等等各种领域。 现在小红书是最国内早践行社区电商这个商业模式并获得市场认可的一家电商,我们从社区把流量引入电商,现在在电商平台的 SKU 已经上到了十万级。我们从社区里的用户创建的笔记生成相关的标签,关联相关商品, 同时在商品页面也展示社区内的用户相关笔记。 小红目前还处在创业阶段,我们的技术团队规模还不大, 当然运维本身也是一个小团队,现在整个运维是八个同学。小公司资源有限,一个是人力资源有限,二是我们很多业务往前赶,在如何做好 CI/CD,怎么务实的落地方面, 我们的策略就是开源优先,优先选择开源的产品,在开源的基础上,发现不足的地方做补缺。 小红书应用上线流程 图 2 如图 2 是现在应用上线的过程,开发向运维提需求,需要多少台服务器, 运维依据需求去做初始化并交付给开发。小红书现在有一个运维平台,所有服务器的部署都是有这个平台来完成,平台调用腾讯云API生成服务器,做环境初始化,配置监控和报警,交付给开发的是一个服务器。 图 3 线上发布是用 Jenkins 脚本的方式:用 Jenkins 的脚本做测试,执行代码推送. 当有新加一台服务器或者下线一台服务器,要去修改这个发布脚本。 发布流程大概是这样的: jenkins脚本先往beta环境发,开发者在 beta 环境里做自测,自测环境没有问题就全量发。…

Read More

MyCat:开源分布式数据库中间件

摘要:MyCat截至到2015年4月,保守估计已经有超过60个项目在使用,主要应用在电信领域、互联网项目,大部分是交易和管理系统,少量是信息系统。比较大的系统中,数据规模单表单月30亿。本文带你全面了解MyCat。 为什么需要MyCat? 虽然云计算时代,传统数据库存在着先天性的弊端,但是NoSQL数据库又无法将其替代。如果传统数据易于扩展,可切分,就可以避免单机(单库)的性能缺陷。 MyCat的目标就是:低成本地将现有的单机数据库和应用平滑迁移到“云”端,解决数据存储和业务规模迅速增长情况下的数据瓶颈问题。2014年MyCat首次在上海的《中华架构师》大会上对外宣讲引发围观,更多的人参与进来,随后越来越多的项目采用了MyCat。 MyCat截至到2015年4月,保守估计已经有超过60个项目在使用,主要应用在电信领域、互联网项目,大部分是交易和管理系统,少量是信息系统。比较大的系统中,数据规模单表单月30亿。 MyCat是什么? 从定义和分类来看,它是一个开源的分布式数据库系统,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。 MyCat发展到目前的版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在MyCat里,都是一个传统的数据库表,支持标准的SQL语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发难度,提升开发速度 图1 MyCat架构设计图 MyCat解决了哪些问题 1. 连接过多问题,可以通过MyCat统一管理所有的数据源,后端数据库集群对前端应用程序透明。使用MyCat之前系统结构如图2。 图2  MyCat早前系统架构 MyCat引入连接复用解决多应用竞争问题,通过MyCat改造后,如图3所示。 图3  改造后的MyCat 2. 独创的ER关系分片,解决E-R分片难处理问题,存在关联关系的父子表在数据插入的过程中,子表会被MyCat路由到其相关父表记录的节点上,从而父子表的Join查询可以下推到各个数据库节点上完成,这是最高效的跨节点Join处理技术,也是MyCat首创。 图4  独创的ER关系分片,是MyCat首创 3. 采用全局分片技术,每个节点同时并发插入和更新数据,每个节点都可以读取数据,提升读性能的同时,也解决跨节点Join的效率。 图5 采用全局分片技术 4. 通过人工智能的catlet支持跨分片复杂SQL实现以及存储过程支持等。使用方式主要通过MyCat注释的方式来执行,如下: (1)跨分片联合查询注解支持: /*!MyCat:catlet=demo.catlets.ShareJoin / select bu. ,sg.* from base_user bu,sam_glucose sg where bu.id_=sg.user_id; 注:sam_glucose是跨分片表。 (2)存储过程注解支持: /*!MyCat: sql=select * from base_user where id_=1;*/ CALL proc_test(); 注:目前执行存储过程通过MyCat注解的方式执行,注意需要把存储过程中的sql写到注解中。 (3)批量插入与ID自增长结合的支持: /*!MyCat:catlet=demo.catlets.BatchInsertSequence */ insert into sam_test(name_) values(‘t1’),(‘t2’);…

Read More

Mycat高级进阶—Mycat注解

注解原理 概念: MyCat对自身不支持的Sql语句提供了一种解决方案——在要执行的SQL语句前添加额外的一段由注解SQL组织的代码,这样Sql就能正确执行,这段代码称之为“注解”。注解的使用相当于对mycat不支持的sql语句做了一层透明代理转发,直接交给目标的数据节点进行sql语句执行,其中注解SQL用于确定最终执行SQL的数据节点。注解的形式是: /*!mycat: sql=注解Sql语句*/ 1 注解的使用方式是: /*!mycat: sql=注解Sql语句*/真正执行Sql 1 使用时将=号后的“注解Sql语句”替换为需要的Sql语句即可,后面会提到具体的用法。 原理: MyCat执行SQL语句的流程是先进行SQL解析处理,解析出分片信息(路由信息)后,然后到该分片对应的物理库上去执行;若传入的SQL语句MyCat无法解析,则MyCat不会去执行;而注解则是告诉MyCat按照注解内的SQL(称之为注解SQL)去进行解析处理,解析出分片信息后,将注解后真正要执行的SQL语句(称之为原始SQL)发送到该分片对应的物理库上去执行。 从上面的原理可以看到,注解只是告诉MyCat到何处去执行原始SQL;因而使用注解前,要清楚的知道该原始SQL去哪个分片执行,然后在注解SQL中也指向该分片,这样才能使用!例子中的sharding_id=10010 即是指明分片信息的。 需要说明的是,若注解SQL没有能明确到具体某个分片,譬如例子中的注解SQL没有添加sharding_id=10010这个条件,则MyCat会将原始SQL发送到persons表所在的所有分片上去执行去,这样造成的后果若是插入语句,则在多个分片上都存在重复记录,同样查询、更新、删除操作也会得到错误的结果! 解决问题: MySql不支持的语法结构,如insert …select… 同一个实例内的跨库关联查询,如用户库和平台库内的表关联 存储过程调用。 表,存储过程创建。 注解规范 注解SQL使用select语句,不允许使用delete/update/insert等语句;虽然delete/update/insert 等语句也能用在注解中,但这些语句在Sql处理中有额外的逻辑判断,从性能考虑,请使用select语句 注解SQL禁用表关联语句 注解SQL尽量用最简单的SQL语句,如select id from tab_a where id=’10000’ 无论是原始SQL还是注解SQL,禁止DDL语句 能不用注解的尽量不用 详细要求见下面 Select -选择能唯一确定分片的主表,如与用户表关联的时候可以选择用户表 若是业务需要在主表所在的各个分片上都执行可以不加能确定分片的条件 Insert 对于分片表 使用insert的表做注解SQL 注解SQL必须能确认具体到某个分片 原始SQL插入的字段必须包含分片字段 原始SQL中包含的分片字段和注解SQL中的分片字段确定的分片务必要一致 对于insert … select这种语句,请务必确认插入的记录都在当前查找到的分片上 非分片表 注解SQL必须能具体确认到某个分片 注解SQL包含的分片字段其分片上必须包含这个非分片表 Delete 对于分片表使用要删除记录的表做注解SQL Update 对于分片表用所要更新的表做注解SQL 禁止更新分片表的分片列 根据业务需要添加注解Sql的分片字段值 Call 若是要在所有的分片上都执行存储过程,则使用一个在所有分片上都包含的表,不添加任何分片条件 调用存储过程 若是单个分片执行,使用能确认到这个分片的表以及分片条件…

Read More

MyCat1.6带返回参数存储过程调用示例

本例环境:SpringMVC3.x + Mybatis3.x + Mycat1.6 + Mysql5.6 1、创建带出参存储过程 [sql] view plain copy DELIMITER && CREATE  PROCEDURE `test_proc`( in a_id int , out a_goods_id int) BEGIN               SELECT  a.goods_id  INTO  a_goods_id               FROM  es_goods_community a               WHERE  a.id=a_id ; END && DELIMITER ; 备注:这里的存储过程比较简单,就是根据一个表的ID,返回一个表的另外一个字段,本例中a_goods_id为出参。 2、mybatis映射文件 [html] view plain copy <select id=“testCallProc” resultType=“java.lang.Integer”>  <!– statementType=”CALLABLE” –>          <![CDATA[        /*!mycat:sql=select 1 from es_goods_community where seller_id=26*/{call test_proc(               #{id,mode=IN,jdbcType=INTEGER},               @goodsId            )};select @goodsId;        ]]>     </select> 这里的关键:statementType=”CALLABLE”不需要加上,而是把存储过程当成一条普通的SQL语句,发送给mycat执行,mycat根据注解路由到具体的后端节点,然后执行之,并返回结果,还需要在后面使用selelect语句返回OUT参数。在call语句中,出参用@加变量名定义,名字与select语句中的名字保持一样即可。 为什么要这样写呢?原因如下: 1、mycat已经声明,存储过程的调用通过注解来支持(主要原因,调用存储过程的语句无法定位路由信息),如果statementType=”CALLABLE”,mysql客户端(本例指mysql驱动包)会把语句当存储过程来看到,势必需要知道存储过程的元数据(出参列表)。故在mybatis文件中,call语句之前需要待上注解,但这和mycat驱动包处理存储过程的代码产生了矛盾,如下代码: [java] view plain copy public CallableStatement(MySQLConnection conn, String sql, String catalog,             boolean isFunctionCall) throws SQLException {         super(conn, sql, catalog);         this.callingStoredFunction = isFunctionCall;         if (!this.callingStoredFunction) {             if (!StringUtils.startsWithIgnoreCaseAndWs(sql, “CALL”)) {      // @1                 // not really a stored procedure call                 fakeParameterTypes(false);      //@2             } else {                 determineParameterTypes();  //@3             }             generateParameterMap();         } else {             determineParameterTypes();             generateParameterMap();             this.parameterCount += 1;         }         this.retrieveGeneratedKeys = true; // not provided for in the JDBC spec     } 代码来源与mysql-connector-java-5.1.30.jar中CallableStatement,现在做个简单的解读: 代码@1,判断SQL语句是否以CALL语句开头,如果不是,则调用代码@2fakeParameterTypes方法, 我可以很负责任人的告诉你,该方法只是固定返回一个参数列表,完全与调用的存储过程的出参列表不匹配 代码@3,调用后端连接,得到存储过程的源信息:发送的语句为:SELECT name, type, comment FROM mysql.proc WHERE name like ‘存储过程名’ and db <=> ‘数据库名’ ORDER BY name, type; 但mycat的处理如下:io.mycat.server.ServerConnection 的public void execute(String sql, int type) 方法: 跟进MysqlProcHandler.handle方法得知,mycat只是返回空数据给前端连接,并没有去后端执行该语句。所以,mybatis配置文件的statementType不能陪在为CALLABLE的原因。…

Read More

MyCat不支持的SQL语句

已知的MyCat不支持的SQL语句类型如下(不完全统计,后续会更新):   SELECT: Ø 跨分片(实体库)的交叉查询 Ø 跨节点的联合查询 (如用户库的表和平台库的表做联合查询) INSERT: Ø 插入的字段不包含分片字段 (如插入tbl_user_base_info表,没有提供user_id列) Ø 插入的分片字段找不到对应分片 Ø 复制插入Insert into…select… Ø 多行插入 insert into tab_a(c1,c2) values(v1,v2),(v11,v21)… UPDATE: Ø 更新的列包含分片列 Ø 多表更新 update a, b set a.nation=’China’, b.pwd=’123456’ where a.id=b.id Ø 复杂更新 update a, b set a.nation=’China’ where a.id=b.id;  但支持子查询方式 update a set a.nation=’China’ where id in (select id from b); DELETE: Ø 复杂删除 delete a from a join b on a.id=b.id;  支持子查询方式 delete from a where a.id in (select id from b), 但表不能起别名 其它: Ø Call procedure()   MyCat未支持存储过程定义, 因而不允许调用存储过程,但可通过注解来调用各个分片上的存储过程 Ø Select func(); 不支持这种方式直接调用自定义函数, 但支持 select id, func() from employee 只需employee所在的所有分片上存在这个函数。MySql自带函数可随意使用。     注意事项: Ø Order by字段必须出现在select中(MyCat先将结果取出,然后排序) Ø Group by务必使用标准语法 select count(1),type from tab_a group by type; Ø MyCat的一些自带函数 sum,min,max等可以正确使用,但多分片执行的avg有bug,执行的结果是错误的 Ø 谨慎使用子查询,外层查询没有分片查询条件, 则会在所有分片上执行(子查询内外层的表一样较为特殊)

vue-cli怎么根据后端接口服务器不同 build不同接口代码?

琢磨了几天vue-cli生成的代码,vue觉得你只需要三种配置:开发(npm run dev)、生产(npm run build)和单元测试(npm run test)。。。 吐槽完。 1.打开config/index.js,修改build里面的env文件名为根据环境变量获取, 修改完大概是下面这样子: module.exports = { build: { env: require(‘./’+(process.env.VUE_CONFIG||’prod’)+’.env’), //…… 2.在config目录里面把prod.env.js复制两份,分别是uat.env.js、testing.env.js 3.修改dev.env.js、uat.env.js、testing.env.js、prod.env.js这四个文件,在大括号里面添加API: ‘”/api或uat或其他什么”‘,如下: module.exports = { NODE_ENV: ‘”production”‘, API: ‘”/api”‘ } 4.然后就可以在任何地方通过process.env.API访问到这个变量了。 5.打包的时候,先设置环境变量VUE_CONFIG,例如export VUE_CONFIG=uat && npm run build。

chpasswd -e

对系统定期修改密码是一个很重要的安全常识,通常,我们修改用户密码都使用 passwd user 这样的命令来修改密码,但是这样会进入交互模式,即使使用脚本也不能很方便的批量修改,除非使用expect 这样的软件来实现,难道修改一下密码还需要单独安装一个软件包吗? 不,我们其实还有其他很多方法可以让我们避开交互的,下面具体写一下具体的实现方式: 第一种: echo “123456” | passwd –stdin root 优点:方便快捷 缺点:如果你输入的指令能被别人通过history或者其他方式捕获,那么这样的方式是很不安全的,更重要的是如果密码同时含有单引号和双引号,那么则无法通过这种方法修改。 说明: 批量修改linux密码 passwd –stdin user 从标准输入中读取密码,所以用户可以在脚本中使用如 echo NewPasswd | passwd –stdin username 这种方式来批量更改密码 但在其它的一些发行版(如Debian/Suse)所提供的passwd并不支持–stdin这个参数 第二种: a. 首先将用户名密码一起写入一个临时文件. cat chpass.txt root:123456 zhaohang:123456 b. 使用如下命令对用户口令进行修改: chpasswd < chpass.txt c. 可以使用 123456 来登录系统,密码修改完毕. 优点:可以很快速方便的修改多个用户密码 缺点:明文密码写在文件里仍然显得不够安全,但是避免了第一种修改方式不能有特殊字符串密码的情况. 第三种: a. 用 openssl passwd -1 来生成用户口令,连同用户名一起写入文件. cat chpass.txt root:$1$ri2hceVU$WIf.firUBn97JKswK9ExO0 zhaohang:$1$i/Gou7.v$Bh2K6sXmxV6/UCxJz8N7b. b. 使用如下命令对用户口令进行修改:…

Read More

pinpoint 安装部署

阅读目录 1. 环境配置     1.1 获取需要的依赖包     1.2 配置jdk1.7 2. 安装Hbase     2.1 解压Hbase     2.2 修改Hbase的配置     2.3 启动Hbase 3. 安装pinpoint-collector     3.1 部署war包     3.2 配置快速启动 4. 安装pinpoint-web     4.1 部署war包     4.2 配置快速启动 5. 安装pinpoint-agent     5.1 部署pp-agent     5.2 部署测试App     5.3 配置pp-agent     5.4 监控测试应用 序章 pinpoint是开源在github上的一款APM监控工具,它是用Java编写的,用于大规模分布式系统监控。它对性能的影响最小(只增加约3%资源利用率),安装agent是无侵入式的,只需要在被测试的Tomcat中加上3句话,打下探针,就可以监控整套程序了。这篇Blog主要是想记录一下它安装的过程,方便日后查阅。   我安装它用到的2台 CentOS6.8 虚拟机,一台主要部署pinpoint的主程序,一台模拟测试环境。配置如下: IP 操作系统 安装项 描述…

Read More

[转]用linux下常用命令wget进行整站下载(递归下载至本地)

这个命令可以以递归的方式下载整站,并可以将下载的页面中的链接转换为本地链接。 wget加上参数之后,即可成为相当强大的下载工具。 wget -r -p -np -k http://xxx.com/abc/ -r, –recursive(递归) specify recursive download.(指定递归下载) -k, –convert-links(转换链接) make links in downloaded HTML point to local files.(将下载的HTML页面中的链接转换为相对链接即本地链接) -p, –page-requisites(页面必需元素) get all images, etc. needed to display HTML page.(下载所有的图片等页面显示所需的内容) -np, –no-parent(不追溯至父级) don’t ascend to the parent directory. 另外断点续传用-nc参数 日志 用-o参数 熟练掌握wget命令,可以帮助你方便的使用linux。 如果需要查阅完整详细的帮助说明可以看这里:wget 中文详细使用说明

Linux wget命令整站下载做网站镜像

在linux下完整的用wget命令整站采集网站做镜像 的命令是: wget -m -e robots=off -U “Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6” “http://www.example.com/” wget命令 参数注释: “-e robots=off”  让wget耍流氓无视robots.txt协议 -U “Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6”  伪造agent信息