string::c_str() string::data()

两者返回的都是字符串对象底层字符数组的指针,但是c_str()返回的是以空字符结尾的数组指针,而data()返回的是不以空字符结尾的数组指针。

CI/CD/CO的含义

CI continuous integration 持续集成

代码打包,更新代码版本,构建成可用于下发的包,例如民汉写的代码经过code cc,环境打包形成一个版本,可用于后续发布。

关注的是开发人员将代码变成制品(tgz包)的过程,涉及到repalce代码的管理、开发环境及工具、代码编译、代码扫描,单元测试等环节。主要目的就是加快构建频率,尽早的发现问题,并且及早修复。

从研发团队提交代码作为起点,经过构建扫描测试等环节,以版本仓库为终点

这中间,需要对每个新功能或者问题修复创建自动化测试用例。对新提交的代码执行自动化测试。

通过自动化测试可以提早拿到测试结果,测试成本也大幅降低,CI服务器可以在几秒钟运行上百条测试。

CD continuous deployment 持续部署/发布

用CI生成的包,进行服务的部署,例如民汉当时的版本下发到具体机器

通过了接口测试及功能测试后,将制品和运行环境依赖的组件,通过dockerfile或其他方式生成镜像,提交仓库,等待发布到预发布、灰度、线上环境。

以版本仓库为起点,经过各模块自动化部署,到业务上线提供服务为终点,可以一键部署,自动触发发布流程

CO cotinuous operation 持续运营

对线上服务做配额、参数的动态配置及运营策略调整而出发的操作,比如扩缩容、配置文件修改、服务启停等等。所有和线上服务相关的运营操作

从业务上线服务为起点,到业务下线终止服务,期间包含各种运营事件。

stub的含义

很多地方都可能出现stub这个词

  • 在测试中,可以理解成打桩服务,由于服务是需要成本的,如果写的程序需要调用服务A,而A的代价较高,我们又只想测试程序有无bug,则可以对服务打桩,程序调用的接口api不变,但是该api不访问真实的服务A,减少开销,聚焦于测试程序的可行性。

  • 在代码编写中,其实可以简单的理解成一个流程中需要调用某个api,但是这个api还没有开发好,或者说目前关注的是流程的跑通,而不是业务是否正确,可以对这种api写一个空方法(最简单的直接返回正确的结果),日后可以补充实现这个api。

  • 在rpc中,stub是客户端代码访问rpc服务的桥梁,通过stub类的对象来访问服务的访问。

0.0.0.0和127.0.0.1的区别

因为服务器可能有多个ip地址,外网地址、内网地址或者虚拟ip节点,0.0.0.0表示本机上的所有ip地址

如果一个服务在0.0.0.0上启动,那么客户端访问该服务器的外网、内网、虚拟ip地址均可以得到服务响应

而127.0.0.1是一个环回地址,所有发向这个地址的数据都会loopback,一般用在服务器调试的时候。多数情况下localhost是绑定在127.0.0.1上的,所以很多时候我们使用localhost就是环回地址,当然我们也可以更改localhost绑定的ip地址,这个可以通过查看/etc/hosts文件当前localhost代表哪个地址:

magic number 魔法数字

魔法数字一般指代码中莫名其妙出现的数字,必须通过阅读代码才能知道数字的含义,这类就叫魔法数字

名字服务

所谓名字服务就是将服务名与ip端口映射的服务,因为后台服务可能会更换机器,那么如果上游服务根据ip端口来访问的话就写死了,如果不修改上游服务代码,则后台服务所有的变更都只能在那台机器上。

名字服务就相当于是加了一层过渡,通过查服务的字符串名,得到当前该服务所处的ip端口,进行正常访问,无需修改上游服务。

vscode代码能够跳转(能找到引用)但是代码显示未定义、无法找到某个定义

问题描述:VS Code中出现“未定义标识符”,可以右键“转到声明”,但会一直出现红色提醒。

问题原因:VS Code intellisense不能自动找到需要的头文件路径,需要在用户设置中强制intellisense使用Tag Parser,递归方式检索头文件。

解决方式:找到工程对应的settings.json,并复制以下两个语句,在其中配置使用Tag Parser方式。

打开vscode的command palette,搜索settings.json:

并在其中加入:

"C_Cpp.intelliSenseEngineFallback": "Disabled", //需要添加的
"C_Cpp.intelliSenseEngine": "Tag Parser",  //  需要添加的

便能解决问题

tar命令

参数:

-c  :建立一个压缩档案的参数指令(create 的意思);

-x  :解开一个压缩档案的参数指令!

-t  :查看 tarfile 里面的档案!

特别注意,在参数的下达中, c/x/t 仅能存在一个!不可同时存在!

因为不可能同时压缩与解压缩。

-z  :是否同时具有 gzip 的属性?亦即是否需要用 gzip 压缩?

-j  :是否同时具有 bzip2 的属性?亦即是否需要用 bzip2 压缩?

-v  :压缩的过程中显示档案!这个常用,但不建议用在背景执行过程!

-f  :使用档名,请留意,在 f 之后要立即接档名喔!不要再加参数!

例如使用『 tar -zcvfP tfile sfile 』就是错误的写法,要写成

『 tar -zcvPf tfile sfile 』才对喔!

-p  :使用原档案的原来属性(属性不会依据使用者而变)

-P  :可以使用绝对路径来压缩!

-N  :比后面接的日期(yyyy/mm/dd)还要新的才会被打包进新建的档案中!

--exclude=FILE:在压缩的过程中,不要将 FILE 打包!

https://www.cnblogs.com/52linux/archive/2012/03/04/2379738.html

tar czvf my_pack.tgz mydir --exclude=file1 --exclude=dir1

注意dir1不要加后缀/,否则没有排除这个目录

crontab

查看crontab的执行日志: /var/log/cron 不能使用cat命令查看

1、crontab执行定时任务时,所在的路径是根路径/root,所以如果脚本中使用了相对路径,就会执行失败,甚至出错。

2、crontab -e,或者直接编辑crontab的文件时,使用%必须进行转义,因为crontab遇到%就会认为是标准输入的开始。:

0 3 * * * mysqldump -u user -pxxxx database > "/alidata/backup/imyzf.com/$(date +%F\ %T).sql"

3、crontab的环境变量是另外定义的。通过cat /etc/crontab你会发现默认的PATH是/sbin:/bin:/usr/sbin:/usr/bin,如果要使用自己想要的环境变量,应当在脚本中先执行source /etc/profile等指定了环境变量的文件。

crontab -e 编辑crontab文件,添加或删除要执行的任务;通过这种方式添加的任务会自动根据当前添加任务的用户是谁,来确定到时候执行的用户是谁,例如root添加的,那么执行的时候就是root身份。

man 5 crontab 可以查看crontab的使用方法

crontab -l 列出现在的所有任务

shell获取系统时间并格式化

time=$(date "+%Y-%m-%d %H:%M:%S")

mysql的replace into和insert into的区别

两者都可以实现插入新数据的功能

replace into 首先会根据主键/唯一字段来查找本次插入的数据是否已经存在:

是的话则先删除已有的数据行,然后再插入

如果没有的话,则直接插入。

使用replace into不会出现插入失败。

如果表中没有主键/唯一字段,则不会判断上述逻辑,直接插入。

而insert into如果发现已经有了某行数据(如果表中没有主键/唯一字段)的话,则会直接报重复记录,插入失败的错误。

mysql已有数据的表增加自增列

一个表中,自增列只有一个。https://cloud.tencent.com/developer/article/1532394

更改已有列为字增列:

alter table my_table modify column my_column_name int(11) unsigned auto_increment;

如果该字段的已有数据,则下一次新增记录时,使用当前该列的最大数值+1.

例如当初最大为10000,则下次新增该字段为10001

指定下次新增字段是自增列的值(或者叫设置自增列的起始值):

alter table my_table auto_increment=10002;

则新记录的该自增列将从10002开始。

mysql的自增列在insert时存在竞争

早先最常见的就是在一个数据中心采用一个全局的锁,做一自增长的id算法。比如说使用Mysql的自增长ID。但这样做会造成系统的瓶颈,性能和可用性都会受到很大的影响。于是snowflake id的设计是避免了使用全局锁,每台ID生成的服务器都可以独立地生成自己的ID,而且不会产生重复。因为大家可以看到每个id都会带有一定位数的机器ID,这样就可以保证不同机器生成的id不会重复。

但是自增列又有好处,可以令数据底层存储更加顺序,减少页分裂,查询效率也高,具体场景需要根据业务情况进行权衡。

自增列的较为详细的使用教程:

https://www.cnblogs.com/kerrycode/p/9294767.html

mysql 4种sql语句来避免重复插入

https://cloud.tencent.com/developer/article/1738721

要维护mysql连接池的原因

官方的说法是:操作(operations)。也就是说把【多次的单一词条插入操作】整合成为【一次的多词条插入操作】这个是提高Insert速度的基础。原因很简单,在数据里做插入操作的时候,整体时间的分配是这样的:

  1. 链接耗时 (30%)

  2. 发送query到服务器 (20%)

  3. 解析query (20%)

  4. 插入操作 (10% * 词条数目)

  5. 插入index (10% * Index的数目)

  6. 关闭链接 (10%)

上面的百分比是官方给出的近似比例。从这里可以看出来,真正耗时的不是操作,而是链接,解析的过程,这也就是为什么【多次的单一词条插入操作】的耗时要比 【一次的多词条插入操作】高的根本原因

如果是多线程连接mysql,一种能够有效减少行锁冲突的方式是数据库加一个线程相关的id,这样每个线程都去查询或者修改自己负责的这些行,就可以减少线程之间竞争行锁。

快照读和当前读,快照读读的是事务开始的那一刻数据库的数据,此时后续的快照读都是基于这个快照进行的,看不到新的修改,而如果是当前读 select * from my_table for update,那么就会读取现在最新的数据库数据,如果读的数据刚好被别的会话得到了锁,那么就会在当前读的时候阻塞,等待锁的释放。(可重复读就是一种快照读)

在可重复读的隔离级别下,进行了一个小测试:

create table tt(id int(11), name varchar(12));
insert into tt values(1,"rex"),(2,"chloew");

transaction 1:

begin;
select * from tt;
update tt set name='newrex' where name='rex';

执行到第三步的结果:

可见对数据进行了修改,影响的行数为1

先不commit事务1,此时执行事务2

transaction 2:

begin;
select * from tt;
update tt set name='newnewrex' where name='rex';

此时,事务2会被阻塞挂起,因为事务1已经获得了这行的行锁

然后对事务1 commit,随后锁释放,事务2得以执行,其第三步执行结果为:

可以看到,事务2的update操作并没有修改记录,影响行数为0.

这是因为,在事务1commit之后,该行记录的name字段已经变成newrex,而不是rex,所以事务2获得锁执行update时的筛选条件并没有命中某一行,所以修改了0行。如果事物2的第三步语句为:

update tt set name='newnewrex' where name='newrex';

才会产生修改。

mysql支持四种级别的隔离,但如果对于同时写入同一条数据而言,实际上还是锁的竞争,mysql的锁有表锁、行锁、意向锁、间隙锁,不同的锁的访问限制不一样,但多个事务或者说多个客户端对同一个数据的并发修改,都是要竞争锁的,然后根据得到锁的顺序进行数据的修改。

说白了,就是要根据业务场景和并发量,选择合适的锁和事物隔离级别,已得到最好的qps。

C++11支持类似go一样的结构体列表初始化格式

struct my_struct{
    int a,b,c;
    string str;
}
int main(){
    my_struct test{a:1,b:2,c:3,};
    return 0;
}

上面可以看到,使用了类似字典kv一样的初始化方式,同时未指定初始值的变量将采用默认值(经测试为零值)。

mysql异常

Incorrect string value: '\xE6\xB5\x8B\xE8\xAF\x95' for column 'region_name'

这是因为字符集不对造成的,例如可能你的数据表是latin1,而你当前客户端会话设置的字符集是utf8,那么有可能utf8编码的格式latin1不识别,就会导致插入失败。

所以只需要根据数据表的字符集,在插入前set names就行。

开发时查询的一些脚本写法

shell教程:https://www.runoob.com/linux/linux-shell-basic-operators.html

使用$变量名就可以引用变量:

$var1
${var1}//两种方式都可以

可通过在变量面前加$来获取变量的值。

为了能使shell正确的界定变量名,可以在引用变量时使用大括号将变量括起来

如:

v4=123

echo “${v4}abc”

结果:123abc

(若直接echo “$v4abc”,会变成空字符串,因为v4abc没有被定义)

https://liam.page/2016/11/08/Shell-variable-reference-and-string-cut-off/

统计文件中某个词的词频

more filename  | grep -o "pattern" | wc -l

grep -o 只现实匹配的pattern部分,o(only matching)

遍历目录下的每个文件

for file in./*
do
    echo ${file}
done

if语句

https://blog.csdn.net/doiido/article/details/43966819

https://blog.csdn.net/m0_37138008/article/details/72814543

语法:

if
then
 
else
fi

条件判断中的单双括号的区别:

https://www.cnblogs.com/zeweiwu/p/5485711.html

使用双括号能够有效避免语法错误,有种单括号是双括号的子集的感觉。

if的判断条件:

基本上和其他脚本语言一样。没有太大区别。不过值得注意的是。[]里面的条件判断。

1 字符串判断

str1 = str2      当两个串有相同内容、长度时为真

str1 != str2      当串str1和str2不等时为真

-n str1        当串的长度大于0时为真(串非空)

-z str1        当串的长度为0时为真(空串)

str1         当串str1为非空时为真

2 数字的判断

int1 -eq int2    两数相等为真

int1 -ne int2    两数不等为真

int1 -gt int2    int1大于int2为真

int1 -ge int2    int1大于等于int2为真

int1 -lt int2    int1小于int2为真

int1 -le int2    int1小于等于int2为真

3 文件的判断

-r file     用户可读为真

-w file     用户可写为真

-x file     用户可执行为真

-f file     文件为正规文件为真

-d file     文件为目录为真

-c file     文件为字符特殊文件为真

-b file     文件为块特殊文件为真

-s file     文件大小非0时为真

-t file     当文件描述符(默认为1)指定的设备为终端时为真

3 复杂逻辑判断

-a         与

-o        或

!        非

结尾

语法虽然简单,但是在SHELL里使用的时候,他的功能变得强大了。

附 表:

[ -a FILE ] 如果 FILE 存在则为真。

[ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真。

[ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真。

[ -d FILE ] 如果 FILE 存在且是一个目录则为真。

[ -e FILE ] 如果 FILE 存在则为真。

[ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。

[ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真。 [ -h FILE ] 如果 FILE 存在且是一个符号连接则为真。

[ -k FILE ] 如果 FILE 存在且已经设置了粘制位则为真。

[ -p FILE ] 如果 FILE 存在且是一个名字管道(F如果O)则为真。

[ -r FILE ] 如果 FILE 存在且是可读的则为真。

[ -s FILE ] 如果 FILE 存在且大小不为0则为真。

[ -t FD ] 如果文件描述符 FD 打开且指向一个终端则为真。

[ -u FILE ] 如果 FILE 存在且设置了SUID (set user ID)则为真。

[ -w FILE ] 如果 FILE 如果 FILE 存在且是可写的则为真。

[ -x FILE ] 如果 FILE 存在且是可执行的则为真。

[ -O FILE ] 如果 FILE 存在且属有效用户ID则为真。

[ -G FILE ] 如果 FILE 存在且属有效用户组则为真。

[ -L FILE ] 如果 FILE 存在且是一个符号连接则为真。

[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则为真。

[ -S FILE ] 如果 FILE 存在且是一个套接字则为真。

[ FILE1 -nt FILE2 ] 如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1 exists and FILE2 does not则为真。

[ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在则为真。

[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则为真。

[ -o OPTIONNAME ] 如果 shell选项 “OPTIONNAME” 开启则为真。

[ -z STRING ] “STRING” 的长度为零则为真。

[ -n STRING ] or [ STRING ] “STRING” 的长度为非零 non-zero则为真。

[ STRING1 == STRING2 ] 如果2个字符串相同。 “=” may be used instead of “==” for strict POSIX compliance则为真。

[ STRING1 != STRING2 ] 如果字符串不相等则为真。

[ STRING1 < STRING2 ] 如果 “STRING1” sorts before “STRING2” lexicographically in the current locale则为真。

[ STRING1 > STRING2 ] 如果 “STRING1” sorts after “STRING2” lexicographically in the current locale则为真。

[ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers.

while语句

while
do
 
done

脚本程序挂起

sleep 1//睡眠1s,可以给浮点数
usleep 1//睡眠1微秒

curl获取返回码

curl -I -m 10 -o /dev/null -s -w %{http_code} www.baidu.com

-I 仅测试HTTP头

-m 10 最多查询10s

-o /dev/null 屏蔽原有输出信息

-s silent 模式,不输出任何东西

-w %{http_code} 控制额外输出

即返回码会写到变量http_code中,通过${http_code}获取结果

冒烟测试

冒烟测试是测试用例的子集,测试主要为了覆盖了组件或系统的最重要功能,并用于辅助评价一个软件的主要功能是否正常运行。

所谓冒烟测试其实就是在转测之前,开发同学对代码的所有功能点进行一次测试,相当于跑通每个功能,不是深入的测试,深入的测试需要转给测试同学。

冒烟测试是为了避免程序设计存在明显缺陷,还没跑通就送给测试同学,浪费人力和时间。

冒烟测试的叫法来源,最初是指电路板更改之后,看通电是否冒烟,如果电路板有缺陷,就会短路冒烟,所以才有这个说法。

ABtest、灰度发布的区别

灰度发布很好理解,就是版本经过测试后,发布更新给用户的过程,是一个逐渐递增的发布,在过程中去检测是否有线上问题,若有可以回滚,若无则可以全量灰度。

灰度发布则是指在新的功能上线以及没有上线之间能够保证新的版本可以稳定过渡的一种发布方法,可以在灰度发布的过程当中解决一些问题或者对新版本做出一些可以提高用户体验的调整,这是保证网站可以平稳更新到新版本的有效过程。

而ABtest其实就是做实验一样,有个对照组和实验组,将两个版本的程序分别给随机的给不同的用户使用,在这个过程中采集两个版本的反馈,来选择版本和判断版本的更新是否合理,可用来收集用户的反馈,确定产品迭代的功能。和灰度发布很像,这是因为ABtest是灰度发布的一种方式。

灰度测试和灰度发布概念很像,可以这么理解,灰度测试是已经确认了发布版本,只是一个逐渐放量的过程,出现问题只是回滚取消发布,不会涉及功能的变更。

而ABtest则是偏向于得到用户的结果,在多个版本中选择更好的,看哪种功能的版本更符合用户需求,是通过结果来决策,而灰度测试只是一个过程,版本功能是不会变的。

Cookies

cookies是访问网站时,网站服务器传回来的一些信息,是存在请求者本地上的,在有这个网站的cookies之后,访问该网站的服务,如果需要cookies中的某些信息,例如token,就会直接在请求头中一并带走,可以使得网站服务器知道用户的前置信息,来实现响应,例如避免每次用户访问页面都要重新登录。

HTTP cookies (also called web cookies, Internet cookies, browser cookies, or simply cookies) are small blocks of data created by a web server while a user is browsing a website and placed on the user's computer or other device by the user’s web browser. Cookies are placed on the device used to access a website, and more than one cookie may be placed on a user’s device during a session.

Cookies serve useful and sometimes essential functions on the web. They enable web servers to store stateful information (such as items added in the shopping cart in an online store) on the user’s device or to track the user's browsing activity (including clicking particular buttons, logging in, or recording which pages were visited in the past). They can also be used to save for subsequent use information that the user previously entered into form fields, such as names, addresses, passwords, and payment card numbers.

wiki:https://en.wikipedia.org/wiki/HTTP_cookie#Origin_of_the_name

ping通 telnet不通的原因

两者是不同的层级协议,ping是ip层的icmp协议,走网络层,所以即使两台机器之间存在防火墙或者网络隔离,都是可以ping通的,因为不需要再往上走更高层的协议。

有些防火墙和网络隔离会隔离不同层级的协议,所以传输层协议的数据包也有可能不通。

而telnet是应用层协议,防火墙/网络隔离肯定会屏蔽这类协议,所以自然而然就telnet不通了。

telnet ip port

组包直接ip port发包访问rpc

肯定是可以的,因为rpc是应用程序,网络请求包来了,程序会自动处理该请求包,然后通过读请求包的信息,来执行特定的方法。

如果自己写的rpc中用的是自定义的协议,若判断调用哪个方法的逻辑是根据请求包中的字段信息来判断,那么只要这个包有这些信息,那么直接ip port访问自然是可以的。

md5

md5是对文件二进制数据进行计算的,按照每512位为一个分组进行计算,所以在计算前会将文件补齐到512的整数倍。计算的结果是一个128位二进制数,如果用十六进制数来表示,那么就有32个十六进制数,这就是为什么计算结果都是32个十六进制数的原因:

2704de0c18321705f9d899e2564a8eb5

因此只要文件数据不同,算出来的md5就不同(不考虑碰撞的情况下),所以同一张图片,模糊和清晰的md5就不同,因为像素不一样,文件数据也不一样。想要判断图片是否同源,需要更高级的算法。

md5经过研究不是安全的hash算法,后续有更安全的hash算法,例如sha1,sha2等。

修改db权限不影响连接,只是增删改查会失败而已

core文件正确的使用方式:

gdb program_bin program_core_file

这样才能正确获取符号信息

core文件的路径可以通过/proc/sys/kernel/core_pattern查看,是否在core文件名中给出pid信息可以通过/etc/sysctl.conf给出

获取本机ip的方法

ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"

https://www.cnblogs.com/poloyy/p/12212868.html

遍历protobuf,获取字段类型和值信息

Message* message = &your_proto;
const google::protobuf::Descriptor* desc = message->GetDescriptor();
const google::protobuf::Reflection* ref = message->GetReflection();
for (int i = 0; i < desc->field_count(); ++i) {
  const google::protobuf::FieldDescriptor* field_desc = desc->field(i); 
  switch (field_desc->cpp_type()) {
    case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
      // call get_int32
      break;
    case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
      // call get_int64
      break;
    ...
  }
}

查看某个进程的启动路径

ps -elf | grep your_prog #获取进程id

得到进程id后

ll /proc/pid