
一般我们存储简单处理就是写三副本,但是三副本的成本太大了,采用纠删码可以比较好的降低存储空间的成本,具体看下golang中的代码实现。 // 纠删码测试 // 将一个文件拆分成10分,删除其中的任意三分,尝试还原文件 // 这边需要注意的一点是文件的拆分后的顺序和还原的顺序是相关的,顺序错误是无法还原的 // 其中Encoder接口有以下几个关键的函数。 // Verify(shards [][]byte) (bool, error)。每个分片都是[]byte类型,分片集合就是[][]byte类型,传入所有分片,如果有任意的分片数据错误,就返回false。 // Split(data []byte) ([][]byte, error)。将原始数据按照规定的分片数进行切分。注意:数据没有经过拷贝,所以修改分片也就是修改原数据。 // Reconstruct(shards [][]byte) error。 这个函数会根据shards中完整的分片,重建其他损坏的分片。 // Join(dst io.Writer, shards [][]byte, outSize int) error。将shards合并成完整的原始数据并写入dst这个Writer中。 package main import ( "flag" "fmt" "io/ioutil" "os" "strings" "github.com/klauspost/reedsolomon" "github.com/qtj/gosdk/file" ) 定义和初始化验证一些参数 var ( srcFile string // 原始文件 dstDir string // 目标目录 recoverName string // 还原后的文件名称 dataShards int // 数据分片 parityShards int // 校验分片 oper string // 操作动作 ) func init() { flag.StringVar(&srcFile, "srcFile", "qtjErasureCode.exe", "原始文件名称") flag.StringVar(&dstDir, "dstDir", "dstDir", "目标目录") flag.StringVar(&recoverName, "recoverName", "recoverName", "还原后的文件名称") flag.StringVar(&oper, "oper", "", "split和recover二选一,split会将一个文件拆分成类似10个数据文件和3和校验文件,recover的时候可以删除目标目录下的三个文件做还原即可") flag.IntVar(&dataShards, "dataShards", 10, "数据分片个数") flag.IntVar(&parityShards, "parityShards", 3, "校验分片个数") flag.Parse() } 主调用 // qtjErasureCode.exe -oper=split先将文件拆分 // 删除当前目录下的子文件夹dstDir里面的任意三个文件 // qtjErasureCode.exe -oper=recover -recoverName="recover.exe" 将文件还原 // 最后比对md5发现是一致的 func main() { if !strings.Contains(dstDir, "/") && !strings.Contains(dstDir, "\\") { dstDir = file.GetCurDir() + dstDir + "/" } if oper == "split" { file.RemoveDirTree(dstDir) file.CreateDirTree(dstDir) if err := splitFile(); err != nil { fmt.Println(err) return } } else if oper == "recover" { if err := recoverFile(); err != nil { fmt.Println(err) return } } else { fmt.Println("错误的操作动作参数,oper必须为split或者recover") return } } 还原文件验证 func recoverFile() error { if recoverName == "" { return fmt.Errorf("还原后的文件名称%s不能为空", recoverName) } // 数据分10片和校验3片 enc, err := reedsolomon.New(dataShards, parityShards) if err != nil { return fmt.Errorf("创建数据分片和校验分片失败,%s", err.Error()) } shards := make([][]byte, dataShards+parityShards) for i := range shards { splitName := fmt.Sprintf("%ssplit%010d", dstDir, i) // 不管文件是否存在,需要保留原先的顺序 if shards[i], err = ioutil.ReadFile(splitName); err != nil { fmt.Printf("读取文件[%s]失败,%s\n", splitName, err.Error()) } fmt.Println(splitName) } ok, err := enc.Verify(shards) if ok { fmt.Println("非常好,数据块和校验块都完整") } else { if err = enc.Reconstruct(shards); err != nil { return fmt.Errorf("重建其他损坏的分片失败,%s", err.Error()) } if ok, err = enc.Verify(shards); err != nil { return fmt.Errorf("数据块校验失败2,%s", err.Error()) } if !ok { return fmt.Errorf("重建其他损坏的分片后数据还是不完整,文件损坏") } } f, err := os.Create(recoverName) if err != nil { return fmt.Errorf("创建还原文件[%s]失败,%s", recoverName, err.Error()) } // 这部分的大小决定了还原后的大小和原先的是不是一致的,不然使用md5比对或者大小都是不一样的 // 实际生产需要一开始就拆分文件时候就记录总的大小 //if err = enc.Join(f, shards, len(shards[0])*dataShards); err != nil { _, ln, err := file.GetFileLenAndMd5(srcFile) if err != nil { return fmt.Errorf("计算原始文件[%s]大小失败,%s", srcFile, err.Error()) } if err = enc.Join(f, shards, int(ln)); err != nil { return fmt.Errorf("写还原文件[%s]失败,%s", recoverFile(), err.Error()) } return nil } 分隔文件处理 func splitFile() error { // 数据分10片和校验3片 enc, err := reedsolomon.New(dataShards, parityShards) if err != nil { return fmt.Errorf("创建数据分片和校验分片失败,%s", err.Error()) } bigfile, err := ioutil.ReadFile(srcFile) if err != nil { return fmt.Errorf("读取原始文件[%s]失败,%s", srcFile, err.Error()) } // 将原始数据按照规定的分片数进行切分 shards, err := enc.Split(bigfile) if err != nil { return fmt.Errorf("针对原始文件[%s]拆分成数据[%d]块,校验[%d]块失败,%s", srcFile, dataShards, parityShards, err.Error()) } // 编码校验块 if err = enc.Encode(shards); err != nil { return fmt.Errorf("编码校验块失败,%s", err.Error()) } for i := range shards { splitName := fmt.Sprintf("%ssplit%010d", dstDir, i) fmt.Println(splitName) if err = file.SaveFile(shards[i], splitName); err != nil { return fmt.Errorf("原始文件[%s]拆分文件[%s]写失败,%s", srcFile, splitName, err.Error()) } } return nil }
下载etcdetcdkeeper cd /opt/wget https://github.com/evildecay/etcdkeeper/releases/download/v0.7.5/etcdkeeper-v0.7.5-linux_x86_64.zip 解压 unzip etcdkeeper-v0.7.5-linux_x86_64.zipmv etcdkeeper /usr/local/chmod +x /usr/local/etcdkeeper/etcdkeeper 将etcdkeeper注册成服务 touch /lib/systemd/system/etcdkeeper.service 将下面的内容填充到etcdkeeper.service文件中 [Unit]Description=etcdkeeper serviceAfter=network.target[Service]Type=simpleExecStart=/usr/local/etcdkeeper/etcdkeeper -p=8880ExecReload=/bin/kill -HUP $MAINPIDKillMode=processRestart=on-failurePrivateTmp=true[Install]WantedBy=multi-user.target 设置开机自启动 systemctl enable etcdkeeper.service 启动etcdkeeper服务 systemctl start etcdkeeper 停止etcdkeeper服务 systemctl stop etcdkeeper 访问地址,里面可以选择v2和v3 http://localhost:8880
创建目录 mkdir -p /opt/ioTest/mkdir -p /opt/ioTest/cd /opt/ioTest/ time计时,dd用于复制,从if读出,写到ofif=/dev/zero不产生IO,因此可以用来测试纯写速度of=/dev/null不产生IO,可以用来测试纯读速度 测试写速度: time dd if=/dev/zero of=/opt/ioTest/out bs=8k oflag=direct count=500000 测试读速度: time dd if=/opt/ioTest/out of=/dev/null bs=8k 测试读写速度: cp /opt/ioTest/out /opt/ioTest/intime dd if=/opt/ioTest/in of=/opt/ioTest/out bs=8k oflag=direct 使用fio测试iops wget http://brick.kernel.dk/snaps/fio-3.16.tar.gzyum install libaio-develtar -zxvf fio-3.16.tar.gzcd fio-3.16makemake install 顺序读: fio -filename=/opt/ioTest/out -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest 随机写: fio -filename=/opt/ioTest/out -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest 顺序写: fio -filename=/opt/ioTest/out -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest 混合随机读写: fio -filename=/opt/ioTest/out -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest -ioscheduler=noop
卸载自带的mariadb yum -y remove mariadb-libs.x86_64 mkdir /home/vitess/cd /home/vitess/wget http://dev.mysql.com/get/mysql-5.7.27-1.el7.x86_64.rpm-bundle.tartar -xvf mysql-5.7.27-1.el7.x86_64.rpm-bundle.tar rpm -ivh mysql-community-common-5.7.27-1.el7.x86_64.rpm rpm -ivh mysql-community-libs-5.7.27-1.el7.x86_64.rpm rpm -ivh mysql-community-client-5.7.27-1.el7.x86_64.rpmrpm -ivh mysql-community-server-5.7.27-1.el7.x86_64.rpm 启动mysql: service mysqld start 查看并修改mysql密码 cat /var/log/mysqld.log|grep -n password 查询出来的密码值为A4)p3cfKnFyt,这个密码一定要记住 mysql -u root -p输入刚刚的密码登录 在里面输入 set global validate_password_policy =0;set global validate_password_length=6; 在执行下面命令将密码修改成123456 alter user root@localhost identified by '`123qwer'; 给root开通远程访问权限 GRANT ALL PRIVILEGES ON . TO 'root'@'%' IDENTIFIED BY '`123qwer';flush privileges; 设置mysql不区分大小写 vi /etc/my.cnf最后一行加上下面一句lower_case_table_names=1max_connections=512 重启mysql systemctl restart mysqld 给mysql添加超级管理员vitess 登录mysql执行下面命令 set global validate_password_policy =0;set global validate_password_length=6;create user 'vitess'@'%' identified by '`123qwer';grant all on . to vitess@'%' identified by '`123qwer';grant all on . to vitess@'%' with grant option;flush privileges; 关闭和禁用防火墙 systemctl stop firewalld;systemctl disable firewalld;
查看数据库连接 select * from information_schema.PROCESSLIST; 查询当前库中表是否存在 select count(*) from information_schema.tables where TABLE_SCHEMA=database() and table_name ='bp_import_tb'; 查看表结构的关键信息 SELECT t.column_name, t.column_comment, t.ordinal_position, t.column_type FROM information_schema.COLUMNS t WHERE table_name = 'bu_data_tb' order by t.ordinal_position; 查看库使用空间 select TABLE_SCHEMA, concat(truncate(sum(data_length)/1024/1024,2),'MB') as data_size,concat(truncate(sum(index_length)/1024/1024,2),'MB') as index_sizefrom information_schema.tables group by TABLE_SCHEMA order by data_size desc; 查看具体表的索引 show index from bp_index_tb; 查看有索引的表 SELECT distinct table_name, index_name FROM mysql.innodb_index_stats WHERE database_name = database() order by table_name, index_name; 通过系统表查询记录总数 select table_name,table_rows from information_schema.tableswhere TABLE_SCHEMA = database() order by table_name asc; 判断subject_no是否全为数字 SELECT * FROM t_major_catalog where length(0+subject_no)=length(subject_no); 判断sub_subject_name字段是否为中文 SELECT * FROM t_major_catalog WHERE NOT (sub_subject_name REGEXP "[u0391-uFFE5]"); 判断sub_subject_name字段是否包含数字 SELECT * FROM tb_temp where sub_subject_name regexp '[0-9]' 修改列名 alter table t_tmp_qtj_xls你好 change field0 aaa varchar(1024) 已有数据表中添加自增长qtj_id alter table t_tmp_qtj_xls你好 add qtj_id intalter table t_tmp_qtj_xls你好 change qtj_id qtj_id int not null auto_increment primary key; 查询uuid select uuid();select replace(uuid(), '-', ''); 大小写转换 SELECT LOWER('MySql');SELECT UPPER('MySql'); 关联修改 update t_major_catalog a, tb_temp b set a.sub_subject_name = b.sub_subject_name where a.sub_subject_no=b.sub_subject_no main_major_name右取总长度-2 update t_main_major set main_major_name = substr(main_major_name,3) 将长度为5的前补零 update t_subject set subject_no = concat('0', subject_no) where length(subject_no)=5 mysql 取日期和时间 select now(), curdate(),curtime(),left(sysdate(),10), right(sysdate(),8) varchar转int select field1,cast(field1 as SIGNED INTEGER) from t_test order by cast(field1 as SIGNED INTEGER) 有就不插入 insert into sc_field_append_tb (table_name, field_name, insert_date, insert_time )select 'bu_data_rsda_tb', 'category_no', curdate(), curtime() from DUAL where not exists (select * from sc_field_append_tb where table_name = 'bu_data_rsda_tb' and field_name = 'category_no') 表连接,没有设置为0 select concat(en_id, ' ', a.category_name), IFNULL(b.cnt,0) from sc_qtj_rsda_define_tb a leftjoin (select big_category, count(*) cnt from bu_qtj_xml_category_tb where xml_md5 = '5dfafc20e8391023da30c1329ca956aa' group by big_category) bon a.category_id=b.big_category order by a.category_id 将order_sub_no字段中的左边的-符号去除 update bu_temp_rsda_catalogue_tb set order_sub_no = trim(leading '-' from order_sub_no)where archive_unique_code = '2401121032'; 创建方法 DROP FUNCTION IF EXISTS func_import_excel;delimiter ;;CREATE DEFINER=root@localhost FUNCTION func_import_excel() RETURNS int(11)BEGIN insert into bu_import_tb(guid_,insert_date, insert_time, name, id_card, old_archive_no, now_archive_no, sex, key_no, archive_time, work_company, phone, archive_status, graduate_time, graduate_school, highest_degree) select guid_,curdate(), curtime(), 姓名, 身份证号, 原档案号, 档案号, 性别, 唯一码, 存档时间, 工作单位, 手机号码, 档案状态, 毕业时间, 毕业学校, 最高学历 from t_tmp_import where guid_ not in (select guid_ from bu_import_tb); RETURN 0; END;;delimiter ; 使用方法 select func_import_excel() 创建存储过程 delimiter ;;CREATE PROCEDURE proc_import_excel()BEGIN insert into bu_import_tb(guid_,insert_date, insert_time, name, id_card, old_archive_no, now_archive_no, sex, key_no, archive_time, work_company, phone, archive_status, graduate_time, graduate_school, highest_degree) select guid_,curdate(), curtime(), 姓名, 身份证号, 原档案号, 档案号, 性别, 唯一码, 存档时间, 工作单位, 手机号码, 档案状态, 毕业时间, 毕业学校, 最高学历 from t_tmp_import where guid_ not in (select guid_ from bu_import_tb); END;;delimiter ; 使用存储过程 call proc_import_excel()
先保证centos7中有安装ansible,没有则按照 yum install epel-release -yyum install ansible –y 下载tidb-ansible指定版本 从https://github.com/pingcap/tidb-ansible/releases中下载tidb-ansible-3.0.2.zip解压到/home/qtj/tikv/中 下载 cd tidb-ansible-3.0.2ansible-playbook local_prepare.yml 下面是截取的一些提示片段 TASK [local : unarchive tidb binary] *changed: [localhost] => (item={u'url': u'http://download.pingcap.org/tidb-v3.0.2-linux-amd64.tar.gz', u'version': u'v3.0.2', u'name': u'tidb'}) ... PLAY RECAP *localhost : ok=32 changed=24 unreachable=0 failed=0 skipped=6 rescued=0 ignored=0 Congrats! All goes well. :-) 下载好的压缩包都在tidb-ansible-3.0.2/downloads目录下
使用参考: d := dir.NewDir("/") dirs, err := d.LoopLevelDir(0) // 实现遍历目录的功能// 也可以指定层级遍历,遍历几层目录package dir import ( "fmt" "io/ioutil" "strings" "time" ) type Dir struct { rootDir string // 需要遍历的根目录 curDirs []string // 当前级别的目录 dirs []string // 全部的目录 nDirLevel int // 当前目录级别 bInit bool // 是否初始化 } // 创建一个目录func NewDir(rootDir string) *Dir { var dir Dir dir.rootDir = rootDir dir.bInit = true dir.nDirLevel = 0 dir.curDirs = []string{rootDir} return &dir } // 只遍历单层目录func (d *Dir) loopOneDir(dirPath string) ([]string, error) { var ds []string // 如果是读取目录失败的,就是没有权限,直接返回空就好了 dir, err := ioutil.ReadDir(dirPath) if err != nil { return nil, nil //return nil, fmt.Errorf("ioutil.ReadDir(%s)错误,%s", dirPath, err.Error()) } for _, fi := range dir { if fi.IsDir() { onePath := strings.Replace(dirPath+"/"+fi.Name(), "//", "/", -1) ds = append(ds, onePath) } } return ds, nil } // 遍历目录,如果nLevel为0表示一直遍历下去直到为空截止func (d *Dir) LoopLevelDir(nLevel int) ([]string, error) { if !d.bInit { return nil, fmt.Errorf("未初始化") } var err error for { d.nDirLevel++ var tmpAllDirs, tmpOneDirs []string for i := 0; i < len(d.curDirs); i++ { if tmpOneDirs, err = d.loopOneDir(d.curDirs[i]); err != nil { return nil, fmt.Errorf("遍历根目录[%s]失败,%s", d.rootDir, err.Error()) } tmpAllDirs = append(tmpAllDirs, tmpOneDirs...) } d.curDirs = tmpAllDirs if len(tmpAllDirs) == 0 { break } fmt.Printf("[%s] 第[%d]层目录遍历完成,共计[%d]文件夹\n", FormatTime(), d.nDirLevel, len(tmpAllDirs)) d.dirs = append(d.dirs, tmpAllDirs...) if d.nDirLevel >= nLevel && nLevel != 0 { break } } return d.dirs, nil } // 获得当前格式化的数据,形如2017-03-15 16:07:32.236func FormatTime() string { return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d", time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), time.Now().Nanosecond()/1e6) }
从mongodb官网下载mongodb-win32-x86_64-2008plus-ssl-4.0.10.zip将zip解压并命名成d:/mongodb新建D:/mongodb/data/, D:/mongodb/logs/两个文件夹cmd进入D:/mongodb/bin目录输入mongod --dbpath D:/mongodb/data/再新开一个cmd进入D:/mongodb/bin文件夹,输入mongo use admindb.createUser({user: "mgdb",pwd: "123456",roles: [ {role: "userAdminAnyDatabase", db: "admin"} ]})添加mongodb的用户mgdb和设置对应的密码 在D:/mongodb/bin/下创建mongod.cfg,内容如下(这个配置文件是yaml格式的,建议用atom等编辑器或者在线编写保存) systemLog: destination: file path: D:/mongodb/logs/MongoDB.logstorage: dbPath: D:/mongodb/data/net: bindIp: 127.0.0.1,0.0.0.0 port: 27017 关闭原先打开的cmd窗口,以管理员身份运行cmd进入D:/mongodb/bin文件夹,输入将mongodb安装成服务mongod --config D:/mongodb/bin/mongod.cfg --install services.msc即发现MongoDB服务已经注册成功了。
git clone https://github.com/golang/net.git src/github.com/golang/netgit clone https://github.com/golang/sys.git src/github.com/golang/sysgit clone https://github.com/golang/tools.git src/github.com/golang/toolsgit clone https://github.com/golang/lint.git src/github.com/golang/lintgit clone https://github.com/golang/mod.git src/github.com/golang/modgit clone https://github.com/golang/text.git src/github.com/golang/textgit clone https://github.com/golang/crypto.git src/github.com/golang/crypto然后复制到src/golang.org/x/目录下 git clone https://github.com/googleapis/google-cloud-go src/cloud.google.com/go然后复制到src/cloud.google.com/go/目录下 git clone https://github.com/grpc/grpc-go.git src/google.golang.org/grpcgit clone https://github.com/golang/appengine src/google.golang.org/appengine然后复制到src/google.golang.org/目录下 go get -u github.com/gocolly/colly/...
服务端开启server的时候设置 maxSize := 20 * 1024 * 1024 s := grpc.NewServer(grpc.MaxRecvMsgSize(maxSize), grpc.MaxSendMsgSize(maxSize)) PbDownMaxSize.RegisterPbDownMaxSizeServer(s, &server{}) s.Serve(listener) 客户端连接的时候设置 maxSize := 20 * 1024 * 1024 diaOpt := grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxSize), grpc.MaxCallSendMsgSize(maxSize)) conn, err := grpc.Dial(endpoint, grpc.WithInsecure(), diaOpt)
查看内核版本 uname -r 导入key rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org 安装elrepo的yum源 rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm 安装内核 在yum的elrepo源中有ml和lt两种内核。其中ml(mainline)为最新的稳定主线版本内核,lt为长期支持的内核。 我们选择长期支持的版本安装 yum --enablerepo=elrepo-kernel -y install kernel-lt // 最新版本为 yum --enablerepo=elrepo-kernel -y install kernel-ml 目前下载的长期支持的内核版本为kernel-lt-4.4.179-1.el7.elre 内核升级完毕后,不会修改默认启动的内核顺序,默认启动的还是原来的内核版本,需要我们修改grub.conf文件设置系统启动顺序 查看系统启动项: cat /boot/grub2/grub.cfg |grep menuentry 可以发现有新版本的内核'CentOS Linux (4.4.179-1.el7.elrepo.x86_64) 7 (Core)',将新版本内核为默认启动: grub2-set-default 'CentOS Linux (4.4.179-1.el7.elrepo.x86_64) 7 (Core)' grub2-set-default 0 grub2-mkconfig -o /etc/grub2.cfg reboot,重启之后发现默认启动内核为新版内核,执行 uname -r 发现内核也是新的内核。
// 安装需要的软件包,yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的 yum install -y yum-utils device-mapper-persistent-data lvm2 // 设置yum源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo // 可以查看所有仓库中所有docker版本,并选择特定版本安装 yum list docker-ce --showduplicates | sort -r // 安装docker yum install docker-ce-18.09.6-3.el7 // 启动并加入开机启动 systemctl start docker systemctl enable docker // 验证安装是否成功(有client和service两部分表示docker安装启动都成功了) docker version // 建议更换docker的镜像源:// 修改或创建daemon.json文件:vi /etc/docker/daemon.json// 将以下配置写入到文件中,保存并退出{"registry-mirrors": ["http://hub-mirror.c.163.com"]} // 重启docker: service docker restart // 安装docker-compose// 具体可以参考https://github.com/docker/compose/releases curl -L https://github.com/docker/compose/releases/download/1.24.0/docker-compose-uname -s-uname -m -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose
centos7查看版本 cat /etc/redhat-release // 我这边是 CentOS Linux release 7.6.1810 (Core) 强制删除已安装程序及其关联 rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps 删除所有残余文件 ##xargs,允许你对输出执行其他某些命令 whereis python |xargs rm -frv 验证删除,返回无结果 whereis python 从http://vault.centos.org/7.5.1804/os/x86_64/Packages/下载版本,大版本要对应,7.6.1810用的7.5.1804版本的 python包下载到/opt/software/python/中(wget已经不能用了,页面下载的直接拷贝文件即可,也可以在其他机器上wget) http://vault.centos.org/7.5.1804/os/x86_64/Packages/lvm2-python-libs-2.02.177-4.el7.x86_64.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/libxml2-python-2.9.1-6.el7_2.3.x86_64.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-libs-2.7.5-68.el7.x86_64.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-ipaddress-1.0.16-2.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-backports-1.0-8.el7.x86_64.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-backports-ssl_match_hostname-3.5.0.1-1.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-2.7.5-68.el7.x86_64.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-iniparse-0.4-9.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-pycurl-7.19.0-19.el7.x86_64.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-urlgrabber-3.10-8.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-setuptools-0.9.8-7.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-kitchen-1.1.1-5.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/python-chardet-2.2.1-1.el7_1.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/rpm-python-4.11.3-32.el7.x86_64.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/yum-utils-1.1.31-45.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/yum-3.4.3-158.el7.centos.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/yum-metadata-parser-1.1.4-10.el7.x86_64.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/yum-plugin-aliases-1.1.31-45.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/yum-plugin-protectbase-1.1.31-45.el7.noarch.rpmhttp://vault.centos.org/7.5.1804/os/x86_64/Packages/yum-plugin-fastestmirror-1.1.31-45.el7.noarch.rpm 上面的包也可以从百度网盘下载,地址:https://pan.baidu.com/s/1h9S5jLKm9PjqPkBWQ_BC1w,密码:njyz 将上面的包放到/opt/software/python/下面,执行下面的命令 rpm -Uvh --replacepkgs python*.rpm 删除原有YUM rpm -aq|grep yum|xargs rpm -e --nodeps --force 即使覆盖属于其它包的文件也强迫安装 --nodeps 如果该RPM包的安装依赖其它包,即使其它包没装,也强迫安装。 rpm -Uvh --replacepkgs rpm-python.rpm yum.rpm --force --nodeps 将yum源配置为网易和阿里的开源镜像 备份原来的镜像源 cd /etc/yum.repos.d/ mkdir repo_bak mv *.repo repo_bak/ 下载阿里和网易源 wget http://mirrors.aliyun.com/repo/Centos-7.repo wget http://mirrors.163.com/.help/CentOS7-Base-163.repo 清除系统所有的yum缓存 yum clean all 生成yum缓存 yum makecache 安装epel源 yum install -y epel-release 使用阿里开源镜像提供的epel源 wget -O /etc/yum.repos.d/epel-7.repo http://mirrors.aliyun.com/repo/epel-7.repo 再次清除系统yum缓存,并重新生成新的yum缓存 yum clean all yum makecache 查看系统可用的yum源和所有的yum源 yum repolist enabled
通过unsafe.Alignof查看内存对齐情况,在X64中8位对齐,在x86中4位对齐int在X64中相当于int64,在x86中相当于int32,所以对应的长度分别是8和4string在X64中长度16,在X86中长度为8[]数组长度在X64为24,X86为12 下面两个结构体的长度计算 type s1 struct { a byte //1 b int //8 c int8 //1 d []byte //24 e int //8 f byte //1 g string //16 }在X64长度为80,在X86长度为40,将结构体更改顺序后生成s2如下 type s2 struct { a byte //1 b byte //1 c int8 //1 d int //4 e int //4 f string //8 g []byte //12 }s2在X64长度为64,在X86长度为32 根据上面的结果发现,不同的位置顺序对应的内存大小占用是有可能相差很大的
先用 go get go.etcd.io/etcd/clientv3 获得etcd的客户端 下面为测试代码package main import ( "fmt" "time" "go.etcd.io/etcd/clientv3" context "golang.org/x/net/context" ) func main() { cli, err := clientv3.New(clientv3.Config{ Endpoints: []string{"localhost:2379", "localhost:22379", "localhost:32379"}, DialTimeout: 5 * time.Second, }) if err != nil { fmt.Println("clientv3.New faild", err) return } fmt.Println("clientv3.New success") defer cli.Close() ctx, cancel := context.WithTimeout(context.Background(), time.Second*50) defer cancel() i := 0 for { resp, err := cli.Put(ctx, fmt.Sprintf("sample_key_%d", i), "sample_value") if err != nil { fmt.Println("clientv3 put key faild", err) return } fmt.Println("clientv3 put key success, return", resp) if i == 10 { break } i++ time.Sleep(time.Second) } time.Sleep(time.Second * 3) }
删除centos7自带的jdk,先输入下面的命令查找已安装的java包rpm -qa | grep java 列出内容如下java-1.8.0-openjdk-1.8.0.102-4.b14.el7.x86_64javapackages-tools-3.4.1-11.el7.noarchjava-1.8.0-openjdk-headless-1.8.0.102-4.b14.el7.x86_64tzdata-java-2016g-2.el7.noarchpython-javapackages-3.4.1-11.el7.noarchjava-1.7.0-openjdk-headless-1.7.0.111-2.6.7.8.el7.x86_64java-1.7.0-openjdk-1.7.0.111-2.6.7.8.el7.x86_64 删除已安装的javarpm -e --nodeps java-1.8.0-openjdk-1.8.0.102-4.b14.el7.x86_64rpm -e --nodeps java-1.8.0-openjdk-headless-1.8.0.102-4.b14.el7.x86_64rpm -e --nodeps java-1.7.0-openjdk-headless-1.7.0.111-2.6.7.8.el7.x86_64rpm -e --nodeps java-1.7.0-openjdk-1.7.0.111-2.6.7.8.el7.x86_64 下载jdk-8u191-linux-x64.tar.gz到/opt/soft/,并解压至/usr/local/tar zxvf /opt/soft/jdk-8u191-linux-x64.tar.gz -C /usr/local/ 配置java环境变量 vi /etc/profile在最后添加下面内容export JAVA_HOME=/usr/local/jdk1.8.0_191 export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH=$PATH:$JAVA_HOME/bin 保存后输入source /etc/profile更新环境变量输入java -version和javac既可验证
yum -y install texinfomkdir /opt/soft/cd /opt/soft/wget http://ftp.gnu.org/gnu/gcc/gcc-8.2.0/gcc-8.2.0.tar.gztar -C /usr/local -xzf gcc-8.2.0.tar.gzcd /usr/local/gcc-8.2.0./contrib/download_prerequisites mkdir build cd build ../configure -enable-checking=release -enable-languages=c,c++ -disable-multilibyum groupinstall "Development Tools" make #这个步骤非常耗时长make install reboot #一定要记得重启 find / -name "libstdc++.so*"输出如下(最新动态库的目录)/usr/local/gcc-8.2.0/build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.25/usr/local/gcc-8.2.0/build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6/usr/local/gcc-8.2.0/build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so 复制最新动态库文件libstdc++.so.6.0.25到/usr/lib64下cp /usr/local/gcc-8.2.0/build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.25 /usr/lib64 复制后,修改系统默认动态库的指向,即:重建默认库的软连接。切换工作目录至/usr/lib64:cd /usr/lib64 删除原来软连接rm -rf libstdc++.so.6 将默认库的软连接指向最新动态库:ln -s libstdc++.so.6.0.25 libstdc++.so.6 默认动态库升级完成。重新运行以下命令检查动态库:strings /usr/lib64/libstdc++.so.6 | grep GLIBC gcc -v 查看版本号就变成8.2了
在musql的目录新建一个my.ini,内容如下 [mysql] 设置mysql客户端默认字符集 default-character-set=utf8 [mysqld] 设置3306端口 port = 3306 设置mysql的安装目录 basedir=c:mysqlmysql-5.7.17-winx64 设置mysql数据库的数据的存放目录 datadir=c:mysqlmysql-5.7.17-winx64data 允许最大连接数 max_connections=500 服务端使用的字符集默认为8比特编码的latin1字符集 character-set-server=utf8 创建新表时将使用的默认存储引擎 default-storage-engine=INNODB 以管理员身份打开cmd窗口后,将目录切换到你mysql安装目录的bin目录,分别执行下面语句 mysqld --initialize-insecure --user=mysqlmysqld installnet start mysql 然后输入 mysql -u root -p 提示输入密码,直接敲回车即可登录,登录之后执行SET PASSWORD = PASSWORD('123456');修改密码为123456 然后就可以通过mysql -u root -p123456登录了,记住-p和密码之间是没有空格的。 添加mysql的普通用户sun_mysql,密码设置为123456 create user 'sun_mysql'@'localhost' identified by '123456'; 设置该用户运行指定IP访问 GRANT ALL PRIVILEGES ON . TO 'sun_mysql'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;flush privileges; 在root用户下创建testdb库 grant all privileges on testdb.* to 'sun_mysql'@'%' identified by '123456';flush privileges; 如果需要修改设置该用户只允许本机访问输入delete from user where user = 'sun_mysql' and host != 'localhost';GRANT ALL PRIVILEGES ON . TO 'sun_mysql'@'localhost' IDENTIFIED BY '123456' WITH GRANT OPTION;flush privileges; 如果设置mysql运行指定的IP访问GRANT ALL PRIVILEGES ON . TO 'sun_mysql'@'110.110.110.46' IDENTIFIED BY '123456' WITH GRANT OPTION;flush privileges;
在14上启动14的consul,会自动创建目录consuldata consul agent -server -bootstrap-expect 1 -data-dir consuldata -node=node14 -bind=192.168.177.14 -ui-dir dist -datacenter=dc1 -client=0.0.0.0 在11上开启 consul agent -server -bootstrap-expect 2 -data-dir consuldata -node=node11 -bind=192.168.177.11 -ui-dir dist -datacenter=dc1 -client=0.0.0.0 在10上开启 consul agent -server -bootstrap-expect 2 -data-dir consuldata -node=node10 -bind=192.168.177.10 -ui-dir dist -datacenter=dc1 -client=0.0.0.0 在14上做添加 consul join 192.168.177.11 consul join 192.168.177.10 12以客户端的方式加入集群组中。consul agent -data-dir consuldata -node=node12 -bind=192.168.177.12 -datacenter=dc1 -client=0.0.0.0consul join 192.168.177.10
先上go http 服务代码 package main import ( "fmt" "net" "net/http" "os" "strconv" "time" ) var ( g_localip string ) func main() { var ( port = 8080 host_addr string err error ) if len(os.Args) >= 2 { if port, err = strconv.Atoi(os.Args[1]); err != nil { fmt.Printf("param2 [%s] must in (1~65535)", os.Args[1]) return } } g_localip = getLocalIP() host_addr = fmt.Sprintf(":%d", port) fmt.Printf("%s start httpsvr at [%s]", g_localip, host_addr) http.HandleFunc("/", mainHandle) http.ListenAndServe(host_addr, nil) } func mainHandle(w http.ResponseWriter, r *http.Request) { var ( temp string ) temp = fmt.Sprintf("%s, welcome! \ncurrent service machie is [%s], service time is [%s]", r.RemoteAddr, g_localip, formatTime()) w.Write([]byte(temp)) } func formatTime() string { return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d", time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), time.Now().Nanosecond()/1e6) } func getLocalIP() string { var ( addrs []net.Addr err error address net.Addr ipnet *net.IPNet ok bool ) if addrs, err = net.InterfaceAddrs(); err != nil { return "" } for _, address = range addrs { if ipnet, ok = address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil { return ipnet.IP.String() } } } return "" } 将上面的代码编译成http_test并放到/opt/http_test/目录下 进入下面目录 cd /etc/systemd/system/ 创建一个名为httptest.service文件,内容填写如下 [Unit]Description=httptest serviceAfter=network.target [Service]Type=simpleExecStart=/opt/http_test/http_test 8080 &ExecStop=/bin/kill-s QUIT $MAINPIDUser=rootRestart=on-abort [Install]WantedBy=multi-user.target 针对刚刚创建的文件添加执行权限 chmod 754 httptest.service 上面节点的含义分别如下 Description服务的简单描述 After依赖,仅当依赖的服务启动之后再启动自定义的服务单元 ExecStart 默认开启8080端口 sudo systemctl daemon-reloadsudo systemctl enable httptest.servicesudo systemctl start httptest.service --permanent永久生效,没有此参数重启后失效,防火墙打开8080端口,同时刷新防火墙 firewall-cmd --zone=public --add-port=8080/tcp --permanentfirewall-cmd --reload
192.172.0.84/85/86搭建etcd集群 --permanent永久生效,没有此参数重启后失效,防火墙打开2379和2380端口,同时刷新防火墙 firewall-cmd --zone=public --add-port=2379/tcp --permanentfirewall-cmd --zone=public --add-port=2380/tcp --permanentfirewall-cmd --reload 下载并解压etcd cd /home/vitess/wget https://github.com/etcd-io/etcd/releases/download/v3.4.1/etcd-v3.4.1-linux-amd64.tar.gztar -zxvf etcd-v3.4.1-linux-amd64.tar.gz -C /usr/local/mv /usr/local/etcd-v3.4.1-linux-amd64 /usr/local/etcd 添加环境变量 vi /etc/profile 在最后添加一行 export ETCDCTL_API=3执行source /etc/profile刷新环境变量 mkdir -p /var/lib/etcd/mkdir -p /etc/etcd/ 将etcd加入开机自启动中,创建对应的service文件 tee /usr/lib/systemd/system/etcd.service <<-'EOF'[Unit]Description=Etcd ServerAfter=network.targetAfter=network-online.targetWants=network-online.target [Service]Type=notifyWorkingDirectory=/var/lib/etcd/EnvironmentFile=-/etc/etcd/etcd.confExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/local/etcd/etcd --name=${NAME} --data-dir=${DATA_DIR} --initial-advertise-peer-urls ${INITIAL_ADVERTISE_PEER_URLS} --listen-client-urls=${LISTEN_CLIENT_URLS} --listen-peer-urls=${LISTEN_PEER_URLS} --advertise-client-urls=${ADVERTISE_CLIENT_URLS} --initial-cluster-token=${INITIAL_CLUSTER_TOKEN} --initial-cluster=${INITIAL_CLUSTER} --initial-cluster-state=${INITIAL_CLUSTER_STATE} "Restart=on-failureLimitNOFILE=65536 [Install]WantedBy=multi-user.targetEOF 上面的开机启动文件中使用了/etc/etcd/etcd.conf文件,下面是具体的conf文件,每台机器对应的IP地址是不一样的 tee /etc/etcd/etcd.conf <<-'EOF' 84节点 NAME=etcd84DATA_DIR="/var/lib/etcd/default.etcd"LISTEN_PEER_URLS="http://192.172.0.84:2380"LISTEN_CLIENT_URLS="http://192.172.0.84:2379,http://127.0.0.1:2379"INITIAL_ADVERTISE_PEER_URLS="http://192.172.0.84:2380"ADVERTISE_CLIENT_URLS="http://192.172.0.84:2379"INITIAL_CLUSTER_STATE="new"INITIAL_CLUSTER_TOKEN="etcd-cluster1"INITIAL_CLUSTER="etcd85=http://192.172.0.85:2380,etcd86=http://192.172.0.86:2380,etcd84=http://192.172.0.84:2380"EOF tee /etc/etcd/etcd.conf <<-'EOF' 85节点 NAME=etcd85DATA_DIR="/var/lib/etcd/default.etcd"LISTEN_PEER_URLS="http://192.172.0.85:2380"LISTEN_CLIENT_URLS="http://192.172.0.85:2379,http://127.0.0.1:2379"INITIAL_ADVERTISE_PEER_URLS="http://192.172.0.85:2380"ADVERTISE_CLIENT_URLS="http://192.172.0.85:2379"INITIAL_CLUSTER_STATE="new"INITIAL_CLUSTER_TOKEN="etcd-cluster1"INITIAL_CLUSTER="etcd85=http://192.172.0.85:2380,etcd86=http://192.172.0.86:2380,etcd84=http://192.172.0.84:2380"EOF tee /etc/etcd/etcd.conf <<-'EOF' 86节点 NAME=etcd86DATA_DIR="/var/lib/etcd/default.etcd"LISTEN_PEER_URLS="http://192.172.0.86:2380"LISTEN_CLIENT_URLS="http://192.172.0.86:2379,http://127.0.0.1:2379"INITIAL_ADVERTISE_PEER_URLS="http://192.172.0.86:2380"ADVERTISE_CLIENT_URLS="http://192.172.0.86:2379"INITIAL_CLUSTER_STATE="new"INITIAL_CLUSTER_TOKEN="etcd-cluster1"INITIAL_CLUSTER="etcd85=http://192.172.0.85:2380,etcd86=http://192.172.0.86:2380,etcd84=http://192.172.0.84:2380"EOF 通过systemctl start命令启动etcd服务,同时使用systemctl enable 命令将服务加入开机启动列表中 systemctl daemon-reloadsystemctl enable etcdsystemctl start etcdsystemctl status etcd 查看集群信息 ./etcdctl member list
创建型模式抽象工厂模式:提供一个接口用于创建相关对象的家族;Builder模式:使用简单的对象来构建复杂的对象;工厂方法模式:一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中;对象池模式:实例化并维护一组相同类型的对象实例;单例模式:限制类的实例,保证一个类只有一个实例。结构模式适配器模式:适配另一个不兼容的接口来一起工作;桥接模式:将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化;合成模式:将对象组织到树中,用来描述树的关系;装饰模式:给一个静态或动态对象添加行为;门面(Facade)模式:为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用;Flyweight模式:运用共享技术有效地支持大量细粒度的对象;MVC模式:是模型(model)-视图(view)-控制器(controller)的缩写,将一个应用程序划分成三个相互关联的部分,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。代理模式:为其他对象提供一种代理以控制对这个对象的访问。行为模式 责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系;命令模式:就是客户端发布一个命令(也就是“请求”),而这个命令已经被封装成一个对象。即这个命令对象的内部可能已经指定了该命令具体由谁负责执行;中介(Mediator)模式:用一个中介对象来封装一系列关于对象交互行为;观察者模式:对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新;注册(Registry)模式:跟踪给定类的所有子类;状态模式:基于一个对象的内部状态,给相同对象提供多种行为;策略模式:定义一系列算法,并将每一个算法封装起来,而且使它们可以相互替换;模板(Template)模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤;访问者模式:表示一个作用于某对象结构中的各元素的操作,它使开发者可以在不改变各元素类的前提下定义作用于这些元素的新操作。同步模式条件变量:利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使”条件成立”(给出条件成立信号);Lock/Mutex:执行互斥限制资源获得独占访问;监视器模式:互斥锁和条件变量的组合模式;读写锁定模式:它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作;Semaphore:负责协调各个线程,以保证它们能够正确、合理地使用公共资源。并行模式Bounded Parallelism:完成大量资源限制的独立任务;广播(Broadcast):把一个消息同时传输到所有接收端;协同(Coroutines):允许在特定地方暂停和继续执行的子程序;生成器:一次性生成一系列值;Reactor模式:在事件驱动的应用中,将一个或多个客户的服务请求分离(demultiplex)和调度(dispatch)给应用程序。同步、有序地处理同时接收的多个服务请求。并行(Parallelism):完成大量的独立任务;生产者消费者:从任务执行中分离任务;调度器(Scheduler):协调任务步骤。消息传递模式扇入(Fan-In):该模块直接调用上级模块的个数,像漏斗型一样去工作;扇出(Fan-Out):该模块直接调用的下级模块的个数;Futures & Promises:扮演一个占位角色,对未知的结果用于同步;Publish/Subscribe:将信息传递给订阅者;Push & Pull:把一个管道上的消息分发给多人。稳定模式Bulkheads:实施故障遏制原则,例如防止级联故障;断路器(Circuit-Breaker)模式:当请求有可能失败时,停止流动的请求;截止日期(Deadline):一旦响应变缓,允许客户端停止一个正在等待的响应;Fail-Fast机制:集合的一种错误检测机制。当多个线程对集合进行结构上的改变操作时,有可能会产生fail-fast机制;Handshaking:如果一个组件的不能访问请求被拒绝,询问是否还能承担更多负载;稳定状态(Steady-State):为每一个服务积累一个资源,其它服务必须回收这些资源;剖析模式Timing Functions:包装和执行日志的函数;成例Functional Options:允许给默认值创建clean API和惯用重载;反模式级联故障:一个系统的某部分出现错误,与之有关的上下级也随之出现故障,导致多米诺效应。