0%

1
2
3
4
5
6
7
8
# 开启事务,设定事务的开启位置,此指令执行后,后续的所有指令均加入到事务中
multi

# 执行提交事务,加入事务的命令暂时到任务队列中,并没有立即执行,只有执行exec命令才开始执行
exec

# 取消事务,终止当前事务定义,发生在multi之后,exec之前
discard

事务的工作流程

事务的注意事项

  • 语法错误
    指命令书写格式有误
  • 处理结果
    如果定义的事务中所包含的命令存在语法错误,整体事务中所有命令均不会被执行。包括那些语法正确的命令

  • 运行错误
    指命令格式正确,但是无法正常的执行。例如对list进行incr操作
  • 处理结果
    能够正确运行的命令会执行,运行错误的命令不会执行
    注意:已经执行完毕的命令对应的数据不会自动回滚,需要程序员自己在代码中实现回滚。

手动进行事务回滚(基本没法用)

  • 记录操作过程中被影响的数据之前的状态
    单数据:string
    多数据:hash,list,set,zset
  • 设置指令恢复所有的被修改的项
    单数据:直接set(注意周边属性,例如时效)
    多数据:修改对应值或整体克隆复制

1
2
3
4
5
# 对key添加监视锁,在执行exec前如果key发生了变化,终止事务执行
watch key1 [key2…]

# 取消对所有key的监视
unwatch

分布式锁

1
2
3
4
5
6
7
8
# 加锁
setnx lock-key value

# 设置超时时间
expire lock-key second

# 删除锁
dek lock-key
  • 利用setnx命令的返回值特征,有值则返回设置失败,无值则返回设置成功
  • 对于返回设置成功的,拥有控制权,进行下一步的具体业务操作
  • 对于返回设置失败的,不具有控制权,排队或等待
    操作完毕通过del操作释放锁

缓存预热

在高请求之前,做好一系列措施,保证大量用户数量点击造成灾难。

  1. 请求数量较高
  2. 主从之间数据吞吐量较大,数据同步操作频度较高

缓存预热解决方案

前置准备工作:

  1. 日常例行统计数据访问记录,统计访问频度较高的热点数据
  2. 利用LRU数据删除策略,构建数据留存队列
    例如:storm与kafka配合

准备工作:

  1. 将统计结果中的数据分类,根据级别,redis优先加载级别较高的热点数据
  2. 利用分布式多服务器同时进行数据读取,提速数据加载过程

实施:

  1. 使用脚本程序固定出大数据预热过程
  2. 如果条件允许,使用CDN(内容分发网络),效果会更好

缓存预热总结:
缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

缓存雪崩

  1. 系统平稳运行过程中,忽然数据库连接量激增
  2. 应用服务器无法及时请求
  3. 大量408,500错误页面出现
  4. 客户反复刷新页面获取数据
  5. 数据库崩溃
  6. 应用服务器崩溃
  7. 重启应用服务器无效
  8. Redis服务器崩溃
  9. Redis集群崩溃
  10. 重启数据之后再次被瞬间流量放倒

问题排查

简介:缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉

  1. 在一个较短的时间内,缓存中较多的key集中过期
  2. 此周期内请求访问过期的数据,redis未命中,redis向数据库获取数据
  3. 数据库同时接受到大量的请求无法即时处理
  4. Redis大量请求被积压,开始出现超时现象
  5. 数据库流量激增,数据库崩溃
  6. 重启后任然面对缓存中无数据可用
  7. Redis服务器资源被严重占用,Redis服务器崩溃
  8. Redis集群呈现崩塌,集群瓦解
  9. 应用服务器无法即时得到数据响应请求,来自客户端的请求数量越来越多,应用服务器崩溃
  10. 应用服务器,redis,数据库全部重启,效果不理想

问题分析

  • 短时间范围内
  • 大量key集中过期

解决方案(道)

  1. 更多的页面静态化处理
  2. 构建多级缓存架构
    Nginx缓存+redis缓存+ehcache缓存
  3. 检测Mysql严重耗时业务进行优化
    对数据库的瓶颈排查:例如超时查询、耗时较高事务等
  4. 灾难预警机制
    监控redis服务器性能指标
    1、CPU占用、CPU使用率
    2、内存容量
    3、查询平均响应时间
    4、线程数
  5. 限流、降级
    短时间范围内习生一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐渐放开访问

解决方案(术)

  1. LRU与LFU切换
  2. 数据有效期策略调整
    根据业务数据有效期进行分类错峰,A类90分钟,B类80分钟,C类70分钟
    过期时间使用固定形式+随机值的形式,稀释集中到期的key的数量
  3. 超热数据使用永久key
  4. 定期维护(自动+人工)
    对即将过期数据做访问量分析,确认是否演示,配合访问量统计,做热点数据的延时
  5. 加锁 慎用!!!!!!!

总结
缓存雪崩式瞬间过期数量太大,导致对数据库服务器造成压力。如果能有效避免过期时间集中,可以有效解决雪崩现象的出现(约40%)。配合其他策略一起使用,并监控服务器的运行数据,根据运行巨鹿做快速调整

缓存击穿

数据库服务器崩溃(2)

  1. 系统平稳运行过程中
  2. 数据库连接量瞬间激增
  3. Redis服务器无大量key过期
  4. Redis内存平稳,无波动
  5. Redis服务器CPU正常
  6. 数据库崩溃

问题排查

  1. Redis中某个key过期,该key访问量巨大
  2. 多个数据请求从服务器直接压到Redis后,均为命中
  3. Redis在短时间内发起了大量对数据库中同一个数据的访问

问题分析

  • 单个key高热数据
  • key过期

解决方案(术)

  1. 预先设定
    以电商为例,每个商家根据店铺等级,指定若干款主打商品,在购物节期间,加大此类信息key的过期时常
    注意:购物节不仅仅指当天,以及后续若干天,访问峰值呈现逐渐降低趋势
  2. 现场调整
    监控访问量,对自然流量激增的数据延长过期时间或设置为永久性key
  3. 后台刷新数据
    启动定时任务,高峰期来临之前,刷新数据有效期,保存不丢失
  4. 二级缓存
    设置不同的失效时间,保障不会被同时淘汰就行
  5. 加锁
    分布式锁,防止被击穿,但是要注意也是性能瓶颈,慎重!!!!!!!!

总结:
缓存击穿就是单个高热数据过期的瞬间,数据访问较大,未命中redis后,发起了大量对同一数据的数据库访问,导致对数据库服务器造成压力。应对策略应该在业务数据分析与预防方面进行,配合运行监控测试与即时调整策略,毕竟单个key的过期监控难度较高,配合雪崩处理策略即可

缓存穿透

数据库服务器崩溃(3)

简介:一般是黑客故意去请求缓存中不存在的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

  1. 系统平稳运行过程中
  2. 应用服务器流量随时间增量较大
  3. Redis服务器命中率随时间逐步降低
  4. Redis内存平稳,内存无压力
  5. Redis服务器CPU占用激增
  6. 数据库服务器压力激增
  7. 数据库崩溃

问题排查

  1. redis中大面积出现未命中
  2. 出现非正常URL访问

问题分析

  • 获取的数据在数据库中也不存在,数据库查询未得到对应数据
  • Redis获取到null数据未进行持久化,直接返回
  • 下次此类数据到达重复上述过程
  • 出现黑客攻击服务器

解决方法(术)

  1. 缓存null
    对查询结果为null的数据进行缓存(长期使用,定期清理),设定短时限,例如30-60秒,最高五分钟
  2. 白名单策略
    提前预热各种分类数据id对应的bitmaps,id作为bitmaps的offset,相当于设置了数据白名单。当加载正常数据后放型,加载异常数据时直接拦截(效率偏低)
    使用布隆过滤器(有关布隆过滤器的命中问题对当前状态可以忽略)
  3. 实时监控
    试试监控redis命中率(业务正常范围时,通常回有一个波动值)与null数据的占比
    非活动时间波动:通常检测3-5倍,超过5倍纳入重点排查对象
    活动时间波动:通常检测10-50倍,超过50倍纳入重点排查对象
    根据背书不同,启动不同的排查流程。然后使用黑名单进行防控(运营)
  4. key加密
    问题出现后,临时启动防灾业务key,对key进行业务层传输加密服务,设定校验程序,过来的key校验
    例如每天随机分配60个加密串,挑选2-3个,混淆到页面数据id中,发现访问key不满足规则,驳回数据访问

总结
缓存穿透是访问了不存在的数据,跳过了合法数据的redis数据缓存阶段,每次访问数据库,导致对数据库服务器造成压力。通常此类数据的出现量是一个较低的值,当出现此类情况以毒攻毒,并即时报警。应对策略应该在临时预案防范方面多做文章
无论是黑名单还是白名单,都是对整体系统的压力,警报解除后尽快移除

数据存储设计

Key -> CRC16(Key) 相当于HashCode值—>%16384

  • 将所有的存储空间计划切割成16384份,每台主机保存一部分,每份代表的使一个存储空间,不是一个key的保存空间
  • 将key按照计算出的结果放到对应的存储空间

当有新的机器加入集群的时候,就会每台机器转移一些数据空间

集群内部通讯设计

数据存储设计

Key -> CRC16(Key) 相当于HashCode值—>%16384

  • 将所有的存储空间计划切割成16384份,每台主机保存一部分,每份代表的使一个存储空间,不是一个key的保存空间
  • 将key按照计算出的结果放到对应的存储空间

当有新的机器加入集群的时候,就会每台机器转移一些数据空间

集群内部通讯设计


简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

Pay.java

1
2
3
public interface Pay {
void pay(Integer money);
}

SimpleFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class SimpleFactory {

public static Pay create(String payType) {

if (payType.equals("ZFB")) {
return new ZFBPay();
} else if (payType.equals("WX")) {
return new WXPay();
}else {
return null;
}
}
}

WXPay.java

1
2
3
4
5
public class WXPay implements Pay {
public void pay(Integer money) {
System.out.println("微信支付:"+money+"元");
}
}

ZFBPay.java

1
2
3
4
5
public class ZFBPay implements Pay {
public void pay(Integer money) {
System.out.println("支付宝支付:"+money+"元");
}
}

Test.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 简单工厂设计模式
*/
public class Test {

public static void main(String[] args) {

Pay wx = SimpleFactory.create("WX");
wx.pay(2);

Pay zfb = SimpleFactory.create("ZFB");
zfb.pay(1);
}
}


完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务。
为了解决这些问题,可以定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法,在这里,每一个封装算法的类我们都可以称之为策略(Strategy),为了保证这些策略的一致性,一般会用一个抽象的策略类来做算法的定义,而具体每种算法则对应于一个具体策略类。

基础

Strategy

1
2
3
4
5
6
7
public interface Strategy {

/**
* 策略方法
*/
public void strategyInterface();
}

ConcreteStrategyA

1
2
3
4
5
6
7
public class ConcreteStrategyA implements Strategy {

@Override
public void strategyInterface() {
System.out.println("ConcreteStrategyA");
}
}

ConcreteStrategyB

1
2
3
4
5
6
7
public class ConcreteStrategyB implements Strategy {

@Override
public void strategyInterface() {
System.out.println("ConcreteStrategyB");
}
}

ConcreteStrategyC

1
2
3
4
5
6
7
public class ConcreteStrategyC implements Strategy {

@Override
public void strategyInterface() {
System.out.println("ConcreteStrategyC");
}
}

Context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Context {

//持有一个具体策略的对象
private Strategy strategy;

/**
* 构造函数,传入一个具体策略对象
*/
public Context(Strategy strategy){
this.strategy = strategy;
}

/**
* 策略方法
*/
public void contextInterface(){
strategy.strategyInterface();
}

}

Test.java

1
2
3
4
5
6
7
public class Test {

public static void main(String[] args) {
Context context = new Context(new ConcreteStrategyA());
context.contextInterface();
}
}

应用

MemberStrategy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 会员策略
*/
public interface MemberStrategy {

/**
* 计算图书的价格,根绝会员等级
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double calcPrice(double booksPrice);

}

PrimaryMemberStrategy.java 初级会员

1
2
3
4
5
6
7
public class PrimaryMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("初级会员,没有折扣");
return 0;
}
}

IntermediateMemberStrategy.java 中级会员

1
2
3
4
5
6
7
public class IntermediateMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于中级会员的折扣为10%");
return booksPrice * 0.9;
}
}

AdvancedMemberStrategy.java 高级会员

1
2
3
4
5
6
7
public class AdvancedMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于高级会员的折扣为20%");
return booksPrice * 0.8;
}
}

Price.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Price {

private MemberStrategy strategy;


public Price(MemberStrategy strategy) {
this.strategy = strategy;
}

/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}

Test.java

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {

public static void main(String[] args) {
//选择并创建需要使用的策略对象
MemberStrategy strategy = new AdvancedMemberStrategy();
//创建环境
Price price = new Price(strategy);
//计算价格
double quote = price.quote(300);
System.out.println("图书的最终价格为:" + quote);
}
}

流程

1.安装JAVA_HOME

2.安装ANDROID_HOME

3.安装夜神模拟器和安装appium和node.js

4.调试环境

4.编写python脚本

1.安装JAVA_HOME环境

这个很重要,特别是我经常用IDEA做开发,平常就很少配置JAVA_HOME环境变量,,变量名为:ANDROID_HOME

2.安装ANDROID_HOME环境

看网上的教程,都是去官网下了个安卓的SDK,我一上官网,就只是提示我下载Android Studio,所以就安装了这个软件,在软件的配置里面找到的安卓的SDK的目录,然后就配置了环境变量

变量名为:ANDROID_HOME

变量值为:C:\..\..\Android\Sdk

然后在Path里添加:

%ANDROID_HOME%\tools

%ANDROID_HOME%\platform-tools

3.安装夜神模拟器和appium

夜神模拟器就下载最新版本的就可以

appium也直接在网上下载安装好就行

4.调试环境

1.把C:\Program Files (x86)\Nox\bin添加到Path环境变量红

2.查看夜神模拟器的adb版本号:nox_adb.exe version

1
2
3
4
5
[email protected]  C:\Program Files (x86)\Nox\bin
❯ .\nox_adb.exe version
Android Debug Bridge version 1.0.41
Version 30.0.3-6597393
Installed as C:\Program Files (x86)\Nox\bin\nox_adb.exe

2查看adb版本号:adb version,这是安卓的sdk版本号

1
2
3
4
❯ adb version
Android Debug Bridge version 1.0.41
Version 30.0.3-6597393
Installed as C:\Users\xxxx\AppData\Local\Android\Sdk\platform-tools\adb.exe

如果他们不一样,就把安卓的adb.exe拷贝到``C:\Program Files (x86)\Nox\bin里,并改名nox_adb.exe`,再看看版本号是不是就一样的了

3.夜神模拟器连接上安卓sdk

1
2
❯ ./nox_adb.exe connect 127.0.0.1:62001
already connected to 127.0.0.1:62001

4.启动appium,现在先使用默认的设置,点击启动服务器

appium是基于node.js开发的,前提要安装好node.js

1
2
3
4
5
6
7
[Appium] Welcome to Appium v1.17.1
[Appium] Non-default server args:
[Appium] allowInsecure: {
[Appium] }
[Appium] denyInsecure: {
[Appium] }
[Appium] Appium REST http interface listener started on 0.0.0.0:4723

5.查看现在可用的手机设备

1
2
3
❯ adb devices
List of devices attached
127.0.0.1:62001 device

注意看这里的127.0.0.1:62001,这是一个字符串,如果是用真实手机的话,这里显示的是一串连续的字符串

6.sdk连接appium

1
appium -a 127.0.0.1 -p 4723 -U 127.0.0.1:62001

-a 就是appium启动的ip地址

-a 就是appium启动的端口

-U 就是在第五步获取的字符串127.0.0.1:62001,连接这台手机设备

5.编写脚本

安装包

1
pip install Appium-Python-Client

脚本,这里是个简单的抖音的自动点赞功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import time

from appium import webdriver

desired_caps =dict()
# 平台名称,安卓就是Android
desired_caps['platformName']='Android'
# 平台的版本
desired_caps['platformVersion']='5.1'
# 设备的名字,貌似可以随便写
desired_caps['deviceName']='Android'
# 包名
desired_caps['appPackage']='com.ss.android.ugc.aweme'
# 界面名
desired_caps['appActivity']='.splash.SplashActivity'
# 不用每次都重新安装app
desired_caps['noReset'] = True
# 输入中文
desired_caps['unicodekeyboard']=True
desired_caps['resetkeyboard']=True

driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
driver.implicitly_wait(30)


while True:
# 滑动
print("开始滑动")
driver.swipe(200,900,300,500,500)
print("滑动完成,休息")
time.sleep(5)

# 进入头像
driver.find_element_by_id("com.ss.android.ugc.aweme:id/en2").click()

# 获取关注人数
comment = False
number = driver.find_element_by_id("com.ss.android.ugc.aweme:id/arh").text
if number.find("w") != -1:
print("关注人数"+str(number))
# 关注
print("开始点击关注")
driver.find_element_by_id("com.ss.android.ugc.aweme:id/el4").click()
print("开始点击完成")
comment=True
else:
print("关注人数没有一万多,不操作了")
break

# 退到首页
driver.find_element_by_id("com.ss.android.ugc.aweme:id/ks").click()

# 是否要留言,关注了就留言
if comment == True:
# 点击评论按钮
driver.find_element_by_id("com.ss.android.ugc.aweme:id/acv").click()
# 点击评论输入框
driver.find_element_by_id("com.ss.android.ugc.aweme:id/acp").click()
# 写下评论
driver.find_element_by_id("com.ss.android.ugc.aweme:id/acp").send_keys("太棒了")
# 发送
driver.find_element_by_id("com.ss.android.ugc.aweme:id/ad_").click()
# 关闭评论窗口
driver.find_element_by_id("com.ss.android.ugc.aweme:id/ks").click()

time.sleep(10)
print("一次循环完成")

driver.quit()

其它APi

ADB

1
2
3
4
5
# 从电脑上安装软件的手机上
adb install ‪C:\迅雷下载\2a5b812be8277ae6f75b0fb736fab49a_72817400.apk

# 通过这个命令,看
adb shell dumpsys window windows | findstr mFocusedApp

Python

1
2
3
4
5
6
7
8
9
# 滑动滑动
driver.swipe(sx,sy,ex,edy,ms)

# 获取当前的包名和界面明
driver.current_package
driver.current_activity

# 隐式等待
driver.implicitly_wait(30)

服务器

Vultr里买了两天新加坡服务器

说Vultr哪里好

  • 就是简洁到,任何一处功能都是可以用上的,没有多余的按钮,连接,
  • 可以用支付宝支付,也可以直接绑定Visa卡
  • 1G 1核心的服务器,一个月只要5美,对比亚马逊,阿里云的香港节点,华为的国外节点都更便宜,在东南亚连接国内的阿里云,命令行都是一个字母一个字母显示出来的
  • SSH连接速度很快,Maven下载jar包,或是Docker下载镜像,或是Jenkins下载插件速度都更快
  • 不需要备案,HTTPS也不需要跟阿里那样,需要服务器运行慢三个月

说Vultr不好

  • 提个工单,感觉那客服比我还不懂,看了系统的ssh登录日志,每时每刻都有不同的IP尝试访问,暴力破解中
  • 阿里云现在报警系统感觉还是非常牛逼的,像SSH暴力破解都是发邮件提示,Vultr不行
  • 买的一台服务器用Docker跑的Mysql,经常莫名其妙的密码不对,或者是那种勒索了数据库,要求我发多少比特币到那邮箱..阿里云的服务器就不会出现这个问题,已经出现过很多次这样的情况,就算设置的Mysql的访问IP,也没有作用

实在忍受不了了,还是换回阿里云的服务器,2G 2核心一年760左右,感觉好贵呀,心疼…..,虽然命令行非常慢,主要是也没有太多操作,安装Docker,Mysql,Redis,Jenkins和jar包的启动脚本

Mysql

阿里,亚马逊的数据库都贵,给一般企业用还差不多,本来也就开发的时候,和前端联调的时候回用上数据库,买包时的,又嫌麻烦,在Vultr上用docker跑的数据库,明明数据库密码是有很高复杂度的,但总是能被人访问,而且限制了IP访问,还是不起作用,我都怀疑,Vultr这家公司的服务器是不是有后门

还有个时区的问题,Mybatis插入数据库的当前时间,和获取那条记录的插入时间对不上,差8个小时,虽然大概知道是个怎么回事,但是绕了些弯路,整体解决下来就是:

  1. 判断插入时间是不是正确的
  2. 修改服务器时间
  3. 修改docker容器的时间
  4. 修改SpringBoot的时间

Nginx

只是使用了一个简单的功能,域名转发,开始使用的Vultr的服务器,在阿里云域名解析,一下子就能成功,之后换成阿里云服务器之后,就一直解析不成功,用IP:PORT访问又是正常的,后来才发现服务器必须得满使用3个月,才可以用域名转发…慢慢等吧

在Vultr服务器上,因为域名是可以转发的,所以可以在Nginx那里配置SSL证书,免费申请的那种,各种百度一顿操作都是正常,可就是访问报错,一步一步找才发现,用docker跑Nginx的时候,并没有开启443端口……..我TM无语了,貌似Docker就这点不好,如果第一次运行容器的时候,把数据卷映射到服务器本地还好,如果没有映射,那凉凉还得重新来过,没想明白,那么强大的功能,为什么不给个,修改正在运行容器的启动命令(这里不考虑docker commit)

换到阿里云服务器,也就是域名不能转发成功,所以证书也自然而然配不上了

做开发的时候,虽然不是很羡慕做管理的人,但是一直觉得做管理是个稍微轻松的活,工资不说,起码比开发高,这些天回国休假的同事都因为疫情来不了公司了,只能我上

这接近一个月的样子,都没有写代码了,每天各部门导出跑,开发提交代码,到测试,到最后上线,层层环节都有各种问题,特别严重的是之前同事开发的代码,都有各种坑,特别还是在线上,然后测试提禅道单,开发去改,发现是一个深坑,产品不知道需求,开发也不知道原来的需求是什么样子的,看代码,又发现逻辑对不上,所以出来Bug也不知道要怎么改

总之呢,这就是现在公司的现状,管理也没有想象中的那样轻松,分发任务,和Bug,开发人员也不够,也到处都是坑,这项目从0开始还好说,现在简直是从负数开始,也好久没有学习了,身心疲惫,轻松的时候,经常玩到4点多才睡觉,现在就是回去洗个澡就躺着就睡着了

今天回国休假的人也回公司了,我也想稍微的偷偷懒,业务什么的,实在是没有太多心思管,也不想管进度,让专门的人来做吧,我就本本分分的负责好技术

今晚下班的时候还不想回去,闲着的时候准备找个分布式的定时任务的源码看看的,看到拦截器那里,已经忘记拦截器和过滤器有什么区别了,不想看Spring了,最后决定,从头开始吧,从Servlet开始

就在这里立下一个Flag,还没有想好重点,就是想着从头来过,立志要做一个架构师的男人

这两个月,时间过的也是很漫长的,公司的代码已经做了两个版本,各种Bug,我都有点无语了,其中有的代码是已经有了一年的历史了,理论上应该是非常稳定的了,可是到现在还时不时的出现问题,我也是很无奈,最无语的就是,有一些边缘的功能,业务也很简单,就是对一两张表做CRUD,经过一年的测试,等到我接受它相关的业务的时候,我去看那些代码,竟然还有的是错的,真的,我不知道是该骂人好,还是要怎么样,测试竟然没有测出一年的bug

这两个月,时间过的也是很短暂的,闲余的时间,我开始在写自己的商业项目,计划是今年内,或者是11月份内,要上线运行,万事开头难,从刚开始的时候,我都不知道要怎么开始,到现在的的,开始有了服务器,项目名称,和专业的设计,设计出来的LOGO,也开始接触第三方公司,一聊天的时候,别人就说,老板怎么怎么样,我顿时就觉得很尴尬,可能在别人眼里,我就是个有钱的老板,可是只有我才知道,我TM就是个穷人,有意无意的我也有说,现在项目还是个人开发的,然后我就不管别人怎么想的,别人提供服务,我给钱,合作的好,就继续合作,合作的不好,别人换个客户,我给钱给另外一个人,在接触第三方的时候,还是顺利的,毕竟给钱了得

没给钱的就很尴尬了,老是被人封IP,我都换了三个IP了,数据库经常被黑掉,那时也是安全没做好,老是有人把我的数据库删掉,添加张表,让我把比特币汇给那人,然后帮我恢复数据,刚开始的时候,都是没有备份的,后来实在是受不了了,就限制了IP访问…..

还有很多坑在里面,跟前端对接口,跟第三方对接口,配置服务器环境,自动化构建部署…..总之有各种各样的问题,都等着我百度,谷歌之后一个一个解决掉

现在项目已经有雏形了,各个环节都已经打通,就差调试,把整个流程跑通,当然业务功能也是最简单的,都是基本功能,参考同行的软件,不必要的功能都不要,麻烦的或者需要学习成本的功能也不要,怀着抖音,微信这样的方向去做,足够简单,又足够强大

当然也需要我足够强大才行,既能做的了架构,又能做开发,既能做运维,也能做客服,项目前期是真的没有什么人,万事开头难