关于stack:MASA-Stack-10-发布会正式官宣

MASA Stack 1.0 发布会正式官宣2023/1/16 14:00线上直播与你不见不散 视频号与 b 站同步开启直播  如果你对咱们的 MASA Framework 感兴趣,无论是代码奉献、应用、提 Issue,欢送分割咱们WeChat:MasaStackTechOps QQ:7424099

January 11, 2023 · 1 min · jiezi

Go-逃逸分析

原文地址:Go 逃逸分析 堆和栈要理解什么是逃逸分析会涉及堆和栈的一些基本知识,如果忘记的同学我们可以简单的回顾一下: 堆(Heap):一般来讲是人为手动进行管理,手动申请、分配、释放。堆适合不可预知大小的内存分配,这也意味着为此付出的代价是分配速度较慢,而且会形成内存碎片。栈(Stack):由编译器进行管理,自动申请、分配、释放。一般不会太大,因此栈的分配和回收速度非常快;我们常见的函数参数(不同平台允许存放的数量不同),局部变量等都会存放在栈上。栈分配内存只需要两个CPU指令:“PUSH”和“RELEASE”,分配和释放;而堆分配内存首先需要去找到一块大小合适的内存块,之后要通过垃圾回收才能释放。 通俗比喻的说,栈就如我们去饭馆吃饭,只需要点菜(发出申请)--》吃吃吃(使用内存)--》吃饱就跑剩下的交给饭馆(操作系统自动回收),而堆就如在家里做饭,大到家,小到买什么菜,每一个环节都需要自己来实现,但是自由度会大很多。 什么是逃逸分析在编译程序优化理论中,逃逸分析是一种确定指针动态范围的方法,简单来说就是分析在程序的哪些地方可以访问到该指针。 再往简单的说,Go是通过在编译器里做逃逸分析(escape analysis)来决定一个对象放栈上还是放堆上,不逃逸的对象放栈上,可能逃逸的放堆上;即我发现变量在退出函数后没有用了,那么就把丢到栈上,毕竟栈上的内存分配和回收比堆上快很多;反之,函数内的普通变量经过逃逸分析后,发现在函数退出后变量还有在其他地方上引用,那就将变量分配在堆上。做到按需分配(哪里的人民需要我,我就往哪去~~,一个党员的呐喊)。 为何需要逃逸分析ok,了解完堆和栈各自的优缺点后,我们就可以更好的知道逃逸分析存在的目的了: 减少gc压力,栈上的变量,随着函数退出后系统直接回收,不需要gc标记后再清除。减少内存碎片的产生。减轻分配堆内存的开销,提高程序的运行速度。如何确定是否逃逸在Go中通过逃逸分析日志来确定变量是否逃逸,开启逃逸分析日志: go run -gcflags '-m -l' main.go-m 会打印出逃逸分析的优化策略,实际上最多总共可以用 4 个 -m,但是信息量较大,一般用 1 个就可以了。-l 会禁用函数内联,在这里禁用掉内联能更好的观察逃逸情况,减少干扰。逃逸案例案例一:取地址发生逃逸package maintype UserData struct { Name string}func main() { var info UserData info.Name = "WilburXu" _ = GetUserInfo(info)}func GetUserInfo(userInfo UserData) *UserData { return &userInfo}执行 go run -gcflags '-m -l' main.go 后返回以下结果: # command-line-arguments.\main.go:14:9: &userInfo escapes to heap.\main.go:13:18: moved to heap: userInfoGetUserInfo函数里面的变量 userInfo 逃到堆上了(分配到堆内存空间上了)。GetUserInfo 函数的返回值为 *UserData 指针类型,然后 将值变量userInfo 的地址返回,此时编译器会判断该值可能会在函数外使用,就将其分配到了堆上,所以变量userInfo就逃逸了。 ...

July 14, 2019 · 2 min · jiezi

vuepagestackVue页面堆栈管理器

Vue页面堆栈管理器A vue page stack manager Vue页面堆栈管理器 vue-page-stack 示例展示了一般的前进、后退(有activited)和replace的场景,同时还展示了同一个路由可以存在多层的效果(输入必要信息)目前版本还没有经过整体业务的测试,欢迎有同样需求的进行试用 预览 示例源码 需求分析由于重度使用了Vue全家桶在web App、公众号和原生Hybrid开发,所以很自然的会遇到页面跳转与回退这方面的问题。 场景举例: 列表页进入详情页,然后回退某操作页A需要在下一页面B选择,选择后需要退回到A页面(A页面还要知道选择了什么)在任意页面进入到登录页面,登录或者注册成功后返回到原页面,并且要保证继续回退是不会到登陆页面的支持浏览器的back和forward(微信或者小程序很有用)在进入、退出或者某些特殊页面的时候添加一些动画,比如模仿ios的默认动画(进入是页面从右向左平移,退出是页面从左向右平移)尝试过的方法尝试了以下方法,但是都没有达到我的预期 keep-alive一般是使用两个router-view通过route信息和keep-alive控制页面是否缓存,这样存在两个问题: keep-alive对相同的页面只会存储一次,不会有两个版本的相同页面两个router-view之间没有办法使用transition等动画CSS配合嵌套route曾经在查看cube-ui的例子的时候,发现他们的例子好像解决了页面缓存的问题,我借鉴(copy)了他们的处理方式,升级了一下,使用CSS和嵌套route的方式实现了基本的需求。但是也有缺点: 我必须严格按照页面的层级来写我的route很多页面在多个地方需要用到,我必须都得把路由配上(例如商品详情页面,会在很多个地方有入口)功能说明在vue-router上扩展,原有导航逻辑不需改变push或者forward的时候重新渲染页面,Stack中会添加新渲染的页面back或者go(负数)的时候不会重新渲染,从Stack中读取先前的页面,会保留好先前的内容状态,例如表单内容,滚动条滑动的位置等back或者go(负数)的时候会把不用的页面从Stack中移除replace会更新Stack中页面信息回退到之前页面的时候有activited钩子函数触发支持浏览器的后退,前进事件支持响应路由参数的变化,例如从 /user/foo 导航到 /user/bar,组件实例会被复用可以在前进和后退的时候添加不同的动画,也可以在特殊页面添加特殊的动画安装和用法安装npm install vue-page-stack# ORyarn add vue-page-stack使用import Vue from 'vue'import VuePageStack from 'vue-page-stack';// vue-router是必须的Vue.use(VuePageStack, { router }); // App.vue<template> <div id="app"> <vue-page-stack> <router-view ></router-view> </vue-page-stack> </div></template><script>export default { name: 'App', data() { return { }; }, components: {}, created() {}, methods: {}};</script>API注册注册的时候可以指定VuePageStack的名字和keyName,一般不需要 Vue.use(VuePageStack, { router, name: 'VuePageStack', keyName: 'stack-key' });前进和后退想在前进、后退或者特殊路由添加一些动画,可以在router-view的页面通过watch $route,通过stack-key-dir(自定义keyName这里也随之变化)参数判断此时的方向,可以参考实例 ...

June 5, 2019 · 1 min · jiezi

leetcode445-Add-Two-Numbers-II

题目要求You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.You may assume the two numbers do not contain any leading zero, except the number 0 itself.Follow up:What if you cannot modify the input lists? In other words, reversing the lists is not allowed.Example:Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)Output: 7 -> 8 -> 0 -> 7对以链表形式的两个整数进行累加计算。 ...

May 18, 2019 · 2 min · jiezi

Java中的栈

Java中的栈Java中的Stack是早期的遗留类,Sun/Oracle已经不推荐使用,现在只是为了兼容遗留代码而保留.遗留实现如下面的代码所示,java.util.Stack中的实现是基于动态数组实现的,而Vector同样是一个被废弃的类。个人看来,这个实现有两个问题基于Vector,需要同步因而性能损失很严重基于数组而非链表,栈很大时需要多次扩容,带来不必要的性能损失publicclass Stack<E> extends Vector<E> { /** * Creates an empty Stack. / public Stack() { } public E push(E item) { addElement(item); return item; } public synchronized E pop() { E obj; int len = size(); obj = peek(); removeElementAt(len - 1); return obj; } public synchronized E peek() { int len = size(); if (len == 0) throw new EmptyStackException(); return elementAt(len - 1); } public boolean empty() { return size() == 0; } public synchronized int search(Object o) { int i = lastIndexOf(o); if (i >= 0) { return size() - i; } return -1; } /* use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 1224463164541339165L;}自己简单的封装下面是基于LinkedList封装的Stack这里的栈是一个装饰器。import java.util.LinkedList;import java.util.NoSuchElementException;public class Stack<T> { private LinkedList<T> stack; Stack() { stack = new LinkedList<>(); } public void push(T o) { stack.add(o); } public T pop() { if (size() <= 0) { throw new NoSuchElementException(“Stack is Empty.”); } return stack.removeLast(); } public T peek() { if (size() <= 0) { throw new NoSuchElementException(“Stack is Empty.”); } return stack.getLast(); } public boolean empty() { return stack.size() == 0; } public int size() { return stack.size(); }} ...

March 28, 2019 · 1 min · jiezi

leetcode402. Remove K Digits

题目要求Given a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible.Note:The length of num is less than 10002 and will be ≥ k.The given num does not contain any leading zero.Example 1:Input: num = “1432219”, k = 3Output: “1219"Explanation: Remove the three digits 4, 3, and 2 to form the new number 1219 which is the smallest.Example 2:Input: num = “10200”, k = 1Output: “200"Explanation: Remove the leading 1 and the number is 200. Note that the output must not contain leading zeroes.Example 3:Input: num = “10”, k = 2Output: “0"Explanation: Remove all the digits from the number and it is left with nothing which is 0.假设现在有一个用字符串表示的非负的整数,问从中删除掉k个数字后能够得到的最小结果是多少?思路和代码直观的来说,删除数字得到最小的数字意味着我们应当尽可能的将越小的数字保留在高位,因此当我们从左往右遍历时,一旦遇到比前一个数字更小的数字,就应当删除前一个数字而保留这个数字。当我们用尽了所有删除时,就保留后面所有的数字,不再进行任何比较。因为我们已经尽可能获得了最小的最高位,因此无论后面的数字如何取值,其最高位上的数字一定是可以获得的最小的这个数字。举个例子:10200 k=1第一步: 0和1比较,此时0比1小,且还有一次可用的删除,因此删除1,保留0第二步:因为无可用的删除次数,因此剩下的值全部保留123450123 k=5第一步:2>1 保留第二步:3>2 保留第三步: 4>3 保留第四步: 5>4 保留第五步:0<5 删除5 保留0 k=4第六步: 0<4 删除4 保留0 k=3第七步:0<3 删除3 保留0 k=2第八步:0<2 删除2 保留0 k=1第九步:0<1 删除1 保留0 k=0第十步: 此时所有的删除次数用完,因此剩余的值全部保留可以看到,当我们遇到较小值时,我们会尽可能的将其往左边移动,因为只要它比左边的值小且剩余删除次数,则删除左边的值一定会得到一个更小的值。代码如下: public String removeKdigits(String num, int k) { if(num == null || num.length() == 0 || k==num.length()) return “0”; Stack<Character> stack = new Stack<>(); for(int i = 0 ; i < num.length() ; i++) { char c = num.charAt(i); while(k> 0 && !stack.isEmpty() && stack.peek() > c) { stack.pop(); k–; } stack.push(c); } while(k > 0) { stack.pop(); k–; } StringBuilder result = new StringBuilder(); while(!stack.isEmpty()) { result.append(stack.pop()); } while(result.length() > 1 && result.charAt(result.length()-1) == ‘0’) { result.deleteCharAt(result.length()-1); } return result.reverse().toString(); } ...

March 8, 2019 · 2 min · jiezi

宜人贷蜂巢ELK Stack之elasticsearch权限探索

前言上文宜人贷蜂巢API网关技术解密之Netty使用实践提到了,API网关“承外对内”,将外部请求,转发到内部各个抓取服务。在网关中,不仅可以做鉴权、加解密、路由、限流功能;如果想了解各服务接口的调用次数、调用时间、成功次数、失败次数等接口相关的统计,都可以网关中埋点,采集相关信息,通过logstash放入elasticsearch(简称es),在kibana中或通过es的http请求获得各服务接口的统计信息。ELK框架前段时间有一个需求,我们的es需要作为一个服务提供出来。考虑到es内保存着敏感数据,需要对es添加权限管理功能。搜寻es权限管理,大概有三套方案:ELK Stack官方安全插件X-Pack Securites安全插件Search Guard自实现权限管理考虑到X-Pack Security是收费软件,自开发一个权限管理模块成本比较高,最后选用了Search Guard的社区版本,其支持的功能已经满足当前需求。Search Guard安装过程Stop Elasticsearchps -ef | grep elasticsearch | grep -v grep | awk {‘print $2’} | xargs kill -9Install Search Guard/opt/soft/elasticsearch-5.5.1-guard/bin/elasticsearch-plugin install -b com.floragunn:search-guard-5:5.5.1-14如果线上服务器不能访问外网,可以事先下载对应版本的 Search Guard,再以本地模式安装/opt/soft/elasticsearch-5.5.1-guard/bin/elasticsearch-plugin install -b file:///opt/soft/search-guard-5-5.5.1-15.zip产生证书及配置es如果在测试环境安装es,可以使用软件自带的脚本,生成CA及相应证书,并自动配置了essh /opt/soft/elasticsearch-5.5.1-guard/plugins/search-guard-5/tools/install_demo_configuration.sh但以上方式不适用于线上环境,我们的es希望在线上环境能提供权限访问控制,所以采用了search-guard-ssl生成线上证书首先,下载了search-guard-ssl项目git clone https://github.com/floragunncom/search-guard-ssl.git生成证书,可以参考官方文档详细说明建议修改证书信息及密码example-pki-scripts/etc/root-ca.confexample-pki-scripts/etc/signing-ca.conf执行证书生成脚本sh ./example.sh将相应的证书拷贝到es的config文件夹下修改es配置cluster.name: honeycomb-es-guard-5.5.1# node 1 to 5node.name: node-1 path.data: /data01/elasticsearch-guardpath.logs: /opt/logs/elasticsearch-guardnetwork.host: 0.0.0.0http.cors.enabled: truehttp.cors.allow-origin: ““thread_pool.bulk.queue_size: 50searchguard.ssl.transport.keystore_filepath: node-1-keystore.jkssearchguard.ssl.transport.keystore_password: node_essearchguard.ssl.transport.truststore_filepath: truststore.jkssearchguard.ssl.transport.truststore_password: r_ca_honeycombsearchguard.ssl.transport.enforce_hostname_verification: falsesearchguard.ssl.transport.enable_openssl_if_available: truesearchguard.ssl.transport.resolve_hostname: falsesearchguard.ssl.http.enabled: truesearchguard.ssl.http.keystore_filepath: node-1-keystore.jkssearchguard.ssl.http.keystore_password: node_essearchguard.ssl.http.truststore_filepath: truststore.jkssearchguard.ssl.http.truststore_password: r_ca_honeycombsearchguard.authcz.admin_dn: - CN=,OU=client,O=client,L=test, C=de - CN=kirk,OU=client,O=client,L=test,C=DEsearchguard.ssl.http.clientauth_mode: NONERestart Elasticsearch.su elk/opt/soft/elasticsearch-5.5.1-guard/bin/elasticsearch -dInitialise the Search Guard index by running sgadmin <span style=“font-family:monospace;font-size:14px;">/opt/soft/elasticsearch-5.5.1-guard/plugins/search-guard-5/tools/sgadmin.sh -cd /opt/soft/elasticsearch-5.5.1-guard/plugins/search-guard-5/sgconfig/ -cn honeycomb-es-guard-5.5.1 -ks /opt/soft/elasticsearch-5.5.1-guard/config/kirk-keystore.jks -kspass ki_ca_1 -ts /opt/soft/elasticsearch-5.5.1-guard/config/truststore.jks -tspass r_ca_honeycomb –nhnv</span>测试结果curl -k -u admin:admin ‘https://localhost:9200/_searchguard/authinfo?pretty’es装上Search Guard后的ELK框架kibana修改步骤安装插件/opt/soft/kibana-5.5.1-linux-x86_64-guard/bin/kibana-plugin install file:///opt/soft/searchguard-kibana-5.5.1-4.zipkibana配置server.port: 5601server.host: “0.0.0.0"elasticsearch.url: “https://localhost:9200"kibana.index: “.kibana"elasticsearch.username: “kibanaserver"elasticsearch.password: “kibanaserver"elasticsearch.ssl.verificationMode: nonestart kibana/opt/soft/kibana-5.5.1-linux-x86_64-guard/bin/kibana &访问页面logstash修改步骤logstash在按照官方文档配置,且咨询Search Guard官方后,并没有安装成功;现列出操作过程及问题现象,如有哪位读者了解,还望不吝赐教Configure logstash to use HTTPS instead of HTTP.例如,hosts => “https://…“If you want to verify the server’s certificate (optional, but recommended), you need to provide the path to the keystore containing your Root CA as well.logstash不需要验证es的证书,所以设置ssl_certificate_verification => false如果进行证书验证,需配置CA路径及密码Configure the logstash username and password.最终配置output { elasticsearch { hosts => [“https://xx.xx.xx.32:9200”] index => “%{log_project}-%{+YYYY-MM-dd}” ssl => true ssl_certificate_verification => false #truststore => “/opt/soft/elasticsearch-5.5.1-guard/config/truststore.jks” #truststore_password => r_ca_honeycomb user => logstash password => logstash }}start logstash/opt/soft/logstash-2.4.1-guard/bin/logstash -f /opt/soft/logstash-2.4.1-guard/conf/honeycomb-logstash.conf问题1. Search Guard 建议logstash不做证书验证且不需要提供truststore和truststore_password,但按操作后,进程启动成功,但仍有fail提示** WARNING ** Detected UNSAFE options in elasticsearch output configuration!** WARNING ** You have enabled encryption but DISABLED certificate verification.** WARNING ** To make sure your data is secure change :ssl_certificate_verification to true {:level=>:warn}PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target {:class=>“Manticore::ClientProtocolException”, :level=>:error}Pipeline main started2. logstash在启动后,发送数据给es时,始终报错Attempted to send a bulk request to Elasticsearch configured at ‘[“https://xx.xx.xx.32:9200”]’, but an error occurred and it failed! Are you sure you can reach elasticsearch from this machine using the configuration provided? {:error_message=>“PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target”, :error_class=>“Manticore::ClientProtocolException”, :backtrace=>["/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/manticore-0.6.0-java/lib/manticore/response.rb:37:in initialize'", "org/jruby/RubyProc.java:281:in call’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/manticore-0.6.0-java/lib/manticore/response.rb:79:in call'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/manticore-0.6.0-java/lib/manticore/response.rb:256:in call_once’”,"/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/manticore-0.6.0-java/lib/manticore/response.rb:153:in code'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/elasticsearch-transport-1.1.0/lib/elasticsearch/transport/transport/http/manticore.rb:84:in perform_request’”,“org/jruby/RubyProc.java:281:in call'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/elasticsearch-transport-1.1.0/lib/elasticsearch/transport/transport/base.rb:257:in perform_request’”,"/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/elasticsearch-transport-1.1.0/lib/elasticsearch/transport/transport/http/manticore.rb:67:in perform_request'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/elasticsearch-transport-1.1.0/lib/elasticsearch/transport/client.rb:128:in perform_request’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/elasticsearch-api-1.1.0/lib/elasticsearch/api/actions/bulk.rb:93:in bulk'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-output-elasticsearch-2.7.1-java/lib/logstash/outputs/elasticsearch/http_client.rb:53:in non_threadsafe_bulk’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-output-elasticsearch-2.7.1-java/lib/logstash/outputs/elasticsearch/http_client.rb:38:in bulk'", "org/jruby/ext/thread/Mutex.java:149:in synchronize’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-output-elasticsearch-2.7.1-java/lib/logstash/outputs/elasticsearch/http_client.rb:38:in bulk'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-output-elasticsearch-2.7.1-java/lib/logstash/outputs/elasticsearch/common.rb:172:in safe_bulk’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-output-elasticsearch-2.7.1-java/lib/logstash/outputs/elasticsearch/common.rb:101:in submit'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-output-elasticsearch-2.7.1-java/lib/logstash/outputs/elasticsearch/common.rb:86:in retrying_submit’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-output-elasticsearch-2.7.1-java/lib/logstash/outputs/elasticsearch/common.rb:29:in multi_receive'", "org/jruby/RubyArray.java:1653:in each_slice’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-output-elasticsearch-2.7.1-java/lib/logstash/outputs/elasticsearch/common.rb:28:in multi_receive'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-core-2.4.1-java/lib/logstash/output_delegator.rb:130:in worker_multi_receive’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-core-2.4.1-java/lib/logstash/output_delegator.rb:114:in multi_receive'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-core-2.4.1-java/lib/logstash/pipeline.rb:301:in output_batch’”, “org/jruby/RubyHash.java:1342:in each'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-core-2.4.1-java/lib/logstash/pipeline.rb:301:in output_batch’”, “/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-core-2.4.1-java/lib/logstash/pipeline.rb:232:in worker_loop'", "/opt/soft/logstash-2.4.1-guard/vendor/bundle/jruby/1.9/gems/logstash-core-2.4.1-java/lib/logstash/pipeline.rb:201:in start_workers’”], :level=>:error}看日志似乎是目的不可达,但在logstash机器上,通过命令测试,是可以访问的curl -k -u logstash:logstash ‘https://xx.xx.xx.32:9200/_searchguard/authinfo?pretty’另外es有打印错误日志[2017-08-24T10:39:20,834][ERROR][c.f.s.h.SearchGuardHttpServerTransport] [node-2] SSL Problem Received fatal alert: certificate_unknownjavax.net.ssl.SSLException: Received fatal alert: certificate_unknown at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) ~[?:?] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666) ~[?:?] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634) ~[?:?] at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800) ~[?:?] at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1083) ~[?:?] at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:907) ~[?:?] at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781) ~[?:?] at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624) ~[?:1.8.0_131] at io.netty.handler.ssl.SslHandler$SslEngineType$3.unwrap(SslHandler.java:254) ~[netty-handler-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1156) ~[netty-handler-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1078) ~[netty-handler-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489) ~[netty-codec-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) ~[netty-codec-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) ~[netty-codec-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:544) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:498) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458) [netty-transport-4.1.11.Final.jar:4.1.11.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) [netty-common-4.1.11.Final.jar:4.1.11.Final] at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131][2017-08-24T10:39:21,663][ERROR][c.f.s.h.SearchGuardHttpServerTransport] [node-2] SSL Problem Received fatal alert: certificate_unknownjavax.net.ssl.SSLException: Received fatal alert: certificate_unknown at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) ~[?:?] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666) ~[?:?] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634) ~[?:?] at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800) ~[?:?] at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1083) ~[?:?] at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:907) ~[?:?] at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781) ~[?:?] at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624) ~[?:1.8.0_131] at io.netty.handler.ssl.SslHandler$SslEngineType$3.unwrap(SslHandler.java:254) ~[netty-handler-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1156) ~[netty-handler-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1078) ~[netty-handler-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489) ~[netty-codec-4.1.11.Final.jar:4.1.11.Final] at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) ~[netty-codec-4.1.11.Final.jar:4.1.11.Final]3、上文es的错误日志,显示es不知道证书(应该是客户端证书),但是已经配置了不做客户端认证,这又是为什么?es部分配置searchguard.ssl.http.clientauth_mode: NONE总结虽然logstash与es通信暂时没有成功,但是在尝试开通es权限的过程中,也积累了些经验和成果使用类似文中curl的方式(http请求),直接使用es服务添加了Search Guard的es如何对外提供域名访问,实现后端多点服务/路由nginx可以处理来自外部的https请求,但目前不支持https代理,即nginx不能访问后端的https服务。如果仍然使用Search Guard,可以考虑使用四层负载均衡器lvs或者硬件负载均衡器,将请求透传给后端服务器;另外知乎文章上有推荐使用Squid。参考https://floragunn.com/https://github.com/floragunnc…https://github.com/floragunnc...https://github.com/floragunnc...https://github.com/floragunnc...https://github.com/floragunnc...https://github.com/floragunnc...https://forum.nginx.org/read....https://www.zhihu.com/questio…作者:蜂巢团队宜信技术学院 ...

March 6, 2019 · 3 min · jiezi

JavaScript的调用栈、回调队列和事件循环

译者按这篇文章可以看做是对Philip Roberts 2014年在JSConf演讲的《What the heck is the event loop anyway?》的一个总结。建议先看Philip Roberts的这个演讲然后再阅读本篇文章。这哥们儿的演讲语言幽默风趣,内容通俗易懂,非常值得一看。在这个视频中,Philip Roberts将JavaScript的调用栈、回调队列和事件循环的内容讲的很清晰。所以你可以随意的跳过这篇文章,花上一个半小时去看视频。当然如果你愿意读一下我的这篇文章那也不是不可以。什么是JavaScript什么是JavaScript呢?列举一些关键词就是:他是单线程的、非阻塞的、异步的并发语言他有一个调用栈,一个事件循环,一个回调队列,还有一些api和别的东西如果你像我一样(或者像Philip Roberts)对此懵逼的话,这些话本身并没不意味着什么。那我们就来剖析一下。JavaScript运行时JavaScript运行时(像V8引擎)拥有一个堆(内存分配用的)和栈(执行上下文)。但是他没有setTimeout、DOM等。这些是浏览器提供的Web APIs。我们了解的JavaScript浏览器中的JavaScript拥有:一个像V8引擎一样的运行时(提供堆栈)浏览器提供的Web APIs,例如:DOM、AJAX和setTimeout一个为各种事件回调准备的回调队列,例如:onClick、onLoad、onDone一个事件循环什么是调用栈JavaScript是单线程的,意味着他有一个单独的调用栈,意味着他一次能做一件事。调用栈基本上就是一个记录程序执行位置的数据结构。如果程序进入了一个函数,那就往这个栈里面塞些东西。如果程序从一个函数中return了,那就从栈顶弹出一些东西。当我们的程序报错的时候,我们会在控制台看到调用栈信息。报错的时候我们可以看到栈的状态(被调用的那个函数的)。阻塞这涉及到一个重要的问题:程序运行的很慢的时候发生了什么?换句话说,就是程序阻塞了。阻塞并没有严格的定义。实际上就是程序执行慢。执行console.log不慢,但是一个从1到1,000,000,000的while循环,图像处理或者网络请求这些操作的执行就比较费时了。这些执行慢的东西堆在一起就发生了阻塞。因为JavaScript是单线程的,我们发起一个网络请求就不得不一直等到他结束。这在浏览器中就是个问题–当我们等这个请求的时候,浏览器就发生了阻塞(我们不能做点击、提交表单等操作)。解决这个问题的方法就是使用异步回调。并发,看到这个词的时候我们会发现上面有一个地方说的不对JavaScript一次只能做一件事情的说法是不对的。正确的说法应该是:JavaScript的运行时一次只能做一件事。他不能一边发ajax请求一边运行别的代码,也不能在执行别的代码时候运行一个定时器。但是我们可以并发的做这些事。因为浏览器不仅仅是一个运行时(还记得上面那个渣渣画质的图吗?)。调用栈可以往Web APIs里面放东西,Web APIs可以在事件结束的时候把回调函数放进回调队列,然后是事件循环。最终我们进入事件循环,这是这个过程中最简单的部分,他有一个非常简单的工作:看看调用栈,瞅瞅回调队列,如果调用栈空闲了,就把回调队列中的第一个函数取出来丢进调用栈让他执行(这就回到了JavaScript的地盘,回到了V8的内部)。整个串起来Philip搞了一个的碉堡的工具来可视化这个过程,这玩意儿叫Loupe。这是一个能够把JavaScript运行时可视化的工具。我们用它来看一个简单的例子:在一个异步的setTimeout回调中用console.log在控制台打些log出来。整个过程到底都发生了什么呢?我们来看一下:执行进入console.log(‘Hi’);函数,因此这个函数被丢进了调用栈里。console.log(‘Hi’);函数return了,因此他就被弹出了栈顶。执行进入setTimeout函数,因此这个函数被丢进了调用栈里。setTimeout是Web APIs的一部分,因此Web APIs处理了他,并且等了2秒继续执行脚本,进入console.log(‘EvenyBody’)函数,把他也丢进调用栈。console.log(‘EvenyBody’)函数return了,所以把他从栈顶弹出去2秒的定时已经完成了,所以就把对应的回调函数放到回调队列里。事件循环检查调用栈是否为空,如果非空的话,他就等着。因为调用栈现在是空的,所以把回调队列中的回调函数丢进调用栈。console.log(‘There’)函数返回了,因此把他从栈顶弹出去(译者按:原文为console.log(‘Everybody’),应为书写错误)。有趣的一点是:setTimeout(function(…), 0)的情况。setTimeout为0的时候这个过程看起来可能不明显,除非考虑到调用栈的执行环境和事件循环的情况。基本上都会推迟到调用栈为空才执行。考虑UI渲染的性能的情况为了回到了我们日常处理的UI层,我们需要考虑渲染问题。浏览器受到我们在JavaScript中所做操作的影响,他可能每隔16.6ms重绘一次屏幕(60帧/秒)。但是调用栈还有代码在执行的话,他实际上是没法做重绘的。就像Philip说的一样:当大家说不要"阻塞事件循环"的时候,他们实际上是说:不要把耗费时间长的代码放进调用栈,因为你要这么搞的话,浏览器就不能做他该做的事了,比如说给你搞一个漂亮流畅的UI。Philip Roberts “What the Heck Is the Event Loop Anyway”举个例子,滚动的处理函数触发多了会让UI变得卡顿。顺便说一句,这是我听过的对防抖最清楚的解释了,这就是你要做到的“不要阻塞事件循环”(那就是我们只在滚动处理函数被触发x次后才执行那些耗时的操作)。结语总之,这就是《What the heck is the event loop anyway?》的答案。Philip的演讲很好的帮我理解了什么是JavaScript,什么不是,哪个部分是运行时,哪个部分是浏览器的和我们该怎样有效的使用事件循环。好好看看这个视频吧。

February 18, 2019 · 1 min · jiezi

leetcode394. Decode String

题目要求Given an encoded string, return it’s decoded string.The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times. Note that k is guaranteed to be a positive integer.You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc.Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there won’t be input like 3a or 2[4].Examples:s = “3[a]2[bc]”, return “aaabcbc”.s = “3[a2[c]]”, return “accaccacc”.s = “2[abc]3[cd]ef”, return “abcabccdcdcdef”.将一个字符串解码,要求按照次数展开原字符串中的中括号。如3[a]2[bc]对应的字符串就是aaabcbc,即a展开3次,bc展开2次。注意,源字符串中的括号是允许嵌套的,且展开的字符中不会包含任何数字。思路一:递归其实递归的思路是很明显的,一旦我们遇到一个左括号,我们就可以找到其对应的右括号,然后对括号中的内容递归的展开,再将返回结果给上层,根据上次的次数再次展开。如3[a2[c]]=>3[acc]=>accaccacc。递归这里需要注意的是如何找到当前括号对应的右括号。这里可以采用一个小技巧,即从当前括号位置开始,每遇到一个左括号计数就+1,遇到一个右括号计数就-1,当计数器第一次被减为0时,则该位置上的右括号就是我们所要找的对应的右括号。代码如下: public String decodeString2(String s) { if (s.length() == 0) return “”; StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c >= ‘0’ && c <= ‘9’) { // 解析次数 int digitStart = i++; while (s.charAt(i) >= ‘0’ && s.charAt(i) <= ‘9’) i++; int num = Integer.parseInt(s.substring(digitStart, i)); // 找到对应的右括号 int strStart = i+1; // number must be followed by ‘[’ int count = 1; i++; while (count != 0) { if (s.charAt(i) == ‘[’) count++; else if (s.charAt(i) == ‘]’) count–; i++; } i–; // 取子字符串 String subStr = s.substring(strStart, i); // 将子字符串解码 String decodeStr = decodeString(subStr); // 将解码的结果拼接到当前的字符串后面 for (int j = 0; j < num; j++) { sb.append(decodeStr); } } else { // 添加首元素 sb.append(c); } } return sb.toString(); }思路二:栈我们知道,有一些递归的思路是可以转化为栈的,这里同样如此。利用栈我们可以存储外围层已持有的字符串以及应当展开的次数。用栈的思路来写要求思路更加严谨,以免出现逻辑错误。首先,我们会用两个指针lft,rgt分别来记录数字的起始位置和结束位置。同时,rgt还作为我们遍历整个字符串的指针。rgt的情形有如下几种可能:rgt指向[rgt指向]rgt指向数字rgt指向字母下面我们来逐个分析各种场景:1. rgt指向[此时左括号的左侧只会有一种情形,它的左边一定是数字。因此当我们遇到左括号时,我们应当记录左括号左边的数字,并将lft指针移动到左括号下一个位置。这里需要额外注意的是,如果当前该括号外围存在父元素,则我们应当将父元素的计数和已有字符串压入栈中。可以将这个操作理解为上下文切换。2. rgt指向]右括号意味着当前的字符展开序列遍历完毕,因此我们需要做以下几件事情:将lft和rgt之间的内容append到当前上下文的字符串中根据展开次数展开当前上下文的字符串如果存在父元素,则从栈中弹出父元素,恢复父级上下文将当前上文得到的结果append到父元素的字符串中3. rgt指向字母我们需要将rgt指向的字母添加到当前的上下文字符串中去。不要忘记将左指针移动到当前位置后面4. rgt指向数字数字将会在遇见[时提取出来,因此我们无需进行任何处理一个具体的例子假如现在输入的字符串为3[a2[c]],我们有字符串栈s,计数栈c,指针lft,rgt,并用临时变量tmp,number分别记录当前上下文中计数和字符串。运行情况如下:lft=0 rgt=0 : 不执行任何操作lft=0 rgt=1 : 解析当前上下文应当展开的次数 number=3, lft=2lft=2 rgt=2 : 将当前的字符添加到当前的上下文中去,tmp=“a” lft=3lft=3 rgt=3 : 不做任何处理lft=3 rgt=4 : 将父级上下文压入栈中,并解析当前上下文的展开次数 s:[“a”] c:[3] lft=5 tmp="" number=2lft=5 rgt=5 : 将当前的字符添加到当前的上下文中去,tmp=“c” lft=6lft=6 rgt=6 : 展开当前字符串,并恢复父级上下文, tmp=“a”+“cc”, number=3 s:[] c:[] lft=7lft=7 rgt=7 : 展开当前字符串,= 此时没有父级上下文,因此无需恢复。tmp=“accaccacc” number=0代码如下: public String decodeString(String s) { Stack<Integer> count = new Stack<>(); Stack<StringBuilder> letters = new Stack<>(); int lft = 0, rgt = -1; int number = 0; StringBuilder result = null; while(++rgt < s.length()) { char c = s.charAt(rgt); if(c == ‘[’) { if(result != null) { count.push(number); letters.push(result); } result = new StringBuilder(); number = Integer.valueOf(s.substring(lft, rgt)); lft = rgt+1; }else if(c == ‘]’) { result.append(s.substring(lft, rgt)); StringBuilder tmp = new StringBuilder(result); for(int i = 0 ; i<number-1 ; i++) { result.append(tmp); } if(!letters.isEmpty()) { StringBuilder pop = letters.pop(); pop.append(result); result = pop; number = count.pop(); } lft = rgt+1; }else if(Character.isAlphabetic(c)) { if(result==null) { result = new StringBuilder(); } result.append(c); lft = rgt+1; } } if(result == null) { result = new StringBuilder(); } result.append(s.substring(lft, rgt)); return result.toString(); }想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注我的微信公众号!将会不定期的发放福利哦~ ...

February 13, 2019 · 2 min · jiezi

[LeetCode] 71. Simplify Path

ProblemGiven an absolute path for a file (Unix-style), simplify it. For example,path = “/home/”, => “/home"path = “/a/./b/../../c/”, => “/c"path = “/a/../../b/../c//.//”, => “/c” //here: b is cancelled out, a is cancelled outpath = “/a//b////c/d//././/..”, => “/a/b/c” //here d is cancelled outIn a UNIX-style file system, a period (’.’) refers to the current directory, so it can be ignored in a simplified path. Additionally, a double period (”..”) moves up a directory, so it cancels out whatever the last directory was. For more information, look here: https://en.wikipedia.org/wiki...Corner Cases:Did you consider the case where path = “/../"?In this case, you should return “/".Another corner case is the path might contain multiple slashes ‘/’ together, such as “/home//foo/".In this case, you should ignore redundant slashes and return “/home/foo”.Solutionclass Solution { public String simplifyPath(String path) { Deque<String> stack = new ArrayDeque<>(); Set<String> ignore = new HashSet<>(Arrays.asList(””, “.”, “..”)); for (String dir: path.split(”/")) { if (!stack.isEmpty() && dir.equals("..")) stack.pop(); if (!ignore.contains(dir)) stack.push(dir); } String res = “”; while (!stack.isEmpty()) { res = “/"+stack.pop()+res; } if (res.equals(”")) return “/”; return res; }} ...

December 17, 2018 · 1 min · jiezi