erlang 那种 umount 旧的 保持的老会话在旧实现里,同时 mount 新的处理新的会话才能算热部署吧?
php 生产环境依赖 php 的那种"热部署"简直在拷问自己的 RP,不仅修改多个物理文件之间不能保障原子性更新,同时也无法保障 opcode cache 会同步更新 (看重性能的生产环境下启用各种 opcode cache 都是鼓励 never 刷新,或者根据 ttl/访问计数刷新), 依赖语言特性的那种"热部署"每次修改前都得去烧柱香。
改了语言不考虑改架构是耍流氓啊,也无非是把语言层先跑死换成后端数据库一类的服务先跑死。
缩写特定环境下能一眼看懂就好了,以前 mozilla 负责 firefoxOS 相关的宫力博士现在自己搞的 firefoxOS 分支可实打实的叫 H5OS 啊,要不去吊打他一下看看?
用 SSL 就不说了。
建议隐藏的 form 自动 post 一下,或者通过加自定义的 http token 字段。业务上要是不能保障不会产生由用户引用的来自外站的资源,如图片视频甚至外链,在 URL 里直接带 token 或者 session id 都会有安全问题。比如用户 img 自己网站一张图,就可以去日志里数 referer 里的 token 了; 再比如用户 A 发了个自己网站的外链,B 点了,A 又可以去日志里看 referer 里的 token 了
`seq 1 15`.split.map(&:to_i).each {|number| puts "The number inside the loop is #{number}" }
作弊的方法算不
第一,明确观点请用事实和代码说话,用感觉说话会带来思维盲点的。
我不再重复我在15#说的两个等同了,事实上拿加密 cookie 作为默认 session 选项也不是 rails 一家异想天开弄出来的,比如 php 的 codeigniter,java/scala的play, python 的 flask, go 的 gorilla 默认的 session 方案都是加密 cookie.
淘宝分享用加密 cookie 作为 session 方案(请搜"淘宝 session 框架")已经实施了四五年了,请问这几年出现的几次安全问题哪次和这方面有关?
第二,谁说服务端 session 就不需要验证 sign 了?
比如,你用手机和电脑同时登录同一个账户,分别是两个 session, 其中一个改了密码就必须让另一个失效对吧?
你的方案是另外通过 sql db 或者 redis 的 set 维护 id 和 session 的对应表,实现连锁销毁。
但是正常的通用 session 方案里也是通过 current_user 的 password 和 token 做一次 hash, 和 session 里的 sign 验证一下来判断是否有效。
一方面后者不用特意额外搞个 sql db 或者 redis set 维护变更,维护成本小,二来也不需要重度依赖对应表,scale 成本也低。
第一点不是很一致么 (1) 无论是 cookie store 还是传统的 cookie(session id)<->server session, 就算再通过 secret key 加密,劫持到 cookie 时已经算完了,这方面除了 ssl 是没办法保障的。 (2) 不考虑劫持现象,传统的 cookie(session id)<->server session 无法伪造,但是 cookie store 的 session 在服务端 secret key 不泄漏的情况下,同样无法伪造。 所以安全系数上是完全一致的。
第二点针对登出失效,这是设计问题,不是安全问题 cookie store 的 session 检测用户时同样需要存在一个 sign 做验证 (比如根据用户的密码和一个 token 字段),用户登出完全可以重设生成这个 sign 所需要的 token, 也就是说当用户登出或者修改密码时,原先保存在 session 里的 sign 已经失效了,当然也就未登录了。
就这三个来讲,Ruby(MRI) 和 (C)Python、PHP 性能是半斤八两,属于同一梯队的。
踩坑,不掉坑里不长记性,掉坑多了痛怕了经验值刷多了就知道怎么对付了。
#8 楼 @betterthornbird 字符窜类型用 blob/tinyblob 这类有副作用,比如 string 想返回 char_length, varchar/char都是根据编码返回字数(就是ruby里的.size), 但是 blob/tinyblob 返回的是字节长度 (就是 ruby 里的.bytesize)
crul -> curl
想要固定字段大小写敏感的话只要把该字段的 collation 从 utf8_general_ci 改成 utf8_bin.
没搞电商经验或者金融业务出身的 DBA,纯后端上手在线交易的 db 设计,不是死在 decimal 和浮点数的乱用,就是错用少用多用事务和各种锁,还得避免滥用索引这种职业病。
后端要是就一个人,测试覆盖率再高,总有没考虑齐全的地方,和钱打交道的业务总得谨慎点吧。
UI 和前端就算后端能兼,一会儿切图,一会儿刷 js 和 css 改善可用性,一会儿测各种浏览器和设备的兼容性,一会儿再切回去写后端,效率直接被拖爆。
后端兼网管可以,但是一旦线上出问题,自身程序和各种中间件先扫哪头?还不包括要去调 syslog 看看是不是撞上 kernel 或者硬件出错这种小概率事件。
要说全栈,没流行框架前的 php 程序员个个多面手,那么多电商程序光注意数据库的事务和锁的就死剩一个 magento,但是 magento team 的人少说也得 2 位数吧。
当然,肯定有人能点亮上面大部分甚至全部的技能树,不过一难找,二难挖,三不一定比多招几个各方面熟手便宜。
我估了下最少也得
搞过电商或者金融业务的资深 DBA*1 能互相 review 代码的后端熟手*2 UI*1, 前端*1 熟悉虚拟机、haproxy、zookeeper、lvs 等的资深网管*1 搜索、推荐这些预算足也可以找专人做,不足先让后端用 solr、mahout 这些顶着. 移动 app 有预算再找专人,没预算先拿 webapp 凑和着。
result = (array_or_nil || []).first
result = array_or_nil.to_a.first
试了下,确实,不过要近 3000 条路由 martini 才能反超 mux, 比较贴近实际的 (500 条以内), mux 还是能压 martini 近一倍。而且 mux 路由匹配应该是能优化的,martini 为了仿动态性依靠注入机制导致运行时大量反射操作加速应该很难吧。
package main
import (
"encoding/json"
"fmt"
"github.com/go-martini/martini"
"io"
"net/http"
)
const (
N = 1000
)
func json2writer(w io.Writer, result interface{}) error {
if resp, ok := w.(http.ResponseWriter); ok {
resp.Header().Set("Content-Type", "application/json")
}
encoder := json.NewEncoder(w)
if err := encoder.Encode(result); err != nil {
return err
}
return nil
}
func main() {
m := martini.New()
r := martini.NewRouter()
for i := 1; i < N; i++ {
r.Get(fmt.Sprintf(`/%d/(?P<id>[1-9]\d*)`, i), func(i int) func(params martini.Params, w http.ResponseWriter) {
return func(params martini.Params, w http.ResponseWriter) {
json2writer(w, map[string]interface{}{
"result": true,
"i": i,
"params": params,
})
}
}(i))
}
m.Action(r.Handle)
http.Handle("/", m)
http.ListenAndServe(":5000", nil)
}
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"io"
"net/http"
)
const (
N = 1000
)
func json2writer(w io.Writer, result interface{}) error {
if resp, ok := w.(http.ResponseWriter); ok {
resp.Header().Set("Content-Type", "application/json")
}
encoder := json.NewEncoder(w)
if err := encoder.Encode(result); err != nil {
return err
}
return nil
}
func main() {
m := mux.NewRouter()
for i := 1; i < N; i++ {
m.HandleFunc(fmt.Sprintf(`/%d/{id:[1-9]\d*}`, i), func(i int) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
json2writer(w, map[string]interface{}{
"result": true,
"i": i,
"params": mux.Vars(r),
})
}
}(i))
}
http.Handle("/", m)
http.ListenAndServe(":5000", nil)
}
ab -n 10000 -c 100 http://localhost:5000/(N/2)/10000
N = 500
martini => Requests per second: 5286.49 [#/sec] (mean)
mux => Requests per second: 9058.32 [#/sec] (mean)
N = 1000
martini => Requests per second: 3949.45 [#/sec] (mean)
mux => Requests per second: 6380.75 [#/sec] (mean)
N = 1500
martini => Requests per second: 3288.06 [#/sec] (mean)
mux => Requests per second: 4732.49 [#/sec] (mean)
N = 2000
martini => Requests per second: 2673.03 [#/sec] (mean)
mux => Requests per second: 3229.62 [#/sec] (mean)
N = 2500
martini => Requests per second: 2224.42 [#/sec] (mean)
mux => Requests per second: 2472.72 [#/sec] (mean)
N = 3000
martini => Requests per second: 1807.92 [#/sec] (mean)
mux => Requests per second: 1750.74 [#/sec] (mean)
你那偏旧,martini 这几个月 router 之类的改动蛮大的,而且 Go 1.3 的性能拉升对除了 martini 这种黑魔法玩嗨的框架都提升极大。
我这两个例子,为了避免干扰,没用 martini-contrib 的 render 输出 json, 也没用 Classic 一些 serve 静态文件和日志打印的 middleware
运行环境是 1.3 开发版,做的是
ab -n 100000 -c 1000 http://host/ 和 ab -n 100000 -c 1000 http://host/helloworld.json
martini 当前版本是
/ => Requests per second: 9463.05 [#/sec] (mean)
/helloworld.json => Requests per second: 7103.08 [#/sec] (mean)
mux 当前版本是
/ => Requests per second: 17820.39 [#/sec]
/helloworld.json => helloworld.json Requests per second: 17788.92 [#/sec]
测试代码是
package main
import (
"encoding/json"
"fmt"
"github.com/go-martini/martini"
"io"
"net/http"
)
func json2writer(w io.Writer, result interface{}) error {
if resp, ok := w.(http.ResponseWriter); ok {
resp.Header().Set("Content-Type", "application/json")
}
encoder := json.NewEncoder(w)
if err := encoder.Encode(result); err != nil {
return err
}
return nil
}
func main() {
m := martini.New()
r := martini.NewRouter()
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "helloworld")
})
r.Get("/helloworld.json", func(w http.ResponseWriter, r *http.Request) {
json2writer(w, map[string]interface{}{
"message": "helloworld",
"okay": true,
})
})
m.Action(r.Handle)
http.Handle("/", m)
http.ListenAndServe(":5000", nil)
}
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"io"
"net/http"
)
func json2writer(w io.Writer, result interface{}) error {
if resp, ok := w.(http.ResponseWriter); ok {
resp.Header().Set("Content-Type", "application/json")
}
encoder := json.NewEncoder(w)
if err := encoder.Encode(result); err != nil {
return err
}
return nil
}
func main() {
m := mux.NewRouter()
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "helloworld")
})
m.HandleFunc("/helloworld.json", func(w http.ResponseWriter, r *http.Request) {
json2writer(w, map[string]interface{}{
"message": "helloworld",
"okay": true,
})
})
http.Handle("/", m)
http.ListenAndServe(":5000", nil)
}
老板...最起码也得投资人...
国企要的发票,单离岸公司开不了。
15 万的劳务个税绝对不止 20 个点; 不过公司 6 点也不止,6 点最多营业税,算上增值税、所得税,还有各种诸如城建税、教育税之类杂税,摊上个人所得税、强制社保,你 15 万甚至拿不到 60%,这还不包括你办公司要的一些诸如场地租赁、账目外包的开销。
单你短期做一笔,既然允许签劳务,注册公司我觉得不划算。