什么是设计模式 设计模式 (Design pattern) 代表了最佳实践 通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。 使用设计模式是为了重用代码,让代码更容易被他人理解,保证代码可靠性。 设计模式是软件工程的基石,如同大厦的一块块砖石一样。 项目中合理使用设计模式可以完美解决很多问题,每种设计模式都描述了我们周围不断重复发生的问题,以及该问题核心解决方案。 什么是GOF 在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书 四位作者合称 GOF(四人帮,全拼 Gang of Four) 他们所提出的设计模式主要是基于以下的面向对象设计原则。 对接口编程而不是对实现编程 优先使用对象组合而不是继承 设计模式的类型 根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)

Go 并发

golang 天生语言层面支持并发, 非常棒的语言, 有时我们业务开发时, 遇到复杂场景, 需要用于并发, 将多个请求使用协程组完成并发, 当遇到嵌套循环,还存在上下文关系需要改造为并发请求, 将之前的时间复杂度为O(n^2)改为O(n)的时间复杂度, 那是否还能否并时间复杂度进一步降为O(1)呢? 就出现嵌套并发. 具体如何嵌套并发, 如何写. 今天就一步一步分析. 串行执行 时间复杂度为O(n^2) 不使用并发 结果执行时间为 9s // 串行执行 func SerializeRun() { start := time.Now() xx := []int{1, 2, 3} yy := []int{100, 200, 300} for _, x := range xx { for _, y := range yy { abc(x, y) } } fmt.Printf("串行执行总时间:%s\n", time.Since(start)) } func abc(x, y int) { time.Sleep(time.Second * 1) fmt.Printf("x:%d, y:%d\n", x, y) } 执行结果
写项目时,有时我们需要缓存, 缓存就会需要唯一的key. 常规是对字符串求md5指纹. 在golang里我们也可以使用, 目前可以计算一个字符串的crc32, md5, sha1的指纹. md5 : 一种被广泛使用的密码散列函数,可以产bai生出一个128位(du16字节)的散列值(hash value),用于确保信息传输完整一zhi致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。 sha1: SHA1是由NISTNSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1基于MD5,MD5又基于MD4。 crc32: 本身是“冗余校验码”的意思,CRC32则表示会产生一个32bit(8位十六进制数)的校验值。由于CRC32产生校验值时源数据块的每一个bit(位)都参与了计算,所以数据块中即使只有一位发生了变化,也会得到不同的CRC32值。 golang 实现 md5 // md5值 func Md5Str(s string) string { hash := md5.Sum([]byte(s)) return hex.EncodeToString(hash[:]) } sha1 // 散列值 func Sha1Str(s string) string { r := sha1.Sum([]byte(s)) return hex.EncodeToString(r[:]) } crc32 // String hashes a string to a unique hashcode. // https://github.com/hashicorp/terraform/blob/master/helper/hashcode/hashcode.go // crc32 returns a uint32, but for our use we need // and non negative integer.
采用 centos 安装, jmeter 5.3版本 安装 java jdk 环境 JDK1.8版本即可满足 yum install java-1.8.0-openjdk 下载 jmeter cd /home/ wget https://mirrors.bfsu.edu.cn/apache//jmeter/binaries/apache-jmeter-5.3.zip unzip apache-jmeter-5.3.zip cd apache-jmeter-5.3 pwd 配置环境变量 官方下载: https://jmeter.apache.org/download_jmeter.cgi export JMETER=/home/apache-jmeter-5.3 export CLASSPATH=$JMETER/lib/ext/ApacheJMeter_core.jar:$JMETER/lib/jorphan.jar:$JMETER/lib/logkit-2.0.jar:$CLASSPATH export PATH=$JMETER/bin/:$PATH 使用 首先在 window 版本上新建jmx文件, 然后保存为测试计划. 将 jmx 文件上传到 linux , 使用以下命令运行即可. 得到 jtl 结果文件, 下载下来, 导入到可视化界面上,即可查看到分析的结果. jmeter -n -t test.jmx -l test.jtl 图示: 保存 test.jmx 文件 图示: 导入分析结果
curl post json 如果多个头信息, 多次使用-H即可. curl -H "Content-Type: application/json" -X POST --data '{"username:":"abc", "password":"abc"}' http://www.github.com/login -H 请求头信息 -X 请求方式, GET, POST --data 数据 ab post json ab -r -k -c 50 -n 100 -T 'application/json' -p json.txt http://www.github.com/login json.txt { "username":"abc", "password":"1234" } -T就Content-Type -H 自定义头信息 Token:111 -c 请求并发数 -n 请求数. -r 不要退出套接字接收错误 -k 保持 KeepAlive
window 10环境下安装 python3.8 版本. 采用国内镜像, 国内官方下载实在太慢, 无法忍受. 下载安装 推荐华为镜像下载. https://mirrors.huaweicloud.com/python/3.8.0/ 选择 window 64 位 下载后,双击文件 python 安装的目录 勾选加入环境变量. 如果忘记勾选需要配置环境变量. 右击我的电脑->高级系统设置->环境变量->系统变量(最下面的框)->找到path变量名称->点击编辑->点击新建->把 python的目录加入即可.(即安装时的目录) 配置 pip pip 是安装 python 模块的工具. 还是那样, 默认下载源非常慢, 配置国内源. window 10 找到 C:\Users\<yourname>\AppData\Roaming\pip 也许你找不到这个目录, <yourname>是你的计算机名称, AppData 是一个隐藏目录, 点击输入栏输入AppData进入, 然后找到Roaming, 如果没有找到pip目录,请新建一个pip目录, 然后在pip目录下新建一个pip.ini文件, 填下以下内容即可. [global] index-url = https://mirrors.huaweicloud.com/repository/pypi/simple trusted-host = mirrors.huaweicloud.com timeout = 120 更新 pip 打开你的cmd工具, 输入 python -m pip install --upgrade pip即可更新 划线部分显示采用了刚才配置的源信息.说明没有走官网的源.这样非常快的更新完了. 如果你的界面没有动, 回车一下即可.(window常见的毛病) 如果镜像不好用,可以临时指定镜像, 如安装 requests 库
Filebeat是用于转发和集中日志数据的轻量级传送程序。作为服务器上的代理安装,Filebeat监视您指定的日志文件或位置,收集日志事件,并将它们转发到Elasticsearch或 Logstash进行索引。 架构 工作原理是启动 filebeat 时, 它将启动一个或多个输入, 这些输入将在日志数据指定位置中查找, 对于 filebeat 所找到的每个日志, filebeat 都会启动收集器, 每个收割机都读取单个日志以获取新内容,并将新日志数据发送到libbeat,libbeat将聚集事件,并将聚集的数据发送到为Filebeat配置的输出。 配置输入源, 可以是日志(log), 也可以是标准输入(stdin), 可以配置多个输入(input) 为每个日志启一个(Harvester) 收集器, 将不停的读取数据 数据卷轴, 将数据不断的输出到其它终端 终端, 如 es, kafaka, redis 原理 Filebeat由两个主要组件组成:prospector 和 harvester harvester 收集器 负责读取单个文件的的内容,如果文件被删除啦,也会继续监听这个文件的变化. prospector 探测器 prospector 负责管理 harvester 并找到所有要读取的文件来源 如果输入类型是日志类型, 则查找器路径匹配的所有文件, 并为每一个文件启动一个 harvester 收集器 filebeat 目前支持两种 prospector 类型: stdin 和 log Filebeat 如何保持文件的读取状态 Filebeat 保存每个文件的状态并经常将状态刷新到磁盘上的注册文件中。 注册文件位于 /usr/local/filebeat/data/registry/filebeat/data.json 该状态用于记住harvester正在读取的最后偏移量,并确保发送所有日志行。 如果输出(例如Elasticsearch或Logstash)无法访问,Filebeat会跟踪最后发送的行,并在输出再次可用时继续读取文件 安装 官方下载 https://www.elastic.co/cn/downloads/beats/filebeat, 一般国内都很慢, 推荐使用国内镜像下载. https://mirrors.huaweicloud.com/filebeat/ 找到对应的版本. 我这里使用是 7.8.0 版本
基于 filebeat 7.8.0 7filebeat 监听文件的变化, 进行记录文件位移, 从而实现不断读取数据,并收割数据并输送到指定终端或服务 配置 配置文件需要注意,分顶格写, - 表示数组, 缩进采用2个空格方式 输出控制台 监听文件夹下的所有*.log文件, 并自定义字段, tags标识 cd /usr/local/filebeat vim test.yml # 输入配置 filebeat.inputs: - type: log # 定义输入的类型, 可以是 stdin, log, tcp, udp, json enabled: true # 启动 paths: # 文件路径, 可以是多个路径 - /data/logs/tmp/*.log # 配置要监听读取的文件路径, *表示通配符 tags: ["sgfoot"] # 自定义标签, 可以设置多个 fields: # 自定义字段, 默认在 fields 节点下, 可以通过 fields_under_root = true 设置为跟节点 www: sgfoot # 设置字段, key => value fields_under_root: false # true 为根目录, false 是在 fields 节点下.
介绍 Character Filter 在 Tokenizer 之前对文本进行处理, 例如增加删除及替换字符, 可以配置多个 Character Filters, 会影响 Tokenizer 的 position 和 offset 信息 自带: html_strip, mapping, pattern replace Tokenizer 将原始的文本按照一定的规则, 切分为词 (term or token) 自带: whitespace, standard/ pattern/ keyword/ path hierarchy Token Filter 将 Tokenizer 输出的单词 (term), 进行增加, 修改, 删除. 如自带的 lowercase, stop, synonym(添加近义词) 定义分词器 过滤html标签 # 自定义分词器 POST _analyze { "tokenizer": "keyword", "char_filter": ["html_strip"], "text":"<b>hello world</b>" } 过滤之后的结果 { "tokens" : [ { "token" : "hello world", "start_offset" : 3, "end_offset" : 18, "type" : "word", "position" : 0 } ] } 替换 将一个字符替换成其它字符
Mapping的定义 可以对索引的数据字段设置类型, 还可以设置不变索引.也就是说不被搜索到. PUT users { "mappings": { "properties": { "firstName":{ "type": "text" }, "lastName":{ "type": "text" }, "mobile":{ "type": "text", "index": false # 设置不变索引的字段 } } } } 结果 { "acknowledged" : true, "shards_acknowledged" : true, "index" : "users" } 添加真实数据. PUT users/_doc/1 { "firstName":"sg", "lastName":"foot", "mobile":"123" } 对已经禁止索引的mobile字段查询 POST /users/_search { "query": { "match": { "mobile": "123" } } } 结果显示报错是: { "error" : { "root_cause" : [ { "type" : "query_shard_exception", "reason" : "failed to create query: Cannot search on field [mobile] since it is not indexed.